diff --git a/packages/cli/src/nodehost.ts b/packages/cli/src/nodehost.ts index fa9aba0f5d..208fc4fa69 100644 --- a/packages/cli/src/nodehost.ts +++ b/packages/cli/src/nodehost.ts @@ -24,9 +24,6 @@ import { AZURE_AI_INFERENCE_TOKEN_SCOPES, MODEL_PROVIDER_AZURE_SERVERLESS_OPENAI, DOT_ENV_FILENAME, - LARGE_MODEL_ID, - SMALL_MODEL_ID, - VISION_MODEL_ID, } from "../../core/src/constants" import { tryReadText } from "../../core/src/fs" import { @@ -41,7 +38,7 @@ import { ModelConfiguration, } from "../../core/src/host" import { TraceOptions } from "../../core/src/trace" -import { deleteEmptyValues, logError, logVerbose } from "../../core/src/util" +import { logError, logVerbose } from "../../core/src/util" import { parseModelIdentifier } from "../../core/src/models" import { LanguageModel } from "../../core/src/chat" import { errorMessage, NotSupportedError } from "../../core/src/error" @@ -50,7 +47,11 @@ import { shellConfirm, shellInput, shellSelect } from "./input" import { shellQuote } from "../../core/src/shell" import { uniq } from "es-toolkit" import { PLimitPromiseQueue } from "../../core/src/concurrency" -import { LanguageModelConfiguration, Project, ResponseStatus } from "../../core/src/server/messages" +import { + LanguageModelConfiguration, + Project, + ResponseStatus, +} from "../../core/src/server/messages" import { createAzureTokenResolver } from "./azuretoken" import { createAzureContentSafetyClient, @@ -396,15 +397,13 @@ export class NodeHost implements RuntimeHost { } const { - trace, label, cwd, timeout = SHELL_EXEC_TIMEOUT, stdin: input, } = options || {} + const trace = options?.trace?.startTraceDetails(label || command) try { - trace?.startDetails(label || command) - // python3 on windows -> python if (command === "python3" && process.platform === "win32") command = "python" diff --git a/packages/cli/src/scripts.ts b/packages/cli/src/scripts.ts index a13e7e04e5..dfef0044c8 100644 --- a/packages/cli/src/scripts.ts +++ b/packages/cli/src/scripts.ts @@ -8,7 +8,7 @@ import { fixPromptDefinitions, createScript as coreCreateScript, } from "../../core/src/scripts" -import { logInfo, logVerbose } from "../../core/src/util" +import { deleteEmptyValues, logInfo, logVerbose } from "../../core/src/util" import { runtimeHost } from "../../core/src/host" import { RUNTIME_ERROR_CODE } from "../../core/src/constants" import { @@ -27,14 +27,18 @@ export async function listScripts(options?: ScriptFilterOptions) { const prj = await buildProject() // Build the project to get script templates const scripts = filterScripts(prj.scripts, options) // Filter scripts based on options console.log( - YAMLStringify( - scripts.map(({ id, title, group, filename, system: isSystem }) => ({ - id, - title, - group, - filename, - isSystem, - })) + JSON.stringify( + scripts.map(({ id, title, group, filename, system: isSystem }) => + deleteEmptyValues({ + id, + title, + group, + filename, + isSystem, + }) + ), + null, + 2 ) ) } diff --git a/packages/core/bundleprompts.js b/packages/core/bundleprompts.js index 99d2e15adc..3e6a12970a 100644 --- a/packages/core/bundleprompts.js +++ b/packages/core/bundleprompts.js @@ -11,10 +11,13 @@ async function main() { const promptMap = {} const prompts = readdirSync(dir) for (const prompt of prompts) { - if (!/\.m?js$/.test(prompt)) continue + if (!/\.mjs$/.test(prompt)) continue const text = readFileSync(`${dir}/${prompt}`, "utf-8") - if (/\.genai\.m?js$/.test(prompt)) - promptMap[prompt.replace(/\.genai\.m?js$/i, "")] = text + if (/^system\./.test(prompt)) { + const id = prompt.replace(/\.m?js$/i, "") + if (promptMap[id]) throw new Error(`duplicate prompt ${id}`) + promptMap[id] = text + } } console.log(`found ${Object.keys(promptMap).length} prompts`) console.debug(Object.keys(promptMap).join("\n")) diff --git a/packages/core/src/anthropic.ts b/packages/core/src/anthropic.ts index e94e459e4e..b3a143a027 100644 --- a/packages/core/src/anthropic.ts +++ b/packages/core/src/anthropic.ts @@ -30,10 +30,6 @@ import { import { deleteUndefinedValues, logError, logVerbose } from "./util" import { resolveHttpProxyAgent } from "./proxy" -import { - ChatCompletionRequestCacheKey, - getChatCompletionCache, -} from "./chatcache" import { HttpsProxyAgent } from "https-proxy-agent" import { MarkdownTrace } from "./trace" import { createFetch, FetchType } from "./fetch" @@ -289,40 +285,6 @@ const completerFactory = ( const { model } = parseModelIdentifier(req.model) const { encode: encoder } = await resolveTokenEncoder(model) - const cache = !!cacheOrName || !!cacheName - const cacheStore = getChatCompletionCache( - typeof cacheOrName === "string" ? cacheOrName : cacheName - ) - const cachedKey = cache - ? { - ...req, - ...cfgNoToken, - model: req.model, - temperature: req.temperature, - top_p: req.top_p, - max_tokens: req.max_tokens, - logit_bias: req.logit_bias, - } - : undefined - trace.itemValue(`caching`, cache) - trace.itemValue(`cache`, cacheStore?.name) - const { text: cached, finishReason: cachedFinishReason } = - (await cacheStore.get(cachedKey)) || {} - if (cached !== undefined) { - partialCb?.({ - tokensSoFar: estimateTokens(cached, encoder), - responseSoFar: cached, - responseChunk: cached, - inner, - }) - trace.itemValue(`cache hit`, await cacheStore.getKeySHA(cachedKey)) - return { - text: cached, - finishReason: cachedFinishReason, - cached: true, - } - } - const fetch = await createFetch({ trace, retries: retry, @@ -441,9 +403,6 @@ const completerFactory = ( `${usage.total_tokens} total, ${usage.prompt_tokens} prompt, ${usage.completion_tokens} completion` ) } - - if (finishReason === "stop") - await cacheStore.set(cachedKey, { text: chatResp, finishReason }) return { text: chatResp, finishReason, diff --git a/packages/core/src/cache.test.ts b/packages/core/src/cache.test.ts index 086ae0ee17..45bb180981 100644 --- a/packages/core/src/cache.test.ts +++ b/packages/core/src/cache.test.ts @@ -36,4 +36,26 @@ describe("Cache", () => { assert.ok(sha) assert.strictEqual(typeof sha, "string") }) + test("JSONLineCache getOrUpdate retrieves existing value", async () => { + const cache = JSONLineCache.byName("testCache") + await cache.set("existingKey", 42) + const value = await cache.getOrUpdate( + "existingKey", + async () => 99, + () => true + ) + assert.strictEqual(value.value, 42) + }) + + test("JSONLineCache getOrUpdate updates with new value if key does not exist", async () => { + const cache = JSONLineCache.byName("testCache") + const value = await cache.getOrUpdate( + "newKey", + async () => 99, + () => true + ) + assert.strictEqual(value.value, 99) + const cachedValue = await cache.get("newKey") + assert.strictEqual(cachedValue, 99) + }) }) diff --git a/packages/core/src/cache.ts b/packages/core/src/cache.ts index f0542e5b6a..55d471878f 100644 --- a/packages/core/src/cache.ts +++ b/packages/core/src/cache.ts @@ -25,6 +25,7 @@ export class MemoryCache implements WorkspaceFileCache { protected _entries: Record> + private _pending: Record> // Constructor is private to enforce the use of byName factory method protected constructor(public readonly name: string) { @@ -53,6 +54,7 @@ export class MemoryCache protected async initialize() { if (this._entries) return this._entries = {} + this._pending = {} } /** @@ -104,6 +106,29 @@ export class MemoryCache return this._entries[sha]?.val } + async getOrUpdate( + key: K, + updater: () => Promise, + validator: (val: V) => boolean + ): Promise<{ key: string; value: V; cached?: boolean }> { + await this.initialize() + const sha = await keySHA(key) + if (this._entries[sha]) + return { key: sha, value: this._entries[sha].val, cached: true } + if (this._pending[sha]) + return { key: sha, value: await this._pending[sha], cached: true } + + try { + const p = updater() + this._pending[sha] = p + const value = await p + if (validator(value)) await this.set(key, value) + return { key: sha, value, cached: false } + } finally { + delete this._pending[sha] + } + } + protected async appendEntry(entry: CacheEntry) {} /** @@ -177,7 +202,7 @@ export class JSONLineCache extends MemoryCache { */ override async initialize() { if (this._entries) return - this._entries = {} + super.initialize() await host.createDirectory(this.folder()) // Ensure directory exists const content = await tryReadText(this.path()) const objs: CacheEntry[] = (await JSONLTryParse(content)) ?? [] @@ -201,7 +226,7 @@ export class JSONLineCache extends MemoryCache { } /** - * Compute the SHA1 hash of a key for uniqueness. + * Compute the hash of a key for uniqueness. * Normalizes the key by converting it to a string and appending the core version. * @param key - The key to hash * @returns A promise resolving to the SHA256 hash string diff --git a/packages/core/src/chat.ts b/packages/core/src/chat.ts index 4293677a50..2e48922550 100644 --- a/packages/core/src/chat.ts +++ b/packages/core/src/chat.ts @@ -86,6 +86,10 @@ import { } from "./server/messages" import { unfence } from "./unwrappers" import { fenceMD } from "./mkmd" +import { + ChatCompletionRequestCacheKey, + getChatCompletionCache, +} from "./chatcache" export function toChatCompletionUserMessage( expanded: string, @@ -674,13 +678,16 @@ async function processChatMessage( if (chatParticipants?.length) { let needsNewTurn = false for (const participant of chatParticipants) { + const { generator, options: participantOptions } = participant || {} + const { label } = participantOptions || {} + const participantTrace = trace.startTraceDetails( + `🙋 participant ${label || ""}` + ) try { - const { generator, options: participantOptions } = - participant || {} - const { label } = participantOptions || {} - trace.startDetails(`🙋 participant ${label || ""}`) - - const ctx = createChatTurnGenerationContext(options, trace) + const ctx = createChatTurnGenerationContext( + options, + participantTrace + ) await generator(ctx, structuredClone(messages)) const node = ctx.node checkCancelled(cancellationToken) @@ -689,7 +696,7 @@ async function processChatMessage( await renderPromptNode(options.model, node, { flexTokens: options.flexTokens, fenceFormat: options.fenceFormat, - trace, + trace: participantTrace, }) if (participantMessages?.length) { if ( @@ -704,7 +711,7 @@ async function processChatMessage( user: true, assistant: true, }) - trace.details( + participantTrace.details( `💬 messages (${participantMessages.length})`, renderMessagesToMarkdown(participantMessages, { user: true, @@ -714,21 +721,22 @@ async function processChatMessage( ) messages.push(...participantMessages) needsNewTurn = true - } else trace.item("no message") + } else participantTrace.item("no message") if (errors?.length) { err = errors[0] - for (const error of errors) trace.error(undefined, error) + for (const error of errors) + participantTrace.error(undefined, error) needsNewTurn = false break } } catch (e) { err = e logError(e) - trace.error(`participant error`, e) + participantTrace.error(`participant error`, e) needsNewTurn = false break } finally { - trace?.endDetails() + participantTrace.endDetails() } } if (needsNewTurn) return undefined @@ -873,8 +881,12 @@ export async function executeChatSession( fallbackTools, choices, topLogprobs, + cache: cacheOrName, + cacheName, } = genOptions assert(!!model, "model is required") + + const { token, source, ...cfgNoToken } = connectionToken const top_logprobs = genOptions.topLogprobs > 0 ? topLogprobs : undefined const logprobs = genOptions.logprobs || top_logprobs > 0 ? true : undefined traceLanguageModelConnection(trace, genOptions, connectionToken) @@ -891,11 +903,17 @@ export async function executeChatSession( } ) : undefined + const cache = !!cacheOrName || !!cacheName + const cacheStore = cache + ? getChatCompletionCache( + typeof cacheOrName === "string" ? cacheOrName : cacheName + ) + : undefined + const chatTrace = trace.startTraceDetails(`🧠 llm chat`, { expanded: true }) try { - trace.startDetails(`🧠 llm chat`, { expanded: true }) if (toolDefinitions?.length) { - trace.detailsFenced(`🛠️ tools`, tools, "yaml") + chatTrace.detailsFenced(`🛠️ tools`, tools, "yaml") const toolNames = toolDefinitions.map(({ spec }) => spec.name) const duplicates = uniq(toolNames).filter( (name, index) => toolNames.lastIndexOf(name) !== index @@ -909,7 +927,7 @@ export async function executeChatSession( collapseChatMessages(messages) const tokens = estimateChatTokens(model, messages) if (messages) - trace.details( + chatTrace.details( `💬 messages (${messages.length})`, renderMessagesToMarkdown(messages, { user: true, @@ -923,10 +941,10 @@ export async function executeChatSession( let resp: ChatCompletionResponse try { checkCancelled(cancellationToken) + const reqTrace = chatTrace.startTraceDetails(`📤 llm request`) try { - trace.startDetails(`📤 llm request`) const logit_bias = await choicesToLogitBias( - trace, + reqTrace, model, choices ) @@ -962,21 +980,50 @@ export async function executeChatSession( : undefined, messages, } - updateChatFeatures(trace, req) + updateChatFeatures(reqTrace, req) logVerbose( `chat: sending ${messages.length} messages to ${model} (~${tokens ?? "?"} tokens)\n` ) - resp = await completer( - req, - connectionToken, - genOptions, - trace - ) + + const infer = async () => + await completer( + req, + connectionToken, + genOptions, + reqTrace + ) + if (cacheStore) { + const cachedKey = deleteUndefinedValues({ + ...req, + ...cfgNoToken, + }) satisfies ChatCompletionRequestCacheKey + const validator = (value: ChatCompletionResponse) => { + const ok = value?.finishReason === "stop" + return ok + } + const cacheRes = await cacheStore.getOrUpdate( + cachedKey, + infer, + validator + ) + resp = cacheRes.value + resp.cached = cacheRes.cached + if (resp.cached) { + reqTrace.itemValue("cache", cacheStore.name) + reqTrace.itemValue("cache_key", cacheRes.key) + logVerbose( + `chat: cache hit (${cacheStore.name}/${cacheRes.key.slice(0, 7)})` + ) + } + } else { + resp = await infer() + } + if (resp.variables) genVars = { ...(genVars || {}), ...resp.variables } } finally { logVerbose("\n") - trace.endDetails() + reqTrace.endDetails() } const output = await processChatMessage( @@ -1008,9 +1055,9 @@ export async function executeChatSession( } } } finally { - await dispose(disposables, { trace }) - stats.trace(trace) - trace.endDetails() + await dispose(disposables, { trace: chatTrace }) + stats.trace(chatTrace) + chatTrace.endDetails() } } diff --git a/packages/core/src/chatcache.ts b/packages/core/src/chatcache.ts index 1cc01020e8..bf1ecc9b24 100644 --- a/packages/core/src/chatcache.ts +++ b/packages/core/src/chatcache.ts @@ -9,21 +9,13 @@ import { LanguageModelConfiguration } from "./server/messages" // Define the type for a cache key, which combines chat completion request // with additional model options, excluding "token" and "source" from the language model configuration. export type ChatCompletionRequestCacheKey = CreateChatCompletionRequest & - ModelOptions & Omit -// Define the type for a cache value, containing the response text -// and the reason for completion. -export type ChatCompletationRequestCacheValue = { - text: string - finishReason: ChatCompletionResponse["finishReason"] -} - // Define a JSON line cache type that maps cache keys to cache values. // This cache stores chat completion requests and their associated responses. export type ChatCompletationRequestCache = JSONLineCache< ChatCompletionRequestCacheKey, - ChatCompletationRequestCacheValue + ChatCompletionResponse > // Function to retrieve a chat completion cache. @@ -34,6 +26,6 @@ export function getChatCompletionCache( ): ChatCompletationRequestCache { return JSONLineCache.byName< ChatCompletionRequestCacheKey, - ChatCompletationRequestCacheValue + ChatCompletionResponse >(name || CHAT_CACHE) } diff --git a/packages/core/src/crypto.ts b/packages/core/src/crypto.ts index 96c5610b14..9a5827355d 100644 --- a/packages/core/src/crypto.ts +++ b/packages/core/src/crypto.ts @@ -3,6 +3,7 @@ import { getRandomValues as cryptoGetRandomValues } from "crypto" // Importing the toHex function from the util module to convert byte arrays to hexadecimal strings import { concatBuffers, toHex, utf8Encode } from "./util" +import { CORE_VERSION } from "./version" function getRandomValues(bytes: Uint8Array) { if (typeof self !== "undefined" && self.crypto) { @@ -40,7 +41,7 @@ export function randomHex(size: number) { } export async function hash(value: any, options?: HashOptions) { - const { algorithm = "sha-1", length, ...rest } = options || {} + const { algorithm = "sha-256", version, length, ...rest } = options || {} const sep = utf8Encode("|") const h: Uint8Array[] = [] @@ -68,6 +69,10 @@ export async function hash(value: any, options?: HashOptions) { } else h.push(utf8Encode(JSON.stringify(v))) } + if (version) { + await append(CORE_VERSION) + await append(sep) + } await append(value) await append(sep) await append(rest) diff --git a/packages/core/src/fileedits.ts b/packages/core/src/fileedits.ts index 94a14bfb7d..487bebbbff 100644 --- a/packages/core/src/fileedits.ts +++ b/packages/core/src/fileedits.ts @@ -121,8 +121,8 @@ export async function computeFileEdits( // Apply user-defined output processors if (outputProcessors?.length) { + const outputTrace = trace.startTraceDetails("🖨️ output processors") try { - trace.startDetails("🖨️ output processors") for (const outputProcessor of outputProcessors) { const { text: newText, @@ -141,7 +141,7 @@ export async function computeFileEdits( if (newText !== undefined) { text = newText - trace.detailsFenced(`📝 text`, text) + outputTrace.detailsFenced(`📝 text`, text) } if (files) @@ -149,7 +149,7 @@ export async function computeFileEdits( const fn = runtimeHost.path.isAbsolute(n) ? n : runtimeHost.resolvePath(projFolder, n) - trace.detailsFenced(`📁 file ${fn}`, content) + outputTrace.detailsFenced(`📁 file ${fn}`, content) const fileEdit = await getFileEdit(fn) fileEdit.after = content fileEdit.validation = { pathValid: true } @@ -158,9 +158,9 @@ export async function computeFileEdits( } } catch (e) { logError(e) - trace.error(`output processor failed`, e) + outputTrace.error(`output processor failed`, e) } finally { - trace.endDetails() + outputTrace.endDetails() } } @@ -225,52 +225,55 @@ function validateFileOutputs( ) { if (fileOutputs?.length && Object.keys(fileEdits || {}).length) { trace.startDetails("🗂 file outputs") - for (const fileEditName of Object.keys(fileEdits)) { - const fe = fileEdits[fileEditName] - for (const fileOutput of fileOutputs) { - const { pattern, options } = fileOutput - if (isGlobMatch(fileEditName, pattern)) { - try { - trace.startDetails(`📁 ${fileEditName}`) - trace.itemValue(`pattern`, pattern) - const { schema: schemaId } = options || {} - if (/\.(json|yaml)$/i.test(fileEditName)) { - const { after } = fileEdits[fileEditName] - const data = /\.json$/i.test(fileEditName) - ? JSON5parse(after) - : YAMLParse(after) - trace.detailsFenced("📝 data", data) - if (schemaId) { - const schema = schemas[schemaId] - if (!schema) - fe.validation = { - schemaError: `schema ${schemaId} not found`, - } - else - fe.validation = validateJSONWithSchema( - data, - schema, - { - trace, + try { + for (const fileEditName of Object.keys(fileEdits)) { + const fe = fileEdits[fileEditName] + for (const fileOutput of fileOutputs) { + const { pattern, options } = fileOutput + if (isGlobMatch(fileEditName, pattern)) { + try { + trace.startDetails(`📁 ${fileEditName}`) + trace.itemValue(`pattern`, pattern) + const { schema: schemaId } = options || {} + if (/\.(json|yaml)$/i.test(fileEditName)) { + const { after } = fileEdits[fileEditName] + const data = /\.json$/i.test(fileEditName) + ? JSON5parse(after) + : YAMLParse(after) + trace.detailsFenced("📝 data", data) + if (schemaId) { + const schema = schemas[schemaId] + if (!schema) + fe.validation = { + schemaError: `schema ${schemaId} not found`, } - ) + else + fe.validation = validateJSONWithSchema( + data, + schema, + { + trace, + } + ) + } + } else { + fe.validation = { pathValid: true } } - } else { - fe.validation = { pathValid: true } - } - } catch (e) { - trace.error(errorMessage(e)) - fe.validation = { - schemaError: errorMessage(e), + } catch (e) { + trace.error(errorMessage(e)) + fe.validation = { + schemaError: errorMessage(e), + } + } finally { + trace.endDetails() } - } finally { - trace.endDetails() + break } - break } } + } finally { + trace.endDetails() } - trace.endDetails() } } diff --git a/packages/core/src/genaisrc/system.agent_docs.genai.mjs b/packages/core/src/genaisrc/system.agent_docs.mjs similarity index 100% rename from packages/core/src/genaisrc/system.agent_docs.genai.mjs rename to packages/core/src/genaisrc/system.agent_docs.mjs diff --git a/packages/core/src/genaisrc/system.agent_fs.genai.mjs b/packages/core/src/genaisrc/system.agent_fs.mjs similarity index 100% rename from packages/core/src/genaisrc/system.agent_fs.genai.mjs rename to packages/core/src/genaisrc/system.agent_fs.mjs diff --git a/packages/core/src/genaisrc/system.agent_git.genai.mjs b/packages/core/src/genaisrc/system.agent_git.mjs similarity index 100% rename from packages/core/src/genaisrc/system.agent_git.genai.mjs rename to packages/core/src/genaisrc/system.agent_git.mjs diff --git a/packages/core/src/genaisrc/system.agent_github.genai.mjs b/packages/core/src/genaisrc/system.agent_github.mjs similarity index 100% rename from packages/core/src/genaisrc/system.agent_github.genai.mjs rename to packages/core/src/genaisrc/system.agent_github.mjs diff --git a/packages/core/src/genaisrc/system.agent_interpreter.genai.mjs b/packages/core/src/genaisrc/system.agent_interpreter.mjs similarity index 100% rename from packages/core/src/genaisrc/system.agent_interpreter.genai.mjs rename to packages/core/src/genaisrc/system.agent_interpreter.mjs diff --git a/packages/core/src/genaisrc/system.agent_planner.genai.mjs b/packages/core/src/genaisrc/system.agent_planner.mjs similarity index 100% rename from packages/core/src/genaisrc/system.agent_planner.genai.mjs rename to packages/core/src/genaisrc/system.agent_planner.mjs diff --git a/packages/core/src/genaisrc/system.agent_user_input.genai.mjs b/packages/core/src/genaisrc/system.agent_user_input.mjs similarity index 100% rename from packages/core/src/genaisrc/system.agent_user_input.genai.mjs rename to packages/core/src/genaisrc/system.agent_user_input.mjs diff --git a/packages/core/src/genaisrc/system.agent_web.genai.mjs b/packages/core/src/genaisrc/system.agent_web.mjs similarity index 100% rename from packages/core/src/genaisrc/system.agent_web.genai.mjs rename to packages/core/src/genaisrc/system.agent_web.mjs diff --git a/packages/core/src/genaisrc/system.annotations.genai.mjs b/packages/core/src/genaisrc/system.annotations.mjs similarity index 100% rename from packages/core/src/genaisrc/system.annotations.genai.mjs rename to packages/core/src/genaisrc/system.annotations.mjs diff --git a/packages/core/src/genaisrc/system.assistant.genai.mjs b/packages/core/src/genaisrc/system.assistant.mjs similarity index 100% rename from packages/core/src/genaisrc/system.assistant.genai.mjs rename to packages/core/src/genaisrc/system.assistant.mjs diff --git a/packages/core/src/genaisrc/system.changelog.genai.mjs b/packages/core/src/genaisrc/system.changelog.mjs similarity index 100% rename from packages/core/src/genaisrc/system.changelog.genai.mjs rename to packages/core/src/genaisrc/system.changelog.mjs diff --git a/packages/core/src/genaisrc/system.diagrams.genai.mjs b/packages/core/src/genaisrc/system.diagrams.mjs similarity index 100% rename from packages/core/src/genaisrc/system.diagrams.genai.mjs rename to packages/core/src/genaisrc/system.diagrams.mjs diff --git a/packages/core/src/genaisrc/system.diff.genai.mjs b/packages/core/src/genaisrc/system.diff.mjs similarity index 100% rename from packages/core/src/genaisrc/system.diff.genai.mjs rename to packages/core/src/genaisrc/system.diff.mjs diff --git a/packages/core/src/genaisrc/system.explanations.genai.mjs b/packages/core/src/genaisrc/system.explanations.mjs similarity index 100% rename from packages/core/src/genaisrc/system.explanations.genai.mjs rename to packages/core/src/genaisrc/system.explanations.mjs diff --git a/packages/core/src/genaisrc/system.files.genai.mjs b/packages/core/src/genaisrc/system.files.mjs similarity index 100% rename from packages/core/src/genaisrc/system.files.genai.mjs rename to packages/core/src/genaisrc/system.files.mjs diff --git a/packages/core/src/genaisrc/system.files_schema.genai.mjs b/packages/core/src/genaisrc/system.files_schema.mjs similarity index 100% rename from packages/core/src/genaisrc/system.files_schema.genai.mjs rename to packages/core/src/genaisrc/system.files_schema.mjs diff --git a/packages/core/src/genaisrc/system.fs_ask_file.genai.mjs b/packages/core/src/genaisrc/system.fs_ask_file.mjs similarity index 100% rename from packages/core/src/genaisrc/system.fs_ask_file.genai.mjs rename to packages/core/src/genaisrc/system.fs_ask_file.mjs diff --git a/packages/core/src/genaisrc/system.fs_diff_files.genai.mjs b/packages/core/src/genaisrc/system.fs_diff_files.mjs similarity index 100% rename from packages/core/src/genaisrc/system.fs_diff_files.genai.mjs rename to packages/core/src/genaisrc/system.fs_diff_files.mjs diff --git a/packages/core/src/genaisrc/system.fs_find_files.genai.mjs b/packages/core/src/genaisrc/system.fs_find_files.mjs similarity index 100% rename from packages/core/src/genaisrc/system.fs_find_files.genai.mjs rename to packages/core/src/genaisrc/system.fs_find_files.mjs diff --git a/packages/core/src/genaisrc/system.fs_read_file.genai.mjs b/packages/core/src/genaisrc/system.fs_read_file.mjs similarity index 100% rename from packages/core/src/genaisrc/system.fs_read_file.genai.mjs rename to packages/core/src/genaisrc/system.fs_read_file.mjs diff --git a/packages/core/src/genaisrc/system.git.genai.mjs b/packages/core/src/genaisrc/system.git.mjs similarity index 100% rename from packages/core/src/genaisrc/system.git.genai.mjs rename to packages/core/src/genaisrc/system.git.mjs diff --git a/packages/core/src/genaisrc/system.git_diff.genai.mjs b/packages/core/src/genaisrc/system.git_diff.mjs similarity index 100% rename from packages/core/src/genaisrc/system.git_diff.genai.mjs rename to packages/core/src/genaisrc/system.git_diff.mjs diff --git a/packages/core/src/genaisrc/system.git_info.genai.mjs b/packages/core/src/genaisrc/system.git_info.mjs similarity index 100% rename from packages/core/src/genaisrc/system.git_info.genai.mjs rename to packages/core/src/genaisrc/system.git_info.mjs diff --git a/packages/core/src/genaisrc/system.github_actions.genai.mjs b/packages/core/src/genaisrc/system.github_actions.mjs similarity index 100% rename from packages/core/src/genaisrc/system.github_actions.genai.mjs rename to packages/core/src/genaisrc/system.github_actions.mjs diff --git a/packages/core/src/genaisrc/system.github_files.genai.mjs b/packages/core/src/genaisrc/system.github_files.mjs similarity index 100% rename from packages/core/src/genaisrc/system.github_files.genai.mjs rename to packages/core/src/genaisrc/system.github_files.mjs diff --git a/packages/core/src/genaisrc/system.github_info.genai.mjs b/packages/core/src/genaisrc/system.github_info.mjs similarity index 100% rename from packages/core/src/genaisrc/system.github_info.genai.mjs rename to packages/core/src/genaisrc/system.github_info.mjs diff --git a/packages/core/src/genaisrc/system.github_issues.genai.mjs b/packages/core/src/genaisrc/system.github_issues.mjs similarity index 100% rename from packages/core/src/genaisrc/system.github_issues.genai.mjs rename to packages/core/src/genaisrc/system.github_issues.mjs diff --git a/packages/core/src/genaisrc/system.github_pulls.genai.mjs b/packages/core/src/genaisrc/system.github_pulls.mjs similarity index 100% rename from packages/core/src/genaisrc/system.github_pulls.genai.mjs rename to packages/core/src/genaisrc/system.github_pulls.mjs diff --git a/packages/core/src/genaisrc/system.math.genai.mjs b/packages/core/src/genaisrc/system.math.mjs similarity index 100% rename from packages/core/src/genaisrc/system.math.genai.mjs rename to packages/core/src/genaisrc/system.math.mjs diff --git a/packages/core/src/genaisrc/system.md_find_files.genai.mjs b/packages/core/src/genaisrc/system.md_find_files.mjs similarity index 100% rename from packages/core/src/genaisrc/system.md_find_files.genai.mjs rename to packages/core/src/genaisrc/system.md_find_files.mjs diff --git a/packages/core/src/genaisrc/system.md_frontmatter.genai.mjs b/packages/core/src/genaisrc/system.md_frontmatter.mjs similarity index 100% rename from packages/core/src/genaisrc/system.md_frontmatter.genai.mjs rename to packages/core/src/genaisrc/system.md_frontmatter.mjs diff --git a/packages/core/src/genaisrc/system.meta_prompt.genai.mjs b/packages/core/src/genaisrc/system.meta_prompt.mjs similarity index 100% rename from packages/core/src/genaisrc/system.meta_prompt.genai.mjs rename to packages/core/src/genaisrc/system.meta_prompt.mjs diff --git a/packages/core/src/genaisrc/system.meta_schema.genai.mjs b/packages/core/src/genaisrc/system.meta_schema.mjs similarity index 100% rename from packages/core/src/genaisrc/system.meta_schema.genai.mjs rename to packages/core/src/genaisrc/system.meta_schema.mjs diff --git a/packages/core/src/genaisrc/system.genai.mjs b/packages/core/src/genaisrc/system.mjs similarity index 100% rename from packages/core/src/genaisrc/system.genai.mjs rename to packages/core/src/genaisrc/system.mjs diff --git a/packages/core/src/genaisrc/system.node_info.genai.mjs b/packages/core/src/genaisrc/system.node_info.mjs similarity index 100% rename from packages/core/src/genaisrc/system.node_info.genai.mjs rename to packages/core/src/genaisrc/system.node_info.mjs diff --git a/packages/core/src/genaisrc/system.node_test.genai.mjs b/packages/core/src/genaisrc/system.node_test.mjs similarity index 100% rename from packages/core/src/genaisrc/system.node_test.genai.mjs rename to packages/core/src/genaisrc/system.node_test.mjs diff --git a/packages/core/src/genaisrc/system.output_markdown.genai.mjs b/packages/core/src/genaisrc/system.output_markdown.mjs similarity index 100% rename from packages/core/src/genaisrc/system.output_markdown.genai.mjs rename to packages/core/src/genaisrc/system.output_markdown.mjs diff --git a/packages/core/src/genaisrc/system.output_plaintext.genai.mjs b/packages/core/src/genaisrc/system.output_plaintext.mjs similarity index 100% rename from packages/core/src/genaisrc/system.output_plaintext.genai.mjs rename to packages/core/src/genaisrc/system.output_plaintext.mjs diff --git a/packages/core/src/genaisrc/system.planner.genai.mjs b/packages/core/src/genaisrc/system.planner.mjs similarity index 100% rename from packages/core/src/genaisrc/system.planner.genai.mjs rename to packages/core/src/genaisrc/system.planner.mjs diff --git a/packages/core/src/genaisrc/system.python.genai.mjs b/packages/core/src/genaisrc/system.python.mjs similarity index 100% rename from packages/core/src/genaisrc/system.python.genai.mjs rename to packages/core/src/genaisrc/system.python.mjs diff --git a/packages/core/src/genaisrc/system.python_code_interpreter.genai.mjs b/packages/core/src/genaisrc/system.python_code_interpreter.mjs similarity index 100% rename from packages/core/src/genaisrc/system.python_code_interpreter.genai.mjs rename to packages/core/src/genaisrc/system.python_code_interpreter.mjs diff --git a/packages/core/src/genaisrc/system.python_types.genai.mjs b/packages/core/src/genaisrc/system.python_types.mjs similarity index 100% rename from packages/core/src/genaisrc/system.python_types.genai.mjs rename to packages/core/src/genaisrc/system.python_types.mjs diff --git a/packages/core/src/genaisrc/system.retrieval_fuzz_search.genai.mjs b/packages/core/src/genaisrc/system.retrieval_fuzz_search.mjs similarity index 100% rename from packages/core/src/genaisrc/system.retrieval_fuzz_search.genai.mjs rename to packages/core/src/genaisrc/system.retrieval_fuzz_search.mjs diff --git a/packages/core/src/genaisrc/system.retrieval_vector_search.genai.mjs b/packages/core/src/genaisrc/system.retrieval_vector_search.mjs similarity index 100% rename from packages/core/src/genaisrc/system.retrieval_vector_search.genai.mjs rename to packages/core/src/genaisrc/system.retrieval_vector_search.mjs diff --git a/packages/core/src/genaisrc/system.retrieval_web_search.genai.mjs b/packages/core/src/genaisrc/system.retrieval_web_search.mjs similarity index 100% rename from packages/core/src/genaisrc/system.retrieval_web_search.genai.mjs rename to packages/core/src/genaisrc/system.retrieval_web_search.mjs diff --git a/packages/core/src/genaisrc/system.safety_canary_word.genai.mjs b/packages/core/src/genaisrc/system.safety_canary_word.mjs similarity index 100% rename from packages/core/src/genaisrc/system.safety_canary_word.genai.mjs rename to packages/core/src/genaisrc/system.safety_canary_word.mjs diff --git a/packages/core/src/genaisrc/system.safety_harmful_content.genai.mjs b/packages/core/src/genaisrc/system.safety_harmful_content.mjs similarity index 100% rename from packages/core/src/genaisrc/system.safety_harmful_content.genai.mjs rename to packages/core/src/genaisrc/system.safety_harmful_content.mjs diff --git a/packages/core/src/genaisrc/system.safety_jailbreak.genai.mjs b/packages/core/src/genaisrc/system.safety_jailbreak.mjs similarity index 100% rename from packages/core/src/genaisrc/system.safety_jailbreak.genai.mjs rename to packages/core/src/genaisrc/system.safety_jailbreak.mjs diff --git a/packages/core/src/genaisrc/system.safety_protected_material.genai.mjs b/packages/core/src/genaisrc/system.safety_protected_material.mjs similarity index 100% rename from packages/core/src/genaisrc/system.safety_protected_material.genai.mjs rename to packages/core/src/genaisrc/system.safety_protected_material.mjs diff --git a/packages/core/src/genaisrc/system.safety_ungrounded_content_summarization.genai.mjs b/packages/core/src/genaisrc/system.safety_ungrounded_content_summarization.mjs similarity index 100% rename from packages/core/src/genaisrc/system.safety_ungrounded_content_summarization.genai.mjs rename to packages/core/src/genaisrc/system.safety_ungrounded_content_summarization.mjs diff --git a/packages/core/src/genaisrc/system.safety_validate_harmful_content.genai.mjs b/packages/core/src/genaisrc/system.safety_validate_harmful_content.mjs similarity index 100% rename from packages/core/src/genaisrc/system.safety_validate_harmful_content.genai.mjs rename to packages/core/src/genaisrc/system.safety_validate_harmful_content.mjs diff --git a/packages/core/src/genaisrc/system.schema.genai.mjs b/packages/core/src/genaisrc/system.schema.mjs similarity index 100% rename from packages/core/src/genaisrc/system.schema.genai.mjs rename to packages/core/src/genaisrc/system.schema.mjs diff --git a/packages/core/src/genaisrc/system.tasks.genai.mjs b/packages/core/src/genaisrc/system.tasks.mjs similarity index 100% rename from packages/core/src/genaisrc/system.tasks.genai.mjs rename to packages/core/src/genaisrc/system.tasks.mjs diff --git a/packages/core/src/genaisrc/system.technical.genai.mjs b/packages/core/src/genaisrc/system.technical.mjs similarity index 100% rename from packages/core/src/genaisrc/system.technical.genai.mjs rename to packages/core/src/genaisrc/system.technical.mjs diff --git a/packages/core/src/genaisrc/system.tool_calls.genai.mjs b/packages/core/src/genaisrc/system.tool_calls.mjs similarity index 100% rename from packages/core/src/genaisrc/system.tool_calls.genai.mjs rename to packages/core/src/genaisrc/system.tool_calls.mjs diff --git a/packages/core/src/genaisrc/system.tools.genai.mjs b/packages/core/src/genaisrc/system.tools.mjs similarity index 100% rename from packages/core/src/genaisrc/system.tools.genai.mjs rename to packages/core/src/genaisrc/system.tools.mjs diff --git a/packages/core/src/genaisrc/system.typescript.genai.mjs b/packages/core/src/genaisrc/system.typescript.mjs similarity index 100% rename from packages/core/src/genaisrc/system.typescript.genai.mjs rename to packages/core/src/genaisrc/system.typescript.mjs diff --git a/packages/core/src/genaisrc/system.user_input.genai.mjs b/packages/core/src/genaisrc/system.user_input.mjs similarity index 100% rename from packages/core/src/genaisrc/system.user_input.genai.mjs rename to packages/core/src/genaisrc/system.user_input.mjs diff --git a/packages/core/src/genaisrc/system.vision_ask_image.genai.mjs b/packages/core/src/genaisrc/system.vision_ask_image.mjs similarity index 100% rename from packages/core/src/genaisrc/system.vision_ask_image.genai.mjs rename to packages/core/src/genaisrc/system.vision_ask_image.mjs diff --git a/packages/core/src/genaisrc/system.zero_shot_cot.genai.mjs b/packages/core/src/genaisrc/system.zero_shot_cot.mjs similarity index 100% rename from packages/core/src/genaisrc/system.zero_shot_cot.genai.mjs rename to packages/core/src/genaisrc/system.zero_shot_cot.mjs diff --git a/packages/core/src/openai.ts b/packages/core/src/openai.ts index 97751dfcfd..d2d23bebb2 100644 --- a/packages/core/src/openai.ts +++ b/packages/core/src/openai.ts @@ -24,10 +24,6 @@ import { RequestError, errorMessage, serializeError } from "./error" import { createFetch, iterateBody, traceFetchPost } from "./fetch" import { parseModelIdentifier } from "./models" import { JSON5TryParse } from "./json5" -import { - ChatCompletionRequestCacheKey, - getChatCompletionCache, -} from "./chatcache" import { ChatCompletionToolCall, ChatCompletionResponse, @@ -99,36 +95,6 @@ export const OpenAIChatCompletion: ChatCompletionHandler = async ( const { provider, model } = parseModelIdentifier(req.model) const { encode: encoder } = await resolveTokenEncoder(model) - const cache = !!cacheOrName || !!cacheName - const cacheStore = getChatCompletionCache( - typeof cacheOrName === "string" ? cacheOrName : cacheName - ) - const cachedKey = cache - ? { - ...req, - ...cfgNoToken, - model: req.model, - temperature: req.temperature, - top_p: req.top_p, - max_tokens: req.max_tokens, - logit_bias: req.logit_bias, - } - : undefined - trace.itemValue(`caching`, cache) - trace.itemValue(`cache`, cacheStore?.name) - const { text: cached, finishReason: cachedFinishReason } = - (await cacheStore.get(cachedKey)) || {} - if (cached !== undefined) { - partialCb?.({ - tokensSoFar: estimateTokens(cached, encoder), - responseSoFar: cached, - responseChunk: cached, - inner, - }) - trace.itemValue(`cache hit`, await cacheStore.getKeySHA(cachedKey)) - return { text: cached, finishReason: cachedFinishReason, cached: true } - } - const postReq = structuredClone({ ...req, messages: req.messages.map(({ cacheControl, ...rest }) => ({ @@ -428,8 +394,6 @@ export const OpenAIChatCompletion: ChatCompletionHandler = async ( ) } - if (done && finishReason === "stop") - await cacheStore.set(cachedKey, { text: chatResp, finishReason }) return { text: chatResp, toolCalls, diff --git a/packages/core/src/parsers.test.ts b/packages/core/src/parsers.test.ts index aaa0a5ae6e..3e42c5dc74 100644 --- a/packages/core/src/parsers.test.ts +++ b/packages/core/src/parsers.test.ts @@ -61,7 +61,7 @@ describe("parsers", async () => { ) let i = 1 for (const img of result.images) { - await writeFile(`./loremipsum.temp.${i++}.png`, img) + await writeFile(`./loremipsum.temp.${i++}.png`, img) } assert(result.file.content.includes("Lorem")) }) @@ -120,8 +120,8 @@ describe("parsers", async () => { test("hash", async () => { const result = await parsers.hash( { test: "test string", arr: [1, 2, "32"], v: new Uint8Array(123) }, - { length: 20 } + { length: 20, version: false } ) - assert.strictEqual(result, "2c34c8d7df7428c89c64") // Example hash value + assert.strictEqual(result, "889772de6ac65b917519") // Example hash value }) }) diff --git a/packages/core/src/promptcontext.ts b/packages/core/src/promptcontext.ts index e1ec28c811..513bd9f80f 100644 --- a/packages/core/src/promptcontext.ts +++ b/packages/core/src/promptcontext.ts @@ -112,20 +112,20 @@ export async function createPromptContext( webSearch: async (q, options) => { const { provider, count, ignoreMissingProvider } = options || {} // Conduct a web search and return the results + const webTrace = trace.startTraceDetails( + `🌐 web search ${HTMLEscape(q)}` + ) try { - trace.startDetails( - `🌐 web search ${HTMLEscape(q)}` - ) let files: WorkspaceFile[] if (provider === "bing") - files = await bingSearch(q, { trace, count }) + files = await bingSearch(q, { trace: webTrace, count }) else if (provider === "tavily") - files = await tavilySearch(q, { trace, count }) + files = await tavilySearch(q, { trace: webTrace, count }) else { for (const f of [bingSearch, tavilySearch]) { files = await f(q, { ignoreMissingApiKey: true, - trace, + trace: webTrace, count, }) if (files) break @@ -133,17 +133,17 @@ export async function createPromptContext( } if (!files) { if (ignoreMissingProvider) { - trace.log(`no search provider configured`) + webTrace.log(`no search provider configured`) return undefined } throw new Error( `No search provider configured. See ${DOCS_WEB_SEARCH_URL}.` ) } - trace.files(files, { model, secrets: env.secrets }) + webTrace.files(files, { model, secrets: env.secrets }) return files } finally { - trace.endDetails() + webTrace.endDetails() } }, fuzzSearch: async (q, files_, searchOptions) => { diff --git a/packages/core/src/trace.ts b/packages/core/src/trace.ts index 175d804faf..c4e7912a3d 100644 --- a/packages/core/src/trace.ts +++ b/packages/core/src/trace.ts @@ -55,7 +55,7 @@ export class MarkdownTrace extends EventTarget implements ToolCallTrace { .join("") } - startTraceDetails(title: string) { + startTraceDetails(title: string, options?: { expanded?: boolean }) { const trace = new MarkdownTrace({ ...this.options }) trace.addEventListener(TRACE_CHUNK, (ev) => this.dispatchEvent( @@ -65,7 +65,7 @@ export class MarkdownTrace extends EventTarget implements ToolCallTrace { trace.addEventListener(TRACE_DETAILS, () => this.dispatchEvent(new Event(TRACE_DETAILS)) ) - trace.startDetails(title) + trace.startDetails(title, options) this._content.push(trace) return trace } diff --git a/packages/core/src/transformers.ts b/packages/core/src/transformers.ts index f9b70845c9..8ffa686a4c 100644 --- a/packages/core/src/transformers.ts +++ b/packages/core/src/transformers.ts @@ -15,10 +15,6 @@ import { deleteUndefinedValues, dotGenaiscriptPath, logVerbose } from "./util" import { parseModelIdentifier } from "./models" import prettyBytes from "pretty-bytes" import { hash } from "./crypto" -import { - ChatCompletionRequestCacheKey, - getChatCompletionCache, -} from "./chatcache" import { PLimitPromiseQueue } from "./concurrency" function progressBar(): ProgressCallback { @@ -74,35 +70,6 @@ export const TransformersCompletion: ChatCompletionHandler = async ( trace.itemValue("model", model) - const cache = !!cacheOrName || !!cacheName - const cacheStore = getChatCompletionCache( - typeof cacheOrName === "string" ? cacheOrName : cacheName - ) - const cachedKey = cache - ? { - ...req, - model: req.model, - temperature: req.temperature, - top_p: req.top_p, - max_tokens: req.max_tokens, - logit_bias: req.logit_bias, - } - : undefined - trace.itemValue(`caching`, cache) - trace.itemValue(`cache`, cacheStore?.name) - const { text: cached, finishReason: cachedFinishReason } = - (await cacheStore.get(cachedKey)) || {} - if (cached !== undefined) { - partialCb?.({ - tokensSoFar: 0, // TODO - responseSoFar: cached, - responseChunk: cached, - inner, - }) - trace.itemValue(`cache hit`, await cacheStore.getKeySHA(cachedKey)) - return { text: cached, finishReason: cachedFinishReason, cached: true } - } - const device = process.env.HUGGINGFACE_TRANSFORMERS_DEVICE || process.env.TRANSFORMERS_DEVICE || @@ -134,7 +101,9 @@ export const TransformersCompletion: ChatCompletionHandler = async ( tokensSoFar, responseSoFar: chatResp, responseChunk: text, - responseTokens: [{ token: text, logprob: Number.NaN } satisfies Logprob], + responseTokens: [ + { token: text, logprob: Number.NaN } satisfies Logprob, + ], inner, }) }, @@ -165,9 +134,6 @@ export const TransformersCompletion: ChatCompletionHandler = async ( }) const finishReason = "stop" - if (finishReason === "stop") - await cacheStore.set(cachedKey, { text, finishReason }) - return { text, finishReason: "stop", diff --git a/packages/core/src/usage.ts b/packages/core/src/usage.ts index fe84898da1..a0f3b9ae7c 100644 --- a/packages/core/src/usage.ts +++ b/packages/core/src/usage.ts @@ -82,6 +82,7 @@ export class GenerationStats { messages: ChatCompletionMessageParam[] usage: ChatCompletionUsage model: string + cached: boolean }[] = [] /** @@ -305,31 +306,35 @@ export class GenerationStats { const { usage = { completion_tokens: 0, prompt_tokens: 0, total_tokens: 0 }, model, + cached, } = resp const { messages } = req - this.usage.completion_tokens += usage.completion_tokens ?? 0 - this.usage.prompt_tokens += usage.prompt_tokens ?? 0 - this.usage.total_tokens += usage.total_tokens ?? 0 + if (!cached) { + this.usage.completion_tokens += usage.completion_tokens ?? 0 + this.usage.prompt_tokens += usage.prompt_tokens ?? 0 + this.usage.total_tokens += usage.total_tokens ?? 0 - this.usage.completion_tokens_details.audio_tokens += - usage.completion_tokens_details?.audio_tokens ?? 0 - this.usage.completion_tokens_details.reasoning_tokens += - usage.completion_tokens_details?.reasoning_tokens ?? 0 - this.usage.completion_tokens_details.audio_tokens += - usage.prompt_tokens_details?.audio_tokens ?? 0 - this.usage.completion_tokens_details.reasoning_tokens += - usage.prompt_tokens_details?.cached_tokens ?? 0 - this.usage.completion_tokens_details.accepted_prediction_tokens += - usage.completion_tokens_details?.accepted_prediction_tokens ?? 0 - this.usage.completion_tokens_details.rejected_prediction_tokens += - usage.completion_tokens_details?.rejected_prediction_tokens ?? 0 + this.usage.completion_tokens_details.audio_tokens += + usage.completion_tokens_details?.audio_tokens ?? 0 + this.usage.completion_tokens_details.reasoning_tokens += + usage.completion_tokens_details?.reasoning_tokens ?? 0 + this.usage.completion_tokens_details.audio_tokens += + usage.prompt_tokens_details?.audio_tokens ?? 0 + this.usage.completion_tokens_details.reasoning_tokens += + usage.prompt_tokens_details?.cached_tokens ?? 0 + this.usage.completion_tokens_details.accepted_prediction_tokens += + usage.completion_tokens_details?.accepted_prediction_tokens ?? 0 + this.usage.completion_tokens_details.rejected_prediction_tokens += + usage.completion_tokens_details?.rejected_prediction_tokens ?? 0 + } const { provider } = parseModelIdentifier(this.model) const chatTurn = { messages: structuredClone(messages), usage: structuredClone(usage), model: `${provider}:${model}`, + cached, } this.chatTurns.push(chatTurn) } diff --git a/packages/sample/genaisrc/cache.genai.mts b/packages/sample/genaisrc/cache.genai.mts index b85e951eca..369bcf4717 100644 --- a/packages/sample/genaisrc/cache.genai.mts +++ b/packages/sample/genaisrc/cache.genai.mts @@ -23,6 +23,15 @@ for (const cache of [ console.log(`cache test passed`) +const innerPrompt = `Generate 2 word poem. ${Math.random()}` +await Promise.all( + Array(10) + .fill(0) + .map(async (_, i) => { + await runPrompt(innerPrompt, { cache: "inner", label: `run-${i}` }) + }) +) + $`Generate 2 word poem.` defOutputProcessor(async ({ text }) => { diff --git a/packages/sample/src/cli.test.ts b/packages/sample/src/cli.test.ts index 759b4b661b..113aace06f 100644 --- a/packages/sample/src/cli.test.ts +++ b/packages/sample/src/cli.test.ts @@ -36,7 +36,11 @@ describe("scripts", async () => { const cmd = "scripts" await test("list", async () => { const res = await $`node ${cli} ${cmd} list` - assert(res.stdout.includes("id: poem")) + const d = JSON.parse(res.stdout) + assert(d.find((s) => s.id === "poem")) + assert(d.find((s) => s.id === "system")) + assert(d.find((s) => s.id === "system.output_markdown")) + assert(!d.some((s) => s.system && s.filename)) }) await test("create foobar", async () => { const res = await $`node ${cli} ${cmd} create foobar` diff --git a/packages/vscode/src/llmrequesttree.ts b/packages/vscode/src/llmrequesttree.ts index f8487607db..60d06c770d 100644 --- a/packages/vscode/src/llmrequesttree.ts +++ b/packages/vscode/src/llmrequesttree.ts @@ -2,17 +2,19 @@ import * as vscode from "vscode" import { ExtensionState } from "./state" import { infoUri } from "./markdowndocumentprovider" import { CacheEntry } from "../../core/src/cache" -import { CreateChatCompletionRequest } from "../../core/src/chattypes" +import { + ChatCompletionResponse, + CreateChatCompletionRequest, +} from "../../core/src/chattypes" import { CHANGE, CACHE_LLMREQUEST_PREFIX } from "../../core/src/constants" import { ChatCompletationRequestCache, - ChatCompletationRequestCacheValue, getChatCompletionCache, } from "../../core/src/chatcache" type LLMRequestTreeNode = CacheEntry< CreateChatCompletionRequest, - ChatCompletationRequestCacheValue + ChatCompletionResponse > class LLMRequestTreeDataProvider