diff --git a/.eslintignore b/.eslintignore index 7d3c0be..b739030 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,5 @@ **/node_modules/* **/coverage/* **/dist/* -**/types/* \ No newline at end of file +**/types/* +**/scripts/concatenated-output.ts \ No newline at end of file diff --git a/rollup.config.js b/rollup.config.js index 9ad3991..b539ab0 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,64 +1,36 @@ -import commonjs from '@rollup/plugin-commonjs' -import resolve from '@rollup/plugin-node-resolve' -import replace from '@rollup/plugin-replace' -import typescript from '@rollup/plugin-typescript' -import { defineConfig } from 'rollup' -import pkg from './package.json' -import json from '@rollup/plugin-json'; +import json from "@rollup/plugin-json"; +import replace from "@rollup/plugin-replace"; +import typescript from "@rollup/plugin-typescript"; +import { defineConfig } from "rollup"; +import pkg from "./package.json"; export default defineConfig([ - { - input: 'src/index.ts', - output: [ - { - file: pkg.unpkg, - format: 'iife', - sourcemap: true, - name: pkg.name, - }, - { - file: pkg.browser, - format: 'umd', - sourcemap: true, - name: pkg.name, - }, - ], - plugins: [ - json(), - resolve(), - commonjs(), - typescript(), - replace({ - preventAssignment: true, - }) - ].filter(Boolean), - }, - { - input: 'src/index.ts', - external: [ - ...Object.keys(pkg.dependencies || {}), - ...Object.keys(pkg.peerDependencies || {}), - ], - output: [ - { - file: pkg.main, - format: 'cjs', - sourcemap: true, - exports: 'auto', - }, - { - file: pkg.module, - format: 'es', - sourcemap: true, - }, - ], - plugins: [ - json(), - typescript(), - replace({ - __DEV__: `(process.env.NODE_ENV !== 'production')`, - preventAssignment: true, - }) - ].filter(Boolean), - }, -]) \ No newline at end of file + { + input: "src/index.ts", + external: [ + ...Object.keys(pkg.dependencies || {}), + ...Object.keys(pkg.peerDependencies || {}), + ], + output: [ + { + file: pkg.main, + format: "cjs", + sourcemap: true, + exports: "auto", + }, + { + file: pkg.module, + format: "es", + sourcemap: true, + }, + ], + plugins: [ + json(), + typescript(), + replace({ + __DEV__: `(process.env.NODE_ENV !== 'production')`, + preventAssignment: true, + }), + ].filter(Boolean), + }, +]); diff --git a/scripts/shell.mjs b/scripts/shell.mjs index 3e17f14..f1fd248 100755 --- a/scripts/shell.mjs +++ b/scripts/shell.mjs @@ -22,7 +22,7 @@ const SUPABASE_URL = process.env.SERVER_URL || "https://pronvzrzfwsptkojvudd.sup const SUPABASE_ANON_KEY = process.env.SERVER_URL || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InByb252enJ6ZndzcHRrb2p2dWRkIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDY4NTYwNDcsImV4cCI6MjAyMjQzMjA0N30.I6_-XrqssUb2SWYg5DjsUqSodNS3_RPoET3-aPdqywM" // check for --debug flag in 'node example/shell --debug' const SERVER_URL = - process.env.SERVER_URL || dev + process.env?.SERVER_URL ?? dev ? 'http://localhost:7998' : 'https://cojourney.shawmakesmagic.workers.dev' diff --git a/src/agents/cj/actions/introduce.ts b/src/agents/cj/actions/introduce.ts index b26383c..72ef105 100644 --- a/src/agents/cj/actions/introduce.ts +++ b/src/agents/cj/actions/introduce.ts @@ -97,7 +97,9 @@ const handler = async (runtime: BgentRuntime, message: Message) => { export default { name: "INTRODUCE", validate: async ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars _runtime: BgentRuntime, + // eslint-disable-next-line @typescript-eslint/no-unused-vars _message: Message, ): Promise => { return await Promise.resolve(true); diff --git a/src/agents/cj/evaluators/details.ts b/src/agents/cj/evaluators/details.ts index 7f25062..3727674 100644 --- a/src/agents/cj/evaluators/details.ts +++ b/src/agents/cj/evaluators/details.ts @@ -108,7 +108,9 @@ const handler = async (runtime: BgentRuntime, message: Message) => { export default { name: "UPDATE_DETAILS", validate: async ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars _runtime: BgentRuntime, + // eslint-disable-next-line @typescript-eslint/no-unused-vars _message: Message, ): Promise => { return await Promise.resolve(true); diff --git a/src/agents/cj/evaluators/profile.ts b/src/agents/cj/evaluators/profile.ts index 0d7c169..eda2afa 100644 --- a/src/agents/cj/evaluators/profile.ts +++ b/src/agents/cj/evaluators/profile.ts @@ -214,7 +214,9 @@ const handler = async (runtime: BgentRuntime, message: Message) => { export default { name: "UPDATE_PROFILE", validate: async ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars _runtime: BgentRuntime, + // eslint-disable-next-line @typescript-eslint/no-unused-vars _message: Message, ): Promise => { // immediatel resolve true diff --git a/src/agents/index.ts b/src/agents/index.ts index ba35f9e..ba38421 100644 --- a/src/agents/index.ts +++ b/src/agents/index.ts @@ -1,8 +1,7 @@ +export { fetch as CjWorker } from "./cj"; +export { fetch as SimpleWorker } from "./simple"; import { fetch as CjWorker } from "./cj"; -import { fetch as SimpleWorker } from "./simple"; export default { - CjWorker, - SimpleWorker, fetch: CjWorker, }; diff --git a/src/lib/__tests__/actions.test.ts b/src/lib/__tests__/actions.test.ts index c89278c..2484adc 100644 --- a/src/lib/__tests__/actions.test.ts +++ b/src/lib/__tests__/actions.test.ts @@ -3,16 +3,14 @@ import { type UUID } from "crypto"; import dotenv from "dotenv"; import { getCachedEmbedding, writeCachedEmbedding } from "../../test/cache"; import { createRuntime } from "../../test/createRuntime"; -import { GetTellMeAboutYourselfConversationTroll1 } from "../../test/data"; import { getRelationship } from "../relationships"; import { type BgentRuntime } from "../runtime"; -import { Content, type Message } from "../types"; dotenv.config(); const zeroUuid = "00000000-0000-0000-0000-000000000000"; -describe("User Profile", () => { +describe("Actions", () => { let user: User; let runtime: BgentRuntime; let room_id: UUID; @@ -74,35 +72,6 @@ describe("User Profile", () => { } } - test("Action handler test: ignore", async () => { - const message: Message = { - senderId: user.id as UUID, - agentId: zeroUuid, - userIds: [user?.id as UUID, zeroUuid], - content: "", - room_id: room_id as UUID, - }; - - await populateMemories([GetTellMeAboutYourselfConversationTroll1]); - - const response = await runtime.handleRequest(message); - - const state = await runtime.composeState(message); - - console.log( - "*** recentMessagesData", - state.recentMessagesData.map((m) => m.content), - ); - - console.log("*** response", response); - - const lastMessage = state.recentMessagesData[0]; - - console.log("*** lastMessage", lastMessage.content); - - expect((lastMessage.content as Content).action).toBe("IGNORE"); - }, 60000); - test("Action handler test: continue", async () => { // TODO: test action handler with a message that should continue the conversation // evaluate that the response action is a continue diff --git a/src/lib/actions/__tests__/ignore.test.ts b/src/lib/actions/__tests__/ignore.test.ts index 8b8a89e..5b07520 100644 --- a/src/lib/actions/__tests__/ignore.test.ts +++ b/src/lib/actions/__tests__/ignore.test.ts @@ -3,9 +3,14 @@ import { type UUID } from "crypto"; import dotenv from "dotenv"; import { getCachedEmbedding, writeCachedEmbedding } from "../../../test/cache"; import { createRuntime } from "../../../test/createRuntime"; +import { + GetTellMeAboutYourselfConversationTroll1, + GetTellMeAboutYourselfConversationTroll2, + Goodbye1, +} from "../../../test/data"; import { getRelationship } from "../../relationships"; import { type BgentRuntime } from "../../runtime"; -import { type Message } from "../../types"; +import { Content, type Message } from "../../types"; import action from "../continue"; dotenv.config(); @@ -13,7 +18,7 @@ dotenv.config(); const zeroUuid = "00000000-0000-0000-0000-000000000000"; describe("User Profile", () => { - let user: User | null; + let user: User; let runtime: BgentRuntime; let room_id: UUID | null; @@ -23,7 +28,7 @@ describe("User Profile", () => { beforeAll(async () => { const setup = await createRuntime(); - user = setup.user; + user = setup.session.user; runtime = setup.runtime; const data = await getRelationship({ @@ -90,4 +95,91 @@ describe("User Profile", () => { const result = (await handler(runtime, message)) as string[]; expect(result).toBe(true); }, 60000); + + test("Action handler test 1: response should be ignore", async () => { + const message: Message = { + senderId: user.id as UUID, + agentId: zeroUuid, + userIds: [user?.id as UUID, zeroUuid], + content: "", + room_id: room_id as UUID, + }; + + await populateMemories([GetTellMeAboutYourselfConversationTroll1]); + + const response = await runtime.handleRequest(message); + + const state = await runtime.composeState(message); + + console.log( + "*** recentMessagesData", + state.recentMessagesData.map((m) => m.content), + ); + + console.log("*** response", response); + + const lastMessage = state.recentMessagesData[0]; + + console.log("*** lastMessage", lastMessage.content); + + expect((lastMessage.content as Content).action).toBe("IGNORE"); + }, 60000); + + test("Action handler test 2: response should be ignore", async () => { + const message: Message = { + senderId: user.id as UUID, + agentId: zeroUuid, + userIds: [user?.id as UUID, zeroUuid], + content: "", + room_id: room_id as UUID, + }; + + await populateMemories([GetTellMeAboutYourselfConversationTroll2]); + + const response = await runtime.handleRequest(message); + + const state = await runtime.composeState(message); + + console.log( + "*** recentMessagesData", + state.recentMessagesData.map((m) => m.content), + ); + + console.log("*** response", response); + + const lastMessage = state.recentMessagesData[0]; + + console.log("*** lastMessage", lastMessage.content); + + expect((lastMessage.content as Content).action).toBe("IGNORE"); + }, 60000); + + test("Action handler test 3: response should be ignore", async () => { + const message: Message = { + senderId: user.id as UUID, + agentId: zeroUuid, + userIds: [user?.id as UUID, zeroUuid], + content: "", + room_id: room_id as UUID, + }; + + await populateMemories([Goodbye1]); + + const response = await runtime.handleRequest(message); + + const state = await runtime.composeState(message); + + console.log( + "*** recentMessagesData", + state.recentMessagesData.map((m) => m.content), + ); + + console.log("*** response", response); + + const lastMessage = state.recentMessagesData[0]; + + console.log("*** lastMessage", lastMessage.content); + + expect((lastMessage.content as Content).action).toBe("IGNORE"); + }, 60000); }); diff --git a/src/lib/actions/wait.ts b/src/lib/actions/wait.ts index 3100246..d0b7bc7 100644 --- a/src/lib/actions/wait.ts +++ b/src/lib/actions/wait.ts @@ -3,7 +3,7 @@ import { type Action, type Message } from "../types"; export default { name: "WAIT", - // eslint-disable-next-line @typescript-eslint/no-unused-vars + // eslint-disable-next-line @typescript-eslint/no-unused-vars validate: async (_runtime: BgentRuntime, _message: Message) => { return true; }, diff --git a/src/lib/context.ts b/src/lib/context.ts index 11f90cd..0b10c9a 100644 --- a/src/lib/context.ts +++ b/src/lib/context.ts @@ -8,7 +8,7 @@ export const composeContext = ({ template: string; }) => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error + // @ts-expect-error match isn't working as expected const out = template.replace(/{{\w+}}/g, (match) => { const key = match.replace(/{{|}}/g, ""); return state[key] ?? ""; diff --git a/src/lib/evaluators/summarization.ts b/src/lib/evaluators/summarization.ts index 2f44949..fe92179 100644 --- a/src/lib/evaluators/summarization.ts +++ b/src/lib/evaluators/summarization.ts @@ -247,7 +247,9 @@ async function handler(runtime: BgentRuntime, message: Message) { export default { name: "SUMMARIZE", validate: async ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars _runtime: BgentRuntime, + // eslint-disable-next-line @typescript-eslint/no-unused-vars _message: Message, ): Promise => { return await Promise.resolve(true); @@ -257,7 +259,5 @@ export default { condition: "New factual information was revealed in the recent conversation which should be remembered.", handler, - examples: [ - - ], + examples: [], }; diff --git a/src/lib/logger.ts b/src/lib/logger.ts index 7107796..c210b80 100644 --- a/src/lib/logger.ts +++ b/src/lib/logger.ts @@ -1,774 +1,4 @@ -// @ts-nocheck - -import process from "process"; -import os from "os"; -import tty from "tty"; - -// From: https://github.com/sindresorhus/has-flag/blob/main/index.js -/// function hasFlag(flag, argv = globalThis.Deno?.args ?? process.argv) { -function hasFlag(flag: string, argv = process.argv) { - const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--"; - const position = argv.indexOf(prefix + flag); - const terminatorPosition = argv.indexOf("--"); - return ( - position !== -1 && - (terminatorPosition === -1 || position < terminatorPosition) - ); -} - -const env = process.env as { [x: string]: string }; - -let flagForceColor: number; -if ( - hasFlag("no-color") || - hasFlag("no-colors") || - hasFlag("color=false") || - hasFlag("color=never") -) { - flagForceColor = 0; -} else if ( - hasFlag("color") || - hasFlag("colors") || - hasFlag("color=true") || - hasFlag("color=always") -) { - flagForceColor = 1; -} - -function envForceColor() { - if ("FORCE_COLOR" in env) { - if (env.FORCE_COLOR === "true") { - return 1; - } - - if (env.FORCE_COLOR === "false") { - return 0; - } - - return env.FORCE_COLOR.length === 0 - ? 1 - : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3); - } - return undefined; -} - -function translateLevel(level: number) { - if (level === 0) { - return false; - } - - return { - level, - hasBasic: true, - has256: level >= 2, - has16m: level >= 3, - }; -} - -function _supportsColor( - haveStream: any, - { streamIsTTY = false, sniffFlags = true } = {}, -) { - const noFlagForceColor = envForceColor(); - if (noFlagForceColor !== undefined) { - flagForceColor = noFlagForceColor; - } - - const forceColor = sniffFlags ? flagForceColor : noFlagForceColor; - - if (forceColor === 0) { - return 0; - } - - if (sniffFlags) { - if ( - hasFlag("color=16m") || - hasFlag("color=full") || - hasFlag("color=truecolor") - ) { - return 3; - } - - if (hasFlag("color=256")) { - return 2; - } - } - - // Check for Azure DevOps pipelines. - // Has to be above the `!streamIsTTY` check. - if ("TF_BUILD" in env && "AGENT_NAME" in env) { - return 1; - } - - if (haveStream && !streamIsTTY && forceColor === undefined) { - return 0; - } - - const min = forceColor || 0; - - if (env.TERM === "dumb") { - return min; - } - - if (process.platform === "win32") { - // Windows 10 build 10586 is the first Windows release that supports 256 colors. - // Windows 10 build 14931 is the first release that supports 16m/TrueColor. - const osRelease = os.release().split("."); - if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10_586) { - return Number(osRelease[2]) >= 14_931 ? 3 : 2; - } - - return 1; - } - - if ("CI" in env) { - if ("GITHUB_ACTIONS" in env || "GITEA_ACTIONS" in env) { - return 3; - } - - if ( - [ - "TRAVIS", - "CIRCLECI", - "APPVEYOR", - "GITLAB_CI", - "BUILDKITE", - "DRONE", - ].some((sign) => sign in env) || - env.CI_NAME === "codeship" - ) { - return 1; - } - - return min; - } - - if ("TEAMCITY_VERSION" in env) { - return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; - } - - if (env.COLORTERM === "truecolor") { - return 3; - } - - if (env.TERM === "xterm-kitty") { - return 3; - } - - if ("TERM_PROGRAM" in env) { - const version = Number.parseInt( - (env.TERM_PROGRAM_VERSION || "").split(".")[0], - 10, - ); - - switch (env.TERM_PROGRAM) { - case "iTerm.app": { - return version >= 3 ? 3 : 2; - } - - case "Apple_Terminal": { - return 2; - } - // No default - } - } - - if (/-256(color)?$/i.test(env.TERM)) { - return 2; - } - - if ( - /^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM) - ) { - return 1; - } - - if ("COLORTERM" in env) { - return 1; - } - - return min; -} - -export function createSupportsColor(stream: { isTTY: any }, options = {}) { - const level = _supportsColor(stream, { - streamIsTTY: stream && stream.isTTY, - ...options, - }); - - return translateLevel(level); -} - -const supportsColor = { - stdout: createSupportsColor({ isTTY: tty.isatty(1) }), - stderr: createSupportsColor({ isTTY: tty.isatty(2) }), -}; - -const ANSI_BACKGROUND_OFFSET = 10; - -const wrapAnsi16 = - (offset = 0) => - (code: number) => - `\u001B[${code + offset}m`; - -const wrapAnsi256 = - (offset = 0) => - (code: any) => - `\u001B[${38 + offset};5;${code}m`; - -const wrapAnsi16m = - (offset = 0) => - (red: any, green: any, blue: any) => - `\u001B[${38 + offset};2;${red};${green};${blue}m`; - -const styles = { - modifier: { - reset: [0, 0], - // 21 isn't widely supported and 22 does the same thing - bold: [1, 22], - dim: [2, 22], - italic: [3, 23], - underline: [4, 24], - overline: [53, 55], - inverse: [7, 27], - hidden: [8, 28], - strikethrough: [9, 29], - }, - color: { - black: [30, 39], - red: [31, 39], - green: [32, 39], - yellow: [33, 39], - blue: [34, 39], - magenta: [35, 39], - cyan: [36, 39], - white: [37, 39], - - // Bright color - blackBright: [90, 39], - gray: [90, 39], // Alias of `blackBright` - grey: [90, 39], // Alias of `blackBright` - redBright: [91, 39], - greenBright: [92, 39], - yellowBright: [93, 39], - blueBright: [94, 39], - magentaBright: [95, 39], - cyanBright: [96, 39], - whiteBright: [97, 39], - }, - bgColor: { - bgBlack: [40, 49], - bgRed: [41, 49], - bgGreen: [42, 49], - bgYellow: [43, 49], - bgBlue: [44, 49], - bgMagenta: [45, 49], - bgCyan: [46, 49], - bgWhite: [47, 49], - - // Bright color - bgBlackBright: [100, 49], - bgGray: [100, 49], // Alias of `bgBlackBright` - bgGrey: [100, 49], // Alias of `bgBlackBright` - bgRedBright: [101, 49], - bgGreenBright: [102, 49], - bgYellowBright: [103, 49], - bgBlueBright: [104, 49], - bgMagentaBright: [105, 49], - bgCyanBright: [106, 49], - bgWhiteBright: [107, 49], - }, -}; - -export const modifierNames = Object.keys(styles.modifier); -export const foregroundColorNames = Object.keys(styles.color); -export const backgroundColorNames = Object.keys(styles.bgColor); -export const colorNames = [...foregroundColorNames, ...backgroundColorNames]; - -function assembleStyles() { - const codes = new Map(); - - for (const [groupName, group] of Object.entries(styles)) { - for (const [styleName, style] of Object.entries(group)) { - // @ts-ignore - styles[styleName] = { - open: `\u001B[${style[0]}m`, - close: `\u001B[${style[1]}m`, - }; - - // @ts-ignore - group[styleName] = styles[styleName]; - - codes.set(style[0], style[1]); - } - - Object.defineProperty(styles, groupName, { - value: group, - enumerable: false, - }); - } - - Object.defineProperty(styles, "codes", { - value: codes, - enumerable: false, - }); - - // @ts-expect-error - styles.color.close = "\u001B[39m"; - // @ts-expect-error - styles.bgColor.close = "\u001B[49m"; - // @ts-expect-error - styles.color.ansi = wrapAnsi16(); - // @ts-expect-error - styles.color.ansi256 = wrapAnsi256(); - // @ts-expect-error - styles.color.ansi16m = wrapAnsi16m(); - // @ts-expect-error - styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET); - // @ts-expect-error - styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET); - // @ts-expect-error - styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET); - - // From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js - Object.defineProperties(styles, { - rgbToAnsi256: { - value(red: number, green: number, blue: number) { - // We use the extended greyscale palette here, with the exception of - // black and white. normal palette only has 4 greyscale shades. - if (red === green && green === blue) { - if (red < 8) { - return 16; - } - - if (red > 248) { - return 231; - } - - return Math.round(((red - 8) / 247) * 24) + 232; - } - - return ( - 16 + - 36 * Math.round((red / 255) * 5) + - 6 * Math.round((green / 255) * 5) + - Math.round((blue / 255) * 5) - ); - }, - enumerable: false, - }, - hexToRgb: { - value(hex: { toString: (arg0: number) => string }) { - const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16)); - if (!matches) { - return [0, 0, 0]; - } - - let [colorString] = matches; - - if (colorString.length === 3) { - colorString = [...colorString] - .map((character) => character + character) - .join(""); - } - - const integer = Number.parseInt(colorString, 16); - - return [ - /* eslint-disable no-bitwise */ - (integer >> 16) & 0xff, - (integer >> 8) & 0xff, - integer & 0xff, - /* eslint-enable no-bitwise */ - ]; - }, - enumerable: false, - }, - hexToAnsi256: { - // @ts-expect-error - value: (hex: any) => styles.rgbToAnsi256(...styles.hexToRgb(hex)), - enumerable: false, - }, - ansi256ToAnsi: { - value(code: number) { - if (code < 8) { - return 30 + code; - } - - if (code < 16) { - return 90 + (code - 8); - } - - let red; - let green; - let blue; - - if (code >= 232) { - red = ((code - 232) * 10 + 8) / 255; - green = red; - blue = red; - } else { - code -= 16; - - const remainder = code % 36; - - red = Math.floor(code / 36) / 5; - green = Math.floor(remainder / 6) / 5; - blue = (remainder % 6) / 5; - } - - const value = Math.max(red, green, blue) * 2; - - if (value === 0) { - return 30; - } - - // eslint-disable-next-line no-bitwise - let result = - 30 + - ((Math.round(blue) << 2) | - (Math.round(green) << 1) | - Math.round(red)); - - if (value === 2) { - result += 60; - } - - return result; - }, - enumerable: false, - }, - rgbToAnsi: { - // @ts-expect-error - value: (red: any, green: any, blue: any) => - styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)), - enumerable: false, - }, - hexToAnsi: { - // @ts-expect-error - value: (hex: any) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), - enumerable: false, - }, - }); - - return styles; -} - -const ansiStyles = assembleStyles(); - -const { stdout: stdoutColor, stderr: stderrColor } = supportsColor; - -const GENERATOR = Symbol("GENERATOR"); -const STYLER = Symbol("STYLER"); -const IS_EMPTY = Symbol("IS_EMPTY"); - -// `supportsColor.level` → `ansiStyles.color[name]` mapping -const levelMapping = ["ansi", "ansi", "ansi256", "ansi16m"]; - -const styles2 = Object.create(null); - -function stringReplaceAll( - string: string, - substring: string | any[], - replacer: any, -) { - let index = string.indexOf(substring as string); - if (index === -1) { - return string; - } - - const substringLength = substring.length; - let endIndex = 0; - let returnValue = ""; - do { - returnValue += string.slice(endIndex, index) + substring + replacer; - endIndex = index + substringLength; - index = string.indexOf(substring as string, endIndex); - } while (index !== -1); - - returnValue += string.slice(endIndex); - return returnValue; -} - -function stringEncaseCRLFWithFirstIndex( - string: string | string[], - prefix: any, - postfix: string, - index: number, -) { - let endIndex = 0; - let returnValue = ""; - do { - const gotCR = string[index - 1] === "\r"; - returnValue += - string.slice(endIndex, gotCR ? index - 1 : index) + - prefix + - (gotCR ? "\r\n" : "\n") + - postfix; - endIndex = index + 1; - index = string.indexOf("\n", endIndex); - } while (index !== -1); - - returnValue += string.slice(endIndex); - return returnValue; -} - -const applyOptions = ( - object: { (...strings: any[]): string; level?: any }, - options: { level?: number } = {}, -) => { - if ( - options.level && - !( - Number.isInteger(options.level) && - options.level >= 0 && - options.level <= 3 - ) - ) { - throw new Error("The `level` option should be an integer from 0 to 3"); - } - - // Detect level if not set manually - const colorLevel = stdoutColor - ? (stdoutColor as unknown as { level: boolean }).level - : 0; - object.level = options.level === undefined ? colorLevel : options.level; -}; - -export class Chalk { - constructor(options: any) { - // eslint-disable-next-line no-constructor-return - return chalkFactory(options); - } -} - -const chalkFactory = (options: {} | undefined) => { - const chalk = (...strings: any[]) => strings.join(" "); - applyOptions(chalk, options); - - Object.setPrototypeOf(chalk, createChalk.prototype); - - return chalk; -}; - -function createChalk(options: { level: any } | undefined) { - return chalkFactory(options); -} - -Object.setPrototypeOf(createChalk.prototype, Function.prototype); - -for (const [styleName, style] of Object.entries(ansiStyles)) { - styles2[styleName] = { - get() { - // @ts-expect-error - const builder = createBuilder( - this, - createStyler(style.open, style.close, this[STYLER]), - this[IS_EMPTY], - ); - Object.defineProperty(this, styleName, { value: builder }); - return builder; - }, - }; -} - -styles2.visible = { - get() { - const builder = createBuilder(this, this[STYLER], true); - Object.defineProperty(this, "visible", { value: builder }); - return builder; - }, -}; - -// @ts-expect-error -const getModelAnsi = ( - model: string, - level: string, - type: string, - ...arguments_: any[] -) => { - if (model === "rgb") { - if (level === "ansi16m") { - // @ts-expect-error - return ansiStyles[type].ansi16m(...arguments_); - } - - if (level === "ansi256") { - // @ts-expect-error - return ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_)); - } - - // @ts-expect-error - return ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_)); - } - - if (model === "hex") { - // @ts-expect-error - return getModelAnsi( - "rgb", - level, - type, - ...ansiStyles.hexToRgb(...arguments_), - ); - } - - // @ts-expect-error - return ansiStyles[type][model](...arguments_); -}; - -const usedModels = ["rgb", "hex", "ansi256"]; - -for (const model of usedModels) { - styles2[model] = { - get() { - const { level } = this; - return function (...arguments_: any) { - // @ts-expect-error - const styler = createStyler( - getModelAnsi(model, levelMapping[level], "color", ...arguments_), - ansiStyles.color.close, - this[STYLER], - ); - // @ts-expect-error - return createBuilder(this, styler, this[IS_EMPTY]); - }; - }, - }; - - const bgModel = "bg" + model[0].toUpperCase() + model.slice(1); - styles2[bgModel] = { - get() { - const { level } = this; - return function (...arguments_: any) { - // @ts-expect-error - const styler = createStyler( - getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), - ansiStyles.bgColor.close, - this[STYLER], - ); - // @ts-expect-error - return createBuilder(this, styler, this[IS_EMPTY]); - }; - }, - }; -} - -const proto = Object.defineProperties(() => {}, { - ...styles2, - level: { - enumerable: true, - get() { - return this[GENERATOR].level; - }, - set(level) { - this[GENERATOR].level = level; - }, - }, -}); - -const createStyler = ( - open: any, - close: any, - parent: { openAll: any; closeAll: any } | undefined, -) => { - let openAll; - let closeAll; - if (parent === undefined) { - openAll = open; - closeAll = close; - } else { - openAll = parent.openAll + open; - closeAll = close + parent.closeAll; - } - - return { - open, - close, - openAll, - closeAll, - parent, - }; -}; - -const createBuilder = ( - self: any, - _styler: { open: any; close: any; openAll: any; closeAll: any; parent: any }, - _isEmpty: boolean, -) => { - // Single argument is hot path, implicit coercion is faster than anything - // eslint-disable-next-line no-implicit-coercion - const builder = (...arguments_: string[]) => - applyStyle( - builder, - arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "), - ); - - // We alter the prototype because we must return a function, but there is - // no way to create a function with a different prototype - Object.setPrototypeOf(builder, proto); - - builder[GENERATOR] = self; - builder[STYLER] = _styler; - builder[IS_EMPTY] = _isEmpty; - - return builder; -}; - -const applyStyle = ( - self: { - (...arguments_: any[]): any; - [x: string]: any; - "__@GENERATOR@162242"?: any; - "__@STYLER@162087"?: any; - "__@IS_EMPTY@162243"?: any; - level?: any; - }, - string: string | string[], -) => { - if (self.level <= 0 || !string) { - // @ts-expect-error - return self[IS_EMPTY] ? "" : string; - } - - // @ts-expect-error - let styler = self[STYLER]; - - if (styler === undefined) { - return string; - } - - const { openAll, closeAll } = styler; - if (string.includes("\u001B")) { - while (styler !== undefined) { - // Replace any instances already present with a re-opening code - // otherwise only the part of the string until said closing code - // will be colored, and the rest will simply be 'plain'. - // @ts-expect-error - string = stringReplaceAll(string, styler.close, styler.open); - - styler = styler.parent; - } - } - - // We can move both next actions out of loop, because remaining actions in loop won't have - // any/visible effect on parts we add here. Close the styling before a linebreak and reopen - // after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92 - const lfIndex = string.indexOf("\n"); - if (lfIndex !== -1) { - string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex); - } - - return openAll + string + closeAll; -}; - -Object.defineProperties(createChalk.prototype, styles2); - -const chalk = createChalk({ level: 0 }); -export const chalkStderr = createChalk({ - level: stderrColor ? (stderrColor as { level?: number }).level : 0, -}); - -export { stdoutColor as supportsColor, stderrColor as supportsColorStderr }; +import chalk, { ForegroundColorName } from "chalk"; class Logger { frameChar = "*"; @@ -782,10 +12,9 @@ class Logger { }: { title?: string; frame?: boolean; - color?: string; + color?: ForegroundColorName; }, ): void { - // @ts-expect-error const coloredMessage = chalk[color](message); if (frame) { const framedMessage = this.frameMessage(coloredMessage, title); diff --git a/src/lib/templates.ts b/src/lib/templates.ts index 2295ae4..9f08481 100644 --- a/src/lib/templates.ts +++ b/src/lib/templates.ts @@ -19,6 +19,9 @@ json\`\`\` # Actors {{actors}} +Current Scene Dialog: +{{recentMessages}} + # INSTRUCTIONS: - Generate the next message in the scene for {{agentName}} - Include content and action in the response @@ -29,10 +32,4 @@ json\`\`\` Response format should be formatted in a JSON block like this: \`\`\`json { "user": {{agentName}}, "content": string, "action": string } -\`\`\` - -Current Scene Dialog: -\`\`\`json -{{recentMessages}} -{ "user": "{{senderName}}", "content": "{{senderContent}}", "action": "{{senderAction}}" } \`\`\``; diff --git a/src/test/data.ts b/src/test/data.ts index 69ba8fa..1635ab4 100644 --- a/src/test/data.ts +++ b/src/test/data.ts @@ -293,6 +293,26 @@ export const GetTellMeAboutYourselfConversationTroll2 = ( }, ]; +// Jim says bye +export const Goodbye1 = (user_id: UUID | string) => [ + { + user_id: zeroUuid, + content: "Hello! How's it going?", + }, + { + user_id, + content: "Meh, just another day. Actually, I gotta run.", + }, + { + user_id: zeroUuid, + content: "Oh sure, no problem. See you later!", + }, + { + user_id, + content: "Bye", + }, +]; + // Jim is cagey, although he reveals that he 'does computers' export const GetTellMeAboutYourselfConversationFail1 = ( user_id: UUID | string, diff --git a/tsconfig.json b/tsconfig.json index d4a78c2..46a0d34 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -36,7 +36,8 @@ "include": [ "src", "__tests__", - "jest.config.js" + "jest.config.js", + "rollup.config.js", ], "exclude": [ "node_modules",