diff --git a/index.ts b/index.ts index 10cc18a..1702945 100644 --- a/index.ts +++ b/index.ts @@ -33,7 +33,6 @@ const streamCommandCode = createStreamCommandCode({ // --------------------------------------------------------------------------- export default async function (pi: ExtensionAPI) { - const models = await fetchCommandCodeModels({ url: MODELS_URL }) pi.registerProvider("commandcode", { diff --git a/package-lock.json b/package-lock.json index 60649e2..cbcca43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1680,18 +1680,19 @@ "license": "BSD-3-Clause" }, "node_modules/@protobufjs/eventemitter": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", - "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/fetch": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", - "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", "license": "BSD-3-Clause", "dependencies": { - "@protobufjs/aspromise": "^1.1.1" + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" } }, "node_modules/@protobufjs/float": { @@ -1701,9 +1702,9 @@ "license": "BSD-3-Clause" }, "node_modules/@protobufjs/inquire": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.2.tgz", - "integrity": "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.1.tgz", + "integrity": "sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/path": { @@ -2545,9 +2546,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3660,24 +3661,24 @@ } }, "node_modules/protobufjs": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.1.tgz", - "integrity": "sha512-4K0myLaWL5EteuSAro91EGFgcfVgxb64Jx+7oDAY6GOkXD4M69yuSEljNcInGVCA5sOPxmZ/EqDLj2x0Q0+Ygg==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.6.tgz", + "integrity": "sha512-M71sTMB146U3u0di3yup8iM+zv8yPRNQVr1KK4tyBitl3qFvEGucq/rGDRShD2rsJhtN02RJaJ7j5X5hmy8SJg==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.5", - "@protobufjs/eventemitter": "^1.1.1", - "@protobufjs/fetch": "^1.1.1", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.2", + "@protobufjs/inquire": "^1.1.1", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", - "long": "^5.3.2" + "long": "^5.0.0" }, "engines": { "node": ">=12.0.0" @@ -4129,9 +4130,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", - "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", "license": "MIT", "engines": { "node": ">=10.0.0" diff --git a/src/converters.ts b/src/converters.ts index 5f60a07..38ca0d3 100644 --- a/src/converters.ts +++ b/src/converters.ts @@ -39,7 +39,11 @@ export function numberValue(value: unknown): number | undefined { } function defaultAuthPaths(home: string): string[] { - return [join(home, ".commandcode", "auth.json"), join(home, ".omp", "agent", "auth.json"), join(home, ".pi", "agent", "auth.json")] + return [ + join(home, ".commandcode", "auth.json"), + join(home, ".omp", "agent", "auth.json"), + join(home, ".pi", "agent", "auth.json"), + ] } function apiKeyFromCredentialRecord(value: unknown): string | undefined { @@ -288,7 +292,11 @@ export function mapFinishReason(reason: unknown): StopReason { function promptPartToText(value: unknown, depth = 0): string { if (depth > 10) return "" if (typeof value === "string") return value - if (Array.isArray(value)) return value.map((v) => promptPartToText(v, depth + 1)).filter(Boolean).join("\n") + if (Array.isArray(value)) + return value + .map((v) => promptPartToText(v, depth + 1)) + .filter(Boolean) + .join("\n") if (!isRecord(value)) return "" const text = stringValue(value.text) if (text) return text @@ -300,7 +308,10 @@ function promptPartToText(value: unknown, depth = 0): string { export function systemPromptToText(value: unknown): string { if (value === undefined || value === null) return "" if (typeof value === "string") return value - if (Array.isArray(value)) return value.map((v) => promptPartToText(v, 0)).filter(Boolean).join("\n\n") + if (Array.isArray(value)) + return value + .map((v) => promptPartToText(v, 0)) + .filter(Boolean) + .join("\n\n") return promptPartToText(value, 0) } - diff --git a/src/core.ts b/src/core.ts index eaa22b5..41a6560 100644 --- a/src/core.ts +++ b/src/core.ts @@ -18,7 +18,7 @@ import { recordOrEmpty, stringValue, toolsToJson, - systemPromptToText + systemPromptToText, } from "./converters.ts" import type { AssistantMessageEventStreamLike, @@ -135,9 +135,7 @@ export function createStreamCommandCode(deps: CoreDependencies) { // OMP may pass the env-var name "COMMANDCODE_API_KEY" as the apiKey // value instead of resolving it. Filter out this specific string. const hostKey = - options?.apiKey && options.apiKey !== "COMMANDCODE_API_KEY" - ? options.apiKey - : undefined + options?.apiKey && options.apiKey !== "COMMANDCODE_API_KEY" ? options.apiKey : undefined const apiKey = hostKey ?? @@ -157,7 +155,7 @@ export function createStreamCommandCode(deps: CoreDependencies) { usage: defaultUsage(), stopReason: "error", errorMessage: - "No Command Code API key. Run /login and select Command Code, set COMMANDCODE_API_KEY env var, or configure ~/.commandcode/auth.json or ~/.pi/agent/auth.json.", + "No Command Code API key. Run /login and select Command Code, set the COMMANDCODE_API_KEY env var, or configure ~/.commandcode/auth.json, ~/.pi/agent/auth.json or ~/.omp/agent/auth.json", timestamp: now(), } stream.push({ type: "error", reason: "error", error: msg }) diff --git a/tests/test-omp-compat.mjs b/tests/test-omp-compat.mjs index 4517c83..b591675 100644 --- a/tests/test-omp-compat.mjs +++ b/tests/test-omp-compat.mjs @@ -177,10 +177,10 @@ try { assert.equal(print.code, 0, print.stderr) assert.match(print.stdout, /mock-omp-ok/) assert.equal(requestCount, 1) - assert.ok( - typeof lastRequestHeaders.authorization === "string" && - lastRequestHeaders.authorization.startsWith("Bearer "), - "should send a bearer Authorization header", + assert.equal( + lastRequestHeaders.authorization, + "Bearer mock-key", + "should send the resolved env-var value, not the literal var name", ) assert.equal(lastRequestBody?.params?.model, TEST_MODEL) assert.equal(typeof lastRequestBody?.params?.system, "string") diff --git a/tests/test-stream.ts b/tests/test-stream.ts index 42659ce..621891d 100644 --- a/tests/test-stream.ts +++ b/tests/test-stream.ts @@ -54,6 +54,27 @@ describe("streamCommandCode — auth", () => { assert.equal(server.requestCount(), 0) }) + it("ignores the literal env-var name and falls back to env", async () => { + server.mockResponse({ + type: "success", + events: [JSON.stringify({ type: "finish", finishReason: "stop" })], + }) + const { streamCommandCode } = createTestDeps({ + apiBase: server.baseUrl(), + env: { COMMANDCODE_API_KEY: "env-key" }, + }) + + await collectEvents( + streamCommandCode(makeModel(), makeContext(), { apiKey: "COMMANDCODE_API_KEY" }), + ) + + assert.equal( + server.lastRequestHeaders().authorization, + "Bearer env-key", + "should resolve from env, not send the literal var name as the token", + ) + }) + it("uses options.apiKey in the Authorization header", async () => { server.mockResponse({ type: "success",