zidane 8.2.1 → 8.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/acp-cli.js +8 -8
- package/dist/{acp-D7Pr8NGt.js → acp-oYRjlh71.js} +6 -6
- package/dist/{acp-D7Pr8NGt.js.map → acp-oYRjlh71.js.map} +1 -1
- package/dist/acp.d.ts +2 -2
- package/dist/acp.js +1 -1
- package/dist/{agent-DecDtKA_.js → agent-CBQglXtH.js} +9 -379
- package/dist/agent-CBQglXtH.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/{builtin-artifact-kinds-B_OEgf8b.js → builtin-artifact-kinds-BmorPkgz.js} +36 -9
- package/dist/builtin-artifact-kinds-BmorPkgz.js.map +1 -0
- package/dist/chat/pure.d.ts +4 -4
- package/dist/chat/pure.js +6 -6
- package/dist/chat.d.ts +4 -4
- package/dist/chat.js +15 -15
- package/dist/{cli-shared-Dx4vmif6.js → cli-shared-E5m_pI8A.js} +2 -2
- package/dist/{cli-shared-Dx4vmif6.js.map → cli-shared-E5m_pI8A.js.map} +1 -1
- package/dist/{client-core-imHuBWV3.d.ts → client-core-EEEX_u6D.d.ts} +24 -5
- package/dist/{client-core-imHuBWV3.d.ts.map → client-core-EEEX_u6D.d.ts.map} +1 -1
- package/dist/{connection-loop-CdHt3iQi.d.ts → connection-loop-CpgfUmuw.d.ts} +3 -3
- package/dist/{connection-loop-CdHt3iQi.d.ts.map → connection-loop-CpgfUmuw.d.ts.map} +1 -1
- package/dist/contexts/daytona.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +1 -1
- package/dist/{credentials-Dti61yoi.js → credentials-B9DfBJP9.js} +11 -7
- package/dist/credentials-B9DfBJP9.js.map +1 -0
- package/dist/daemon-cli.js +2 -2
- package/dist/{dispatcher-vy3J6JMA.js → dispatcher-Bv9-c6I2.js} +28 -14
- package/dist/dispatcher-Bv9-c6I2.js.map +1 -0
- package/dist/{engine-BN6PjWAW.js → engine-XmoPPB6U.js} +5 -5
- package/dist/{engine-BN6PjWAW.js.map → engine-XmoPPB6U.js.map} +1 -1
- package/dist/{eval-BaJtxLCW.js → eval-CfQlBR81.js} +2 -2
- package/dist/{eval-BaJtxLCW.js.map → eval-CfQlBR81.js.map} +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +1 -1
- package/dist/{executor-CT4oUkg6.js → executor-BhthPE1q.js} +3 -3
- package/dist/{executor-CT4oUkg6.js.map → executor-BhthPE1q.js.map} +1 -1
- package/dist/{extensions-BKt7lxxv.js → extensions-BgBwogRW.js} +114 -113
- package/dist/extensions-BgBwogRW.js.map +1 -0
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +2 -2
- package/dist/{fold-rules-BYedvsH7.d.ts → fold-rules-DSypi36k.d.ts} +2 -2
- package/dist/{fold-rules-BYedvsH7.d.ts.map → fold-rules-DSypi36k.d.ts.map} +1 -1
- package/dist/google-O6pRnddf.js +881 -0
- package/dist/google-O6pRnddf.js.map +1 -0
- package/dist/{headless-Ebd1ZEzC.js → headless-R4pbpTkm.js} +3 -3
- package/dist/{headless-Ebd1ZEzC.js.map → headless-R4pbpTkm.js.map} +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -1
- package/dist/{host-scoped-settings-Cy_zbmB_.js → host-scoped-settings-C-Nmb6vr.js} +2 -2
- package/dist/{host-scoped-settings-Cy_zbmB_.js.map → host-scoped-settings-C-Nmb6vr.js.map} +1 -1
- package/dist/{host-signals-Cx2IAbHh.js → host-signals-BFudPyCT.js} +5 -5
- package/dist/{host-signals-Cx2IAbHh.js.map → host-signals-BFudPyCT.js.map} +1 -1
- package/dist/{index-pc71ADi6.d.ts → index-AqRZ3gEz.d.ts} +71 -4
- package/dist/index-AqRZ3gEz.d.ts.map +1 -0
- package/dist/{index-Bt_G2Z_2.d.ts → index-CDS7YdUC.d.ts} +5 -5
- package/dist/{index-Bt_G2Z_2.d.ts.map → index-CDS7YdUC.d.ts.map} +1 -1
- package/dist/{index-CidMTcxS.d.ts → index-DyQyDLX1.d.ts} +167 -10
- package/dist/index-DyQyDLX1.d.ts.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +15 -15
- package/dist/ipc/remote.d.ts +5 -5
- package/dist/ipc/remote.js +3 -3
- package/dist/ipc.d.ts +5 -5
- package/dist/ipc.js +7 -7
- package/dist/{links-DSZ4uQ5w.js → links-rFaWqS2Y.js} +10 -10
- package/dist/{links-DSZ4uQ5w.js.map → links-rFaWqS2Y.js.map} +1 -1
- package/dist/{mcp-allowlist-BQ5MvhHi.js → mcp-allowlist-CLXweyxk.js} +14 -3
- package/dist/mcp-allowlist-CLXweyxk.js.map +1 -0
- package/dist/mcp.d.ts +1 -1
- package/dist/{oauth-BSqXgads.js → oauth-7_48zR7n.js} +226 -40
- package/dist/oauth-7_48zR7n.js.map +1 -0
- package/dist/{openai-dTmPxM6T.js → openai-Rh6u5NXF.js} +121 -2
- package/dist/openai-Rh6u5NXF.js.map +1 -0
- package/dist/{openrouter-CtZbQDa0.js → openrouter-Dg0yaI-o.js} +91 -2
- package/dist/openrouter-Dg0yaI-o.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/{presets-EzlHyFSi.js → presets-DXeHsd24.js} +3 -3
- package/dist/{presets-EzlHyFSi.js.map → presets-DXeHsd24.js.map} +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/{prompts-D2lPHLOV.d.ts → prompts-DmY13jvF.d.ts} +2 -1
- package/dist/prompts-DmY13jvF.d.ts.map +1 -0
- package/dist/protocol-BIv1Yuvl.js.map +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/google.d.ts +1 -1
- package/dist/providers/google.js +1 -784
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/neuralwatt.d.ts +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.js +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/openrouter.js +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers/xai.js +1 -101
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +6 -5
- package/dist/{registry-BBaEgTsX.js → registry-eourRLY2.js} +3 -3
- package/dist/{registry-BBaEgTsX.js.map → registry-eourRLY2.js.map} +1 -1
- package/dist/{remote-hosts-bO7wOt44.js → remote-hosts-DY2J07ut.js} +4 -4
- package/dist/{remote-hosts-bO7wOt44.js.map → remote-hosts-DY2J07ut.js.map} +1 -1
- package/dist/restate.d.ts +1 -1
- package/dist/{secret-shapes-Cda65uDH.js → secret-shapes-BjW4l6U0.js} +17 -3
- package/dist/secret-shapes-BjW4l6U0.js.map +1 -0
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/{session-factory-BazyVdzj.js → session-factory-CMwIXE-7.js} +5 -5
- package/dist/{session-factory-BazyVdzj.js.map → session-factory-CMwIXE-7.js.map} +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/{settings-keys-zYaer8DY.js → settings-keys-CPdmkTz7.js} +3 -3
- package/dist/{settings-keys-zYaer8DY.js.map → settings-keys-CPdmkTz7.js.map} +1 -1
- package/dist/{shell-path-od9XHRPt.js → shell-path-B8b3EOtK.js} +3 -3
- package/dist/{shell-path-od9XHRPt.js.map → shell-path-B8b3EOtK.js.map} +1 -1
- package/dist/{skills-use-D68a1gyZ.js → skills-use-CssTEaIj.js} +375 -2
- package/dist/skills-use-CssTEaIj.js.map +1 -0
- package/dist/skills.d.ts +1 -1
- package/dist/store-L01W0gGI.js.map +1 -1
- package/dist/{system-freeze-DXvJpveP.js → system-freeze-Um9ZJiPo.js} +24 -9
- package/dist/system-freeze-Um9ZJiPo.js.map +1 -0
- package/dist/{todo-edits-CmqNFvLJ.js → todo-edits-BERpCRPj.js} +3 -3
- package/dist/{todo-edits-CmqNFvLJ.js.map → todo-edits-BERpCRPj.js.map} +1 -1
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/prompts.d.ts +1 -1
- package/dist/tools/prompts.js +7 -0
- package/dist/tools/prompts.js.map +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/{tools-9Dpm8F-f.js → tools-pZVFIJ_K.js} +273 -2
- package/dist/tools-pZVFIJ_K.js.map +1 -0
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +4 -4
- package/dist/{transcript-anchors-B3TFJqr_.js → transcript-anchors-jHrg-r-H.js} +10 -10
- package/dist/{transcript-anchors-B3TFJqr_.js.map → transcript-anchors-jHrg-r-H.js.map} +1 -1
- package/dist/{transcript-reconcile-BC2DbTmp.js → transcript-reconcile-CPdrNbbR.js} +19 -2
- package/dist/{transcript-reconcile-BC2DbTmp.js.map → transcript-reconcile-CPdrNbbR.js.map} +1 -1
- package/dist/tui.d.ts +7 -7
- package/dist/tui.js +25 -23
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-CIFoOebZ.d.ts → turn-operations-DuGtKuc_.d.ts} +10 -3
- package/dist/turn-operations-DuGtKuc_.d.ts.map +1 -0
- package/dist/{types-iFLlZKd0.d.ts → types-C0PJmBaO.d.ts} +2 -2
- package/dist/{types-iFLlZKd0.d.ts.map → types-C0PJmBaO.d.ts.map} +1 -1
- package/dist/types-JzccL5GE.js +24 -0
- package/dist/types-JzccL5GE.js.map +1 -0
- package/dist/types.d.ts +2 -2
- package/dist/{url-BTH-HE9Y.js → url-D8KZ7Edw.js} +2 -2
- package/dist/{url-BTH-HE9Y.js.map → url-D8KZ7Edw.js.map} +1 -1
- package/dist/{version-4T82xRxQ.js → version-bd3DQJkc.js} +2 -2
- package/dist/{version-4T82xRxQ.js.map → version-bd3DQJkc.js.map} +1 -1
- package/dist/wire-DH77Z-rr.js +80 -0
- package/dist/wire-DH77Z-rr.js.map +1 -0
- package/dist/{workspace-exec-stream-By8na6vz.js → workspace-exec-stream-CyfYgqAh.js} +4 -4
- package/dist/{workspace-exec-stream-By8na6vz.js.map → workspace-exec-stream-CyfYgqAh.js.map} +1 -1
- package/dist/{write-file-B4vi3SvQ.js → write-file-QYrcDdl3.js} +3 -3
- package/dist/{write-file-B4vi3SvQ.js.map → write-file-QYrcDdl3.js.map} +1 -1
- package/dist/{ws-CS312Jpx.js → ws-CURQ2igk.js} +5 -5
- package/dist/{ws-CS312Jpx.js.map → ws-CURQ2igk.js.map} +1 -1
- package/dist/{ws-client-wWka-Jku.js → ws-client-BVljYbdb.js} +3 -3
- package/dist/{ws-client-wWka-Jku.js.map → ws-client-BVljYbdb.js.map} +1 -1
- package/dist/xai-CStTwCV2.js +182 -0
- package/dist/xai-CStTwCV2.js.map +1 -0
- package/docs/ARCHITECTURE.md +1 -0
- package/docs/ARTIFACTS.md +1 -1
- package/docs/EXTENSIONS.md +9 -5
- package/package.json +2 -2
- package/dist/agent-DecDtKA_.js.map +0 -1
- package/dist/builtin-artifact-kinds-B_OEgf8b.js.map +0 -1
- package/dist/credentials-Dti61yoi.js.map +0 -1
- package/dist/dispatcher-vy3J6JMA.js.map +0 -1
- package/dist/extensions-BKt7lxxv.js.map +0 -1
- package/dist/index-CidMTcxS.d.ts.map +0 -1
- package/dist/index-pc71ADi6.d.ts.map +0 -1
- package/dist/mcp-allowlist-BQ5MvhHi.js.map +0 -1
- package/dist/oauth-BSqXgads.js.map +0 -1
- package/dist/openai-dTmPxM6T.js.map +0 -1
- package/dist/openrouter-CtZbQDa0.js.map +0 -1
- package/dist/prompts-D2lPHLOV.d.ts.map +0 -1
- package/dist/providers/google.js.map +0 -1
- package/dist/providers/xai.js.map +0 -1
- package/dist/secret-shapes-Cda65uDH.js.map +0 -1
- package/dist/skills-use-D68a1gyZ.js.map +0 -1
- package/dist/system-freeze-DXvJpveP.js.map +0 -1
- package/dist/tools-9Dpm8F-f.js.map +0 -1
- package/dist/turn-operations-CIFoOebZ.d.ts.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"openai-dTmPxM6T.js","names":["getModel","catalogLookup","streamOpenAIResponses","streamOpenAICodexResponses","stream"],"sources":["../src/providers/openai-decisions.ts","../src/providers/openai.ts"],"sourcesContent":["/**\n * OpenAI Decisions (`POST https://api.openai.com/v1/decisions`).\n *\n * Needs a standard platform API key (`sk-…`): Codex OAuth tokens are not\n * valid bearers for `api.openai.com`, so without one the capability reports\n * itself unavailable and no request is sent.\n *\n * Wire shape vs canonical:\n * - `input` is a string or one user message of `input_text` / `input_image`\n * (inline base64 data URLs) parts; JSON input is sent as pretty-printed text.\n * - questions are an array with a `name`; choices are `[{ value, description }]`,\n * score levels `[{ label, description }]`; predicates take no criteria, so\n * they are folded into the instructions.\n * - answers come back as an array; probabilities as arrays of `{ value, probability }`.\n */\n\nimport type { ProviderDecisionAvailability, ProviderDecisionRequest, ProviderDecisionResponse, ProviderDecisions } from '.'\nimport type { DecisionAnswer, DecisionInput, DecisionQuestion } from '../decisions/types'\nimport { DecisionHttpError, DecisionInvalidResponseError, DecisionUnavailableError, DecisionUnsupportedError } from '../decisions/errors'\nimport { isPromptParts, scoreLevelDescription, scoreLevelLabel } from '../decisions/wire'\n\n/** Endpoint of OpenAI Decisions. */\nexport const OPENAI_DECISIONS_URL = 'https://api.openai.com/v1/decisions'\n/** Decision models OpenAI is known to serve. The first is the default. */\nexport const OPENAI_DECISION_MODELS = ['gpt-6-luna'] as const\n\n/** USD per 1M input tokens; decisions bill input only. */\nconst INPUT_PRICE_PER_MTOK: Readonly<Record<string, number>> = {\n 'gpt-6-luna': 0.10,\n}\n\n/** Reason reported when no platform API key is available. */\nexport const OPENAI_DECISIONS_KEY_REQUIRED = 'OpenAI decisions require a platform API key (sk-…); Codex OAuth tokens are not accepted'\n\nfunction toWireInput(input: DecisionInput): unknown {\n if (typeof input === 'string')\n return input\n if (!isPromptParts(input))\n return JSON.stringify(input, null, 2)\n const content = input.map((part) => {\n if (part.type === 'text')\n return { type: 'input_text', text: part.text }\n if (part.type === 'image')\n return { type: 'input_image', image_url: `data:${part.mediaType};base64,${part.data}` }\n if (part.type === 'document' && part.encoding === 'text')\n return { type: 'input_text', text: part.data }\n throw new DecisionUnsupportedError(`OpenAI decisions accept text and images only (got a ${part.type} part)`)\n })\n return [{ role: 'user', content }]\n}\n\nfunction toWireQuestion(name: string, q: DecisionQuestion): Record<string, unknown> {\n switch (q.type) {\n case 'predicate':\n return {\n type: 'predicate',\n name,\n instructions: q.criteria ? `${q.instructions}\\n\\nTrue when: ${q.criteria.true}\\nFalse when: ${q.criteria.false}` : q.instructions,\n }\n case 'choice':\n return {\n type: 'choice',\n name,\n instructions: q.instructions,\n choices: Object.entries(q.choices).map(([value, description]) => ({ value, ...(description ? { description } : {}) })),\n }\n case 'score':\n return {\n type: 'score',\n name,\n instructions: q.instructions,\n levels: q.levels.map((level) => {\n const description = scoreLevelDescription(level)\n return { label: scoreLevelLabel(level), ...(description ? { description } : {}) }\n }),\n }\n }\n}\n\nfunction num(v: unknown): number | undefined {\n return typeof v === 'number' && Number.isFinite(v) ? v : undefined\n}\n\nfunction probabilityEntries(v: unknown): Array<{ value: unknown, label: unknown, probability: number }> | undefined {\n if (!Array.isArray(v))\n return undefined\n const out: Array<{ value: unknown, label: unknown, probability: number }> = []\n for (const e of v) {\n const p = e && typeof e === 'object' ? num((e as { probability?: unknown }).probability) : undefined\n if (p !== undefined)\n out.push({ value: (e as { value?: unknown }).value, label: (e as { label?: unknown }).label, probability: p })\n }\n return out\n}\n\nfunction fromWireAnswer(raw: Record<string, unknown>, question: DecisionQuestion | undefined): DecisionAnswer {\n const confidence = num(raw.confidence)\n switch (raw.type) {\n case 'predicate':\n return { type: 'predicate', probability: num(raw.probability) ?? Number.NaN }\n case 'choice': {\n const entries = probabilityEntries(raw.probabilities)\n const probabilities = entries ? Object.fromEntries(entries.map(e => [String(e.value), e.probability])) : undefined\n return {\n type: 'choice',\n choice: String(raw.choice),\n ...(probabilities ? { probabilities } : {}),\n ...(confidence !== undefined ? { confidence } : {}),\n }\n }\n case 'score': {\n const entries = probabilityEntries(raw.probabilities)\n const labels = question?.type === 'score' ? question.levels.map(scoreLevelLabel) : undefined\n const levels = labels?.length ?? entries?.length ?? 0\n // Levels go out by label; an entry may come back keyed by index or by label.\n const levelIndex = (e: { value: unknown, label: unknown }): number => {\n if (typeof e.value === 'number')\n return e.value\n for (const key of [e.label, e.value]) {\n const i = typeof key === 'string' && labels ? labels.indexOf(key) : -1\n if (i >= 0)\n return i\n }\n return Number(e.value)\n }\n const probabilities = entries\n ? Array.from({ length: levels }, (_, i) => entries.find(e => levelIndex(e) === i)?.probability ?? 0)\n : undefined\n return {\n type: 'score',\n score: num(raw.score) ?? Number.NaN,\n ...(probabilities ? { probabilities } : {}),\n ...(confidence !== undefined ? { confidence } : {}),\n }\n }\n case 'refusal': {\n const message = typeof raw.refusal === 'string' ? raw.refusal : typeof raw.message === 'string' ? raw.message : undefined\n return { type: 'refusal', ...(message ? { message } : {}) }\n }\n default:\n throw new DecisionInvalidResponseError(`answer has unknown type \"${String(raw.type)}\"`)\n }\n}\n\nasync function errorMessage(res: Response): Promise<string> {\n const text = await res.text().catch(() => '')\n try {\n const json = JSON.parse(text) as { error?: { message?: unknown } }\n if (typeof json.error?.message === 'string')\n return json.error.message\n }\n catch {}\n return text.slice(0, 500) || `HTTP ${res.status}`\n}\n\n/** A standard platform key usable on api.openai.com, or `null`. */\nexport function pickOpenAIPlatformKey(candidates: ReadonlyArray<string | undefined>): string | null {\n for (const key of candidates) {\n if (typeof key === 'string' && key.startsWith('sk-') && !key.startsWith('sk-ant-'))\n return key\n }\n return null\n}\n\n/**\n * The native Decisions endpoint of OpenAI as a {@link ProviderDecisions}.\n * Unavailable while `resolveKey` returns `null`. Cost is estimated from input tokens only.\n *\n * @param options - Key resolver, headers and test overrides.\n * @param options.resolveKey - Returns the platform key, or `null` when none is available. Called on every request.\n * @param options.headers - Extra request headers.\n * @param options.url - Endpoint override, for tests.\n * @param options.fetch - Fetch override, for tests.\n */\nexport function openaiDecisions(options: {\n /** Resolved at call time so env/credential changes are picked up. */\n resolveKey: () => string | null\n headers?: Record<string, string>\n url?: string\n fetch?: typeof fetch\n}): ProviderDecisions {\n const doFetch = options.fetch ?? fetch\n return {\n defaultModel: OPENAI_DECISION_MODELS[0],\n models: OPENAI_DECISION_MODELS,\n availability: (): ProviderDecisionAvailability => options.resolveKey()\n ? { available: true }\n : { available: false, reason: OPENAI_DECISIONS_KEY_REQUIRED },\n async decide(request: ProviderDecisionRequest, signal: AbortSignal): Promise<ProviderDecisionResponse> {\n const key = options.resolveKey()\n if (!key)\n throw new DecisionUnavailableError(OPENAI_DECISIONS_KEY_REQUIRED)\n const body = {\n model: request.model,\n input: toWireInput(request.input),\n questions: Object.entries(request.questions).map(([name, q]) => toWireQuestion(name, q)),\n }\n const res = await doFetch(options.url ?? OPENAI_DECISIONS_URL, {\n method: 'POST',\n headers: { ...options.headers, 'authorization': `Bearer ${key}`, 'content-type': 'application/json' },\n body: JSON.stringify(body),\n signal,\n })\n if (!res.ok)\n throw new DecisionHttpError(res.status, await errorMessage(res))\n let json: Record<string, unknown>\n try {\n json = await res.json() as Record<string, unknown>\n }\n catch {\n throw new DecisionInvalidResponseError('response is not JSON')\n }\n if (!Array.isArray(json.answers))\n throw new DecisionInvalidResponseError('response has no answers array')\n const names = Object.keys(request.questions)\n const answers: Record<string, DecisionAnswer> = {}\n json.answers.forEach((raw: unknown, i: number) => {\n if (!raw || typeof raw !== 'object')\n throw new DecisionInvalidResponseError(`answer ${i} is not an object`)\n const a = raw as Record<string, unknown>\n // Names are echoed back; fall back to position for an answer without one.\n const name = typeof a.name === 'string' ? a.name : names[i]\n if (name)\n answers[name] = fromWireAnswer(a, request.questions[name])\n })\n const model = typeof json.model === 'string' ? json.model : request.model\n const usage = (json.usage ?? {}) as Record<string, unknown>\n const input = num(usage.input_tokens) ?? num(usage.prompt_tokens) ?? 0\n const output = num(usage.output_tokens) ?? num(usage.completion_tokens) ?? 0\n const price = INPUT_PRICE_PER_MTOK[request.model] ?? INPUT_PRICE_PER_MTOK[model]\n return {\n answers,\n usage: { input, output, ...(price !== undefined ? { cost: (input * price) / 1_000_000 } : {}) },\n model,\n ...(typeof json.id === 'string' ? { id: json.id } : {}),\n }\n },\n }\n}\n","import type {\n AssistantMessage as PiAssistantMessage,\n Context as PiContext,\n JsonObject as PiJsonObject,\n Message as PiMessage,\n Model as PiModel,\n Tool as PiTool,\n Usage as PiUsage,\n} from '@earendil-works/pi-ai'\nimport type { Provider, StreamCallbacks, StreamOptions, ToolSpec, TurnResult } from '.'\nimport type { ClassifiedError } from '../errors'\nimport type { SessionContentBlock, SessionMessage, ToolResultDocumentContent, TurnFinishReason, TurnUsage } from '../types'\nimport type { ModelCatalog } from './model-catalog'\nimport type { OAuthParams } from './oauth'\nimport { normalizeContext } from '@earendil-works/pi-ai'\nimport { stream as streamOpenAICodexResponses } from '@earendil-works/pi-ai/api/openai-codex-responses'\nimport { stream as streamOpenAIResponses } from '@earendil-works/pi-ai/api/openai-responses'\nimport { getBuiltinModel as getModel } from '@earendil-works/pi-ai/providers/all'\nimport { announcedResetMs, classifyErrorPrelude, classifyProviderLimit, isRetryableHttpStatus, matchesContextExceeded, matchesToolPairingError, providerLimitReason } from '../errors'\nimport { unsupportedMediaError } from '../prompt'\nimport { reasoningWireAction, SYNTHETIC_TOOL_RESULT_PLACEHOLDER } from '../session/messages'\nimport { systemNotesAsText } from '../system-notes'\nimport { renderSystemForWire } from '../system-prompt'\nimport { assertResolvedMediaBlock, documentBlockMarker } from '../types'\nimport { fillEstimatedCost } from './cost'\n// `lookupModel` is aliased: that name is already the pi-ai registry getter below.\nimport { aliasCatalogProviders, lookupModel as catalogLookup, mergeCatalogEntry } from './model-catalog'\nimport { extractRuntimeCredentials, resolveOAuthApiKey } from './oauth'\nimport {\n assistantMessage,\n toolResultsMessage,\n userMessage,\n} from './openai-compat'\nimport { openaiDecisions, pickOpenAIPlatformKey } from './openai-decisions'\nimport { sanitizeToolSpecs } from './schema-sanitize'\nimport { createToolNameBoundary } from './tool-name-boundary'\n\nconst PROVIDER_ID = 'openai-codex'\n/**\n * pi-ai registry id for the standard platform API (`api.openai.com`).\n * The provider auto-detects the backend per stream from the credential\n * shape: a Codex OAuth JWT (`eyJ…`) streams via the ChatGPT Codex backend,\n * a platform API key (`sk-…`) via the standard Responses API. Same model\n * ids, same event contract — only the wire endpoint and billing differ.\n */\nconst PLATFORM_PROVIDER_ID = 'openai'\nconst DEFAULT_MODEL = 'gpt-6-astra'\n\n// Metadata aliases for model ids OpenAI publishes as shorthand (e.g. `gpt-5.6`\n// → the Sol flagship). Used ONLY to resolve extra-model metadata (cost,\n// context window, output ceiling); the requested id is preserved on the wire,\n// which OpenAI accepts. Mirrors `openaiDescriptor.modelAliases` in the chat\n// layer (`src/chat/providers.ts`) — the provider layer can't import that\n// descriptor without a layering cycle. Keep the two in sync.\nconst MODEL_ALIASES: Readonly<Record<string, string>> = {\n 'gpt-5.6': 'gpt-5.6-sol',\n}\n\ntype CodexModel = PiModel<'openai-codex-responses'>\ntype PlatformModel = PiModel<'openai-responses'>\n\n/** Options for {@link openai}: an API key or ChatGPT OAuth credentials, plus model and request settings. */\nexport interface OpenAIParams extends OAuthParams {\n /** ChatGPT account id sent with runtime OAuth credentials. Normally derived from the access token. */\n accountId?: string\n /**\n * Model used when a request does not set one.\n * @default 'gpt-6-astra'\n */\n defaultModel?: string\n /** Transport for the Codex backend: `sse`, `websocket` or `auto`. Ignored for platform API keys. */\n transport?: 'sse' | 'websocket' | 'auto'\n /**\n * Extra HTTP headers merged into every request (the streaming Responses call\n * and the token-count endpoint). Use for routing/attribution headers a proxy\n * in front of the OpenAI Codex endpoint consumes. Merged with provider\n * defaults; pi-ai lets these override defaults, so avoid `authorization` /\n * `content-type` unless you intend to replace them.\n */\n extraHeaders?: Record<string, string>\n}\n\n// pi-ai's `getModel` is typed for `KnownProvider` × `keyof models[P]`;\n// we look up by free-form `modelId` (the registry holds string ids at\n// runtime) and let pi-ai's miss-throw fall through via the wider lookup.\nconst lookupModel = getModel as (provider: string, modelId: string) => CodexModel | undefined\n\nfunction resolveModel(\n modelId: string,\n providerId: string = PROVIDER_ID,\n catalog?: ModelCatalog,\n): CodexModel {\n // A catalog entry overlays whatever the registry resolves below (including\n // the alias and default-model paths), so an override fixes metadata without\n // having to restate the whole model record.\n const entry = catalogLookup(providerId, modelId, catalog)\n const model = lookupModel(providerId, modelId)\n if (model)\n return mergeCatalogEntry(model, entry)\n\n // Shorthand aliases (`gpt-5.6` → `gpt-5.6-sol`): use the canonical\n // registry entry's metadata (cost, context window, output ceiling) while\n // keeping the requested id on the wire — OpenAI accepts the shorthand,\n // and pi-ai's usage accounting must bill at the real rates rather than\n // the default-model fallback's.\n const aliasId = MODEL_ALIASES[modelId]\n const aliased = aliasId ? lookupModel(providerId, aliasId) : undefined\n if (aliased)\n return mergeCatalogEntry({ ...aliased, id: modelId }, entry)\n\n // Registry miss with a catalog entry: the entry is all we know, so build the\n // record from the default model's shape and let the entry override. Without\n // one this stays the \"unknown id, default metadata\" fallback.\n const fallback = lookupModel(providerId, DEFAULT_MODEL)\n if (!fallback)\n throw new Error(`OpenAI model registry (${providerId}) is missing the default model: ${DEFAULT_MODEL}`)\n\n return mergeCatalogEntry({ ...fallback, id: modelId, name: modelId }, entry)\n}\n\nfunction emptyUsage(): PiUsage {\n return {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n totalTokens: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n }\n}\n\nfunction formatTools(tools: ToolSpec[]): PiTool[] {\n // Codex's Responses API runs the same schema validator as the OpenAI\n // Chat Completions endpoint — apply the same sanitisation pass so MCP\n // tools with non-standard root shapes don't 400 here either.\n const sanitized = sanitizeToolSpecs(tools, { profile: 'openai' })\n // `?? ''`: strict validators (and anthropic/openai-format gateways) treat\n // `description` as a required string; MCP tools routinely omit it.\n return sanitized.map(t => ({\n name: t.name,\n description: t.description ?? '',\n parameters: t.inputSchema as PiTool['parameters'],\n }))\n}\n\nfunction documentMarker(doc: ToolResultDocumentContent): string {\n return documentBlockMarker(doc, 'document omitted')\n}\n\nfunction piToolResultMessage(\n result: Extract<SessionContentBlock, { type: 'tool_result' }>,\n toolName = '',\n): PiMessage {\n // pi-ai's ToolResultMessage natively accepts (TextContent | ImageContent)[].\n // Map zidane's canonical union directly — no flattening needed.\n const content = typeof result.output === 'string'\n ? [{ type: 'text' as const, text: result.output }]\n : result.output.map((block) => {\n if (block.type === 'image') {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'image' as const, data: block.data, mimeType: block.mediaType }\n }\n if (block.type === 'audio')\n throw unsupportedMediaError('audio', 'openai')\n if (block.type === 'video')\n throw unsupportedMediaError('video', 'openai')\n if (block.type === 'document') {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'text' as const, text: documentMarker(block) }\n }\n return { type: 'text' as const, text: block.text }\n })\n\n return {\n role: 'toolResult',\n toolCallId: result.callId,\n toolName,\n content,\n isError: result.isError ?? false,\n timestamp: Date.now(),\n }\n}\n\nfunction piUserMessage(\n content: SessionContentBlock[],\n): PiMessage | null {\n for (const b of content) {\n if (b.type === 'audio')\n throw unsupportedMediaError('audio', 'openai')\n if (b.type === 'video')\n throw unsupportedMediaError('video', 'openai')\n }\n\n const textBlocks = content.filter(b => b.type === 'text')\n const imageBlocks = content.filter(b => b.type === 'image')\n const documentBlocks = content.filter(b => b.type === 'document')\n\n if (imageBlocks.length === 0 && textBlocks.length === 0 && documentBlocks.length === 0)\n return null\n\n if (imageBlocks.length === 0 && documentBlocks.length === 0 && textBlocks.length === 1)\n return { role: 'user', content: textBlocks[0].text, timestamp: Date.now() }\n\n return {\n role: 'user',\n content: [\n ...imageBlocks.map((img) => {\n assertResolvedMediaBlock(img, 'OpenAI wire messages')\n return { type: 'image' as const, data: img.data, mimeType: img.mediaType }\n }),\n // NOTE: OpenAI's API natively accepts PDFs (Responses `input_file` /\n // Chat Completions `file`), but pi-ai's message content union is\n // text|image only — it has no file content type — so documents degrade to\n // a marker here. To forward PDFs to OpenAI, route via:\n // openaiCompat({ name: 'openai', apiKey, baseURL: 'https://api.openai.com/v1',\n // capabilities: { documents: true } })\n // which emits the `{type:'file'}` Chat Completions part directly. (That\n // path accepts application/pdf only; spreadsheets/.docx need the\n // Responses API, which would require an input_file content type in pi-ai.)\n ...documentBlocks.map((block) => {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'text' as const, text: documentMarker(block) }\n }),\n ...textBlocks.map(block => ({ type: 'text' as const, text: block.text })),\n ],\n timestamp: Date.now(),\n }\n}\n\nfunction piAssistantMessage(\n content: SessionContentBlock[],\n modelId: string,\n): PiAssistantMessage {\n const piContent: PiAssistantMessage['content'] = []\n for (const block of content) {\n if (block.type === 'text') {\n piContent.push({ type: 'text', text: block.text })\n }\n else if (block.type === 'thinking') {\n // Shared cross-provider policy (`reasoningWireAction`): drop blocks\n // minted by Anthropic (their HMAC is not valid `encrypted_content`),\n // strip the signature from untagged legacy blocks (no signature-400\n // recovery exists on this path), forward openai-tagged ones intact.\n const action = reasoningWireAction(block, 'openai')\n if (action === 'drop')\n continue\n piContent.push({\n type: 'thinking',\n thinking: block.text,\n ...(action === 'keep' && block.signature !== undefined ? { thinkingSignature: block.signature } : {}),\n })\n }\n else if (block.type === 'tool_call') {\n // `input` is parsed wire JSON; pi-ai types it as `JsonObject`.\n piContent.push({ type: 'toolCall', id: block.id, name: block.name, arguments: block.input as PiJsonObject })\n }\n // `redacted_thinking` (Anthropic-only) and `provider_reasoning` (provider-\n // bound reasoning state) are intentionally dropped — Codex Responses\n // doesn't accept them.\n }\n\n return {\n role: 'assistant',\n content: piContent,\n api: 'openai-codex-responses',\n provider: PROVIDER_ID,\n model: modelId,\n usage: emptyUsage(),\n stopReason: 'stop',\n timestamp: Date.now(),\n }\n}\n\n/**\n * Converts session messages to pi-ai messages for the Responses wire, pairing tool calls with their results.\n *\n * @param messages - Session messages to convert.\n * @param modelId - Model id stamped on converted assistant messages.\n */\nexport function toPiMessages(messages: SessionMessage[], modelId: string): PiMessage[] {\n // System notes have no native slot on this wire: send them as `<system-reminder>` text.\n messages = systemNotesAsText(messages)\n const out: PiMessage[] = []\n\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]\n const toolCalls = msg.content.filter((b): b is Extract<SessionContentBlock, { type: 'tool_call' }> => b.type === 'tool_call')\n\n if (msg.role === 'assistant' && toolCalls.length > 0) {\n const next = messages[i + 1]\n const nextToolResults = next?.role === 'user'\n ? next.content.filter((b): b is Extract<SessionContentBlock, { type: 'tool_result' }> => b.type === 'tool_result')\n : []\n const resultById = new Map(nextToolResults.map(result => [result.callId, result]))\n\n let assistantContent: SessionContentBlock[] = []\n for (const block of msg.content) {\n assistantContent.push(block)\n if (block.type !== 'tool_call')\n continue\n\n out.push(piAssistantMessage(assistantContent, modelId))\n assistantContent = []\n\n const result = resultById.get(block.id)\n if (result) {\n out.push(piToolResultMessage(result, block.name))\n }\n else {\n out.push(piToolResultMessage({\n type: 'tool_result',\n callId: block.id,\n output: SYNTHETIC_TOOL_RESULT_PLACEHOLDER,\n isError: true,\n }, block.name))\n }\n }\n if (assistantContent.length > 0)\n out.push(piAssistantMessage(assistantContent, modelId))\n\n if (next?.role === 'user') {\n const remainingUserContent = next.content.filter((block) => {\n if (block.type !== 'tool_result')\n return true\n // Orphan/duplicate tool results should already be removed by the\n // canonical repair pass. If one reaches this adapter, do not send it\n // as an unpaired provider message.\n return false\n })\n const userMessage = piUserMessage(remainingUserContent)\n if (userMessage)\n out.push(userMessage)\n i++\n }\n continue\n }\n\n const toolResults = msg.content.filter(b => b.type === 'tool_result')\n if (toolResults.length > 0) {\n const userMsg = msg.role === 'user'\n ? piUserMessage(msg.content.filter(b => b.type !== 'tool_result'))\n : null\n if (userMsg)\n out.push(userMsg)\n continue\n }\n\n if (msg.role === 'user') {\n const userMsg = piUserMessage(msg.content)\n if (userMsg)\n out.push(userMsg)\n continue\n }\n\n out.push(piAssistantMessage(msg.content, modelId))\n }\n\n return out\n}\n\n/**\n * Map pi-ai's `StopReason` to the zidane `TurnFinishReason` union — the same\n * native-stop-reason fidelity anthropic's `mapStopReason` / openai-compat's\n * `mapOAIFinishReason` provide. `length` (max-token truncation) maps to\n * `'length'`, not to a clean `stop`. `hasToolCalls` is the fallback for\n * messages whose stop reason is missing or doesn't carry the tool-call signal.\n *\n * @param stopReason - pi-ai stop reason, when present.\n * @param hasToolCalls - Whether the turn contains tool calls.\n */\nexport function mapCodexStopReason(stopReason: string | undefined, hasToolCalls: boolean): TurnFinishReason {\n switch (stopReason) {\n case 'toolUse':\n return 'tool-calls'\n case 'length':\n return 'length'\n case 'error':\n return 'error'\n case 'stop':\n return hasToolCalls ? 'tool-calls' : 'stop'\n case 'aborted':\n return 'other'\n default:\n return hasToolCalls ? 'tool-calls' : 'stop'\n }\n}\n\nfunction fromPiAssistantMessage(message: PiAssistantMessage): SessionMessage {\n const content: SessionContentBlock[] = []\n\n for (const block of message.content) {\n if (block.type === 'text') {\n content.push({ type: 'text', text: block.text })\n }\n else if (block.type === 'thinking') {\n const out: Extract<SessionContentBlock, { type: 'thinking' }> = {\n type: 'thinking',\n text: block.thinking,\n }\n if (typeof block.thinkingSignature === 'string') {\n out.signature = block.thinkingSignature\n out.signatureProducer = 'openai'\n }\n content.push(out)\n }\n else if (block.type === 'toolCall') {\n content.push({ type: 'tool_call', id: block.id, name: block.name, input: block.arguments })\n }\n }\n\n return { role: 'assistant', content }\n}\n\nfunction extractToolCalls(message: PiAssistantMessage) {\n return message.content\n .filter(block => block.type === 'toolCall')\n .map(block => ({\n id: block.id,\n name: block.name,\n input: block.arguments as Record<string, unknown>,\n }))\n}\n\nfunction extractText(message: PiAssistantMessage): string {\n return message.content\n .filter((block): block is Extract<PiAssistantMessage['content'][number], { type: 'text' }> => block.type === 'text')\n .map(block => block.text)\n .join('')\n}\n\nfunction toTurnUsage(usage: PiUsage, finishReason: TurnFinishReason | undefined, modelId: string, catalog?: ModelCatalog): Promise<TurnUsage> {\n return fillEstimatedCost({\n input: usage.input,\n output: usage.output,\n cacheRead: usage.cacheRead || undefined,\n cacheCreation: usage.cacheWrite || undefined,\n cost: usage.cost.total || undefined,\n ...(finishReason ? { finishReason } : {}),\n modelId,\n }, 'openai', undefined, catalog)\n}\n\n/**\n * Transient pi-ai error patterns worth a loop-level retry. pi-ai's Codex stream\n * retries pre-stream 429 / 5xx only when `maxRetries` is set (default 0, see\n * `openai-codex-responses.js`), and this provider does not set it. So the\n * loop-level retry, with its longer backoff, is the retry layer for capacity\n * events, plus mid-stream emissions (pi-ai surfaces those as plain `Error`s\n * with no status).\n *\n * Mirrors pi-ai's own `isRetryableError` regex so both layers recognize the\n * same failure modes.\n */\nconst TRANSIENT_OPENAI_MESSAGE_RE = /rate.?limit|overloaded|service.?unavailable|upstream.?connect|connection.?refused|gateway.?time.?out|temporarily.?unavailable/i\n\n/** Numeric HTTP status codes pi-ai sometimes attaches when bubbling structured errors. */\nfunction isRetryableStatusCode(err: object): boolean {\n const status = (err as { status?: unknown }).status\n if (typeof status !== 'number')\n return false\n return isRetryableHttpStatus(status)\n}\n\n/**\n * Classify an OpenAI Codex error. pi-ai surfaces errors either as thrown `Error`s\n * (wrapping `event.error.errorMessage`) or via stream event types.\n *\n * The retryable hint is set on a transient failure — pattern-matched against\n * `message` since pi-ai strips structured fields on plain-Error throws. Set `behavior.retry.maxAttempts: 1`\n * to disable the loop-level retry.\n *\n * @param err - Error thrown by pi-ai or the HTTP layer.\n */\nexport function classifyOpenAIError(err: unknown): ClassifiedError | null {\n const prelude = classifyErrorPrelude(err)\n if (prelude === 'not-object')\n return null\n if (prelude === 'aborted')\n return { kind: 'aborted' }\n\n const anyErr = err as { name?: string, message?: string, code?: string, type?: string }\n\n const message = anyErr.message ?? ''\n const code = anyErr.code ?? anyErr.type\n\n if (code === 'context_length_exceeded' || matchesContextExceeded(message)) {\n return {\n kind: 'context_exceeded',\n providerCode: code ?? 'context_length_exceeded',\n message,\n }\n }\n\n if (matchesToolPairingError(message)) {\n return {\n kind: 'tool_pairing_corruption',\n providerCode: code ?? 'invalid_request_error',\n message,\n }\n }\n\n // pi-ai wraps API errors in generic `Error` — treat as provider_error when we have a message.\n if (message.length > 0) {\n const retryable = isRetryableStatusCode(anyErr) || TRANSIENT_OPENAI_MESSAGE_RE.test(message)\n const status = (anyErr as { status?: unknown }).status\n const reason = providerLimitReason({ status: typeof status === 'number' ? status : undefined, code, message })\n if (reason) {\n // Codex OAuth runs on the user's ChatGPT plan, and pi-ai's message says so.\n const retryAfterMs = announcedResetMs(message)\n return classifyProviderLimit(\n { reason, provider: /ChatGPT/.test(message) ? 'ChatGPT' : 'OpenAI', ...(retryAfterMs !== undefined ? { retryAfterMs } : {}) },\n { providerCode: code, retryable },\n )\n }\n return {\n kind: 'provider_error',\n providerCode: code,\n message,\n ...(retryable ? { retryable: true } : {}),\n }\n }\n\n return null\n}\n\n/**\n * OpenAI's org-verification rejection for `reasoning.summary` — e.g.\n * \"Your organization must be verified to generate reasoning summaries\".\n * Matched loosely on the two load-bearing words so minor copy changes\n * don't defeat the platform-branch fallback.\n */\nfunction isReasoningSummaryVerificationError(err: unknown): boolean {\n if (!(err instanceof Error))\n return false\n return /reasoning summar/i.test(err.message) && /verif/i.test(err.message)\n}\n\n/**\n * A standard OpenAI API key usable against `api.openai.com` (for the exact\n * token-count endpoint), or `null` when only a Codex-OAuth credential is\n * available. Codex OAuth access tokens are JWTs (`eyJ…`) and are NOT valid\n * bearers for the standard API; a real key looks like `sk-…` (but not the\n * Anthropic `sk-ant-…` form). Checks `params.apiKey` then `OPENAI_API_KEY`.\n */\nfunction pickStandardOpenAIKey(params?: OpenAIParams): string | null {\n const candidates = [params?.apiKey, process.env.OPENAI_API_KEY]\n for (const key of candidates) {\n if (typeof key === 'string' && key.startsWith('sk-') && !key.startsWith('sk-ant-'))\n return key\n }\n return null\n}\n\n/**\n * Convert canonical {@link SessionMessage}s to OpenAI Responses-API `input`\n * items for the token-count endpoint. Only the text-bearing shape is needed\n * here (the count path sends a tiny dummy message); images/tool-results are\n * down-converted to text so the count never throws on an exotic block.\n */\nfunction toResponsesInput(messages: SessionMessage[]): unknown[] {\n return systemNotesAsText(messages).map((msg) => {\n const text = msg.content\n .map(b => (b.type === 'text' ? b.text : ''))\n .filter(Boolean)\n .join('\\n')\n const part = msg.role === 'assistant' ? 'output_text' : 'input_text'\n return { role: msg.role === 'assistant' ? 'assistant' : 'user', content: [{ type: part, text }] }\n })\n}\n\n/** Convert pi-ai `PiTool` specs to Responses-API function tools. */\nfunction toResponsesTools(tools: unknown[]): unknown[] {\n return tools.map((t) => {\n const tool = t as { name?: string, description?: string, parameters?: unknown }\n return {\n type: 'function',\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters,\n }\n })\n}\n\nfunction applyPayloadOverrides(payload: unknown, options: StreamOptions, toWireToolName: (name: string) => string = name => name): unknown {\n const body = payload as Record<string, unknown>\n\n if (options.toolChoice) {\n if (options.toolChoice.type === 'tool' && options.toolChoice.name)\n body.tool_choice = { type: 'function', name: toWireToolName(options.toolChoice.name) }\n else if (options.toolChoice.type === 'required')\n body.tool_choice = 'required'\n else\n body.tool_choice = 'auto'\n }\n\n return body\n}\n\n/**\n * Creates the OpenAI provider on the Responses API.\n * Picks the backend per request from the credential: a Codex OAuth token streams through the ChatGPT Codex backend, a platform API key (`sk-…`) through the standard Responses API.\n * A run reads `params.apiKey`, then `OPENAI_CODEX_API_KEY`, then the stored OAuth credentials. `OPENAI_API_KEY` is read only by the exact token count (`countTokens`) and by the decisions helper, together with `params.apiKey` and `OPENAI_CODEX_API_KEY`.\n *\n * @param params - API key or OAuth credentials, account id, default model, transport and extra headers.\n *\n * @example\n * ```ts\n * import { createAgent } from 'zidane'\n * import { openai } from 'zidane/providers/openai'\n *\n * const agent = createAgent({\n * provider: openai({ apiKey: process.env.OPENAI_API_KEY }),\n * })\n * await agent.run({ prompt: 'Say hello.' })\n * ```\n */\nexport function openai(params?: OpenAIParams): Provider {\n const defaultModel = params?.defaultModel || DEFAULT_MODEL\n const baseCredentials = extractRuntimeCredentials(params)\n let runtimeCredentials = baseCredentials\n ? { ...baseCredentials, ...(params?.accountId ? { accountId: params.accountId } : {}) }\n : undefined\n\n return {\n name: 'openai',\n meta: {\n defaultModel,\n isOAuth: true,\n capabilities: {\n vision: true,\n imageInToolResult: true,\n // pi-ai's Codex Responses wire has no audio/video input content type.\n audio: false,\n video: false,\n },\n },\n formatTools,\n userMessage,\n assistantMessage,\n toolResultsMessage,\n classifyError: classifyOpenAIError,\n // Decisions live on the standard platform API, so only a platform key\n // works: explicit `apiKey`, `OPENAI_API_KEY`, or a platform key stored\n // under the Codex env slot (the chat host's API-key login writes there).\n decisions: openaiDecisions({\n resolveKey: () => pickOpenAIPlatformKey([params?.apiKey, process.env.OPENAI_API_KEY, process.env.OPENAI_CODEX_API_KEY]),\n ...(params?.extraHeaders ? { headers: params.extraHeaders } : {}),\n }),\n\n async countTokens(payload, signal): Promise<number | null> {\n // The exact count endpoint (`POST /v1/responses/input_tokens`) lives on\n // the standard OpenAI API and needs a standard `OPENAI_API_KEY` bearer.\n // This provider authenticates via Codex OAuth against the Codex backend,\n // whose token is NOT valid for that endpoint — so we only attempt the\n // count when a standard key is present (env or params.apiKey that isn't\n // an OAuth/JWT token). Otherwise return null → heuristic fallback.\n const standardKey = pickStandardOpenAIKey(params)\n if (!standardKey)\n return null\n try {\n const tools = payload.tools as PiTool[]\n const nameBoundary = createToolNameBoundary(payload.messages, tools.map(tool => tool.name))\n const res = await fetch('https://api.openai.com/v1/responses/input_tokens', {\n method: 'POST',\n headers: {\n ...params?.extraHeaders,\n 'authorization': `Bearer ${standardKey}`,\n 'content-type': 'application/json',\n },\n // The Responses `input_tokens` endpoint takes the same shape as\n // `responses.create`: `instructions` (system), `input` (Responses\n // input items — NOT pi-ai messages), and function-shaped `tools`.\n body: JSON.stringify({\n model: payload.model || defaultModel,\n instructions: renderSystemForWire(payload.system),\n input: toResponsesInput(nameBoundary.messages),\n tools: toResponsesTools(tools.map(tool => ({ ...tool, name: nameBoundary.toWire(tool.name) }))),\n }),\n ...(signal ? { signal } : {}),\n })\n if (!res.ok)\n return null\n const json = (await res.json()) as { input_tokens?: unknown }\n return typeof json.input_tokens === 'number' ? json.input_tokens : null\n }\n catch {\n return null\n }\n },\n\n async stream(options: StreamOptions, callbacks: StreamCallbacks): Promise<TurnResult> {\n const modelId = options.model || defaultModel\n const apiKey = await resolveOAuthApiKey(\n {\n provider: 'openai',\n providerId: PROVIDER_ID,\n params: runtimeCredentials ? { ...params, ...runtimeCredentials } : params,\n envKey: 'OPENAI_CODEX_API_KEY',\n extraCredentialKeys: ['accountId'],\n missingError: 'No OpenAI Codex OAuth token found. Run `bun run auth --openai` first.',\n refreshError: reason => `OpenAI Codex OAuth token refresh failed. Run \\`bun run auth --openai\\` again. ${reason}`,\n },\n {\n ...callbacks,\n async onOAuthRefresh(ctx) {\n if (ctx.source === 'params') {\n runtimeCredentials = {\n access: ctx.credentials.access,\n refresh: ctx.credentials.refresh,\n expires: ctx.credentials.expires,\n ...(typeof ctx.credentials.accountId === 'string' ? { accountId: ctx.credentials.accountId } : {}),\n }\n }\n await callbacks.onOAuthRefresh?.(ctx)\n },\n },\n )\n // Backend auto-detection by credential shape. A Codex OAuth access\n // token is a JWT whose claims carry the `chatgpt_account_id` the Codex\n // backend requires per request; a standard `sk-…` platform key can\n // NEVER stream there (pi-ai fails with an opaque \"Failed to extract\n // accountId from token\") — but it's a first-class credential for the\n // standard Responses API, so route it there instead. Scoped to the\n // unambiguous `sk-` shape: exotic bearers (test harnesses, relays)\n // keep flowing to the Codex path untouched.\n const usePlatformApi = apiKey.startsWith('sk-')\n const model = resolveModel(modelId, usePlatformApi ? PLATFORM_PROVIDER_ID : PROVIDER_ID, options.modelCatalog)\n const tools = options.tools as PiTool[]\n const nameBoundary = createToolNameBoundary(options.messages, tools.map(tool => tool.name))\n // Codex's Responses API has no `cache_control` analogue, but the\n // system-prompt boundary marker is structural metadata that should\n // never reach the model. Strip it via `renderSystemForWire`; the\n // doctrine + env are collapsed into a single byte stream the model\n // sees as one logical prompt.\n // pi-ai's stream entry points take a `TranscriptContext`: the prompt\n // and tools folded into a leading system message. `normalizeContext` is\n // the only producer of that branded type.\n const rawContext: PiContext = {\n systemPrompt: renderSystemForWire(options.system),\n messages: toPiMessages(nameBoundary.messages, modelId),\n tools: tools.map(tool => ({ ...tool, name: nameBoundary.toWire(tool.name) })),\n }\n const context = normalizeContext(rawContext)\n // OpenAI's `reasoning_effort` accepts minimal/low/medium/high/xhigh, and\n // the GPT-5.6 line adds a native `max` tier. Clamp `max` to `xhigh` on\n // older models only; `'adaptive'` degrades to no reasoning rather than\n // forwarding an unknown value the API would reject.\n const supportsMaxEffort = modelId.startsWith('gpt-5.6')\n const reasoningLevel\n = options.thinking && options.thinking !== 'off' && options.thinking !== 'adaptive'\n ? options.thinking === 'max' && !supportsMaxEffort ? 'xhigh' : options.thinking\n : undefined\n // Options are shared verbatim across both backends — the platform\n // Responses API and the Codex bridge take the same reasoning / service\n // tier knobs; only the websocket `transport` toggle is Codex-specific.\n const makeStream = (reasoningSummary: 'auto' | undefined) => {\n const streamOptions = {\n apiKey,\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n signal: options.signal,\n reasoningEffort: reasoningLevel,\n reasoningSummary,\n ...(options.modelOptions?.fast ? { serviceTier: 'priority' as const } : {}),\n // pi-ai sends it as `prompt_cache_key` (and session headers on the\n // platform API, websocket reuse on Codex). Unset = no key.\n ...(options.sessionId ? { sessionId: options.sessionId } : {}),\n ...(params?.extraHeaders ? { headers: params.extraHeaders } : {}),\n // pi-ai types the payload as `unknown`; both backends send the\n // Responses-API body shape `applyPayloadOverrides` expects.\n onPayload: (payload: unknown) => applyPayloadOverrides(payload as Record<string, unknown>, options, nameBoundary.toWire),\n }\n return usePlatformApi\n ? streamOpenAIResponses(model as unknown as PlatformModel, context, streamOptions)\n : streamOpenAICodexResponses(model, context, { ...streamOptions, transport: params?.transport })\n }\n let stream = makeStream(reasoningLevel ? 'auto' : undefined)\n\n let finalMessage: PiAssistantMessage | undefined\n let text = ''\n let thinking = ''\n\n const consume = async (s: ReturnType<typeof makeStream>) => {\n for await (const event of s) {\n if (event.type === 'text_delta') {\n text += event.delta\n callbacks.onText(event.delta)\n }\n else if (event.type === 'thinking_delta') {\n thinking += event.delta\n callbacks.onThinking?.(event.delta)\n }\n else if (event.type === 'thinking_end') {\n const delta = event.content.startsWith(thinking)\n ? event.content.slice(thinking.length)\n : (thinking ? '' : event.content)\n if (delta) {\n thinking += delta\n callbacks.onThinking?.(delta)\n }\n }\n else if (event.type === 'toolcall_start' || event.type === 'toolcall_delta') {\n // Liveness only: a tool-only turn streams nothing else for the stall watchdog to see.\n callbacks.onToolCallDelta?.()\n }\n else if (event.type === 'done') {\n finalMessage = event.message\n }\n else if (event.type === 'error') {\n throw new Error(event.error.errorMessage || (usePlatformApi ? 'OpenAI API error' : 'OpenAI Codex API error'))\n }\n }\n }\n\n try {\n await consume(stream)\n }\n catch (err) {\n // The platform Responses API rejects reasoning summaries for\n // organizations that haven't completed verification (the Codex\n // backend has no such gate). That 400 fails request validation, so\n // nothing has streamed yet — retry once without the summary rather\n // than bricking every reasoning-enabled stream for those orgs.\n const nothingStreamed = text.length === 0 && thinking.length === 0 && finalMessage === undefined\n if (usePlatformApi && reasoningLevel && nothingStreamed && isReasoningSummaryVerificationError(err)) {\n stream = makeStream(undefined)\n await consume(stream)\n }\n else {\n throw err\n }\n }\n\n finalMessage ??= await stream.result()\n text ||= extractText(finalMessage)\n\n const toolCalls = extractToolCalls(finalMessage)\n .map(call => ({ ...call, name: nameBoundary.fromWire(call.name) }))\n const assistantTurn = fromPiAssistantMessage(finalMessage)\n assistantTurn.content = assistantTurn.content.map(block =>\n block.type === 'tool_call' ? { ...block, name: nameBoundary.fromWire(block.name) } : block,\n )\n const finishReason = mapCodexStopReason(finalMessage.stopReason, toolCalls.length > 0)\n // Metadata resolves under `openai-codex` (or `openai` on the platform\n // path) while cost estimation runs under `openai` — accept a catalog\n // entry keyed either way so one entry fixes both.\n const usage = await toTurnUsage(finalMessage.usage, finishReason, modelId, aliasCatalogProviders(\n options.modelCatalog,\n [usePlatformApi ? PLATFORM_PROVIDER_ID : PROVIDER_ID, PLATFORM_PROVIDER_ID],\n ))\n\n return {\n assistantMessage: assistantTurn,\n text,\n toolCalls,\n done: toolCalls.length === 0,\n usage,\n }\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"openrouter-CtZbQDa0.js","names":[],"sources":["../src/providers/openrouter-decisions.ts","../src/providers/openrouter.ts"],"sourcesContent":["/**\n * OpenRouter Decisions (`POST https://openrouter.ai/api/alpha/decisions`).\n *\n * Wire shape vs canonical:\n * - `state` carries the input (string or JSON); prompt parts are text-only here.\n * - questions are keyed by name; `predicate` is `noul` with `criteria: { true, false }`,\n * choices are a `criteria` map, score levels a `criteria` array.\n * - answers come back keyed by name; probabilities are maps (score: by level index).\n */\n\nimport type { ProviderDecisionRequest, ProviderDecisionResponse, ProviderDecisions } from '.'\nimport type { DecisionAnswer, DecisionInput, DecisionQuestion } from '../decisions/types'\nimport { DecisionHttpError, DecisionInvalidResponseError, DecisionUnsupportedError } from '../decisions/errors'\nimport { isPromptParts, scoreLevelDescription, scoreLevelLabel } from '../decisions/wire'\n\n/** Endpoint of OpenRouter Decisions. */\nexport const OPENROUTER_DECISIONS_URL = 'https://openrouter.ai/api/alpha/decisions'\n/** Decision models OpenRouter is known to serve. The first is the default. */\nexport const OPENROUTER_DECISION_MODELS = ['typesafe/jev-1.13'] as const\n\nfunction toState(input: DecisionInput): unknown {\n if (!isPromptParts(input))\n return input\n const texts: string[] = []\n for (const part of input) {\n if (part.type === 'text')\n texts.push(part.text)\n else if (part.type === 'document' && part.encoding === 'text')\n texts.push(part.data)\n else\n throw new DecisionUnsupportedError(`OpenRouter decisions accept text and JSON input only (got a ${part.type} part)`)\n }\n return texts.join('\\n\\n')\n}\n\nfunction toWireQuestion(q: DecisionQuestion): Record<string, unknown> {\n switch (q.type) {\n case 'predicate':\n return { type: 'noul', instructions: q.instructions, ...(q.criteria ? { criteria: { true: q.criteria.true, false: q.criteria.false } } : {}) }\n case 'choice':\n return { type: 'choice', instructions: q.instructions, criteria: { ...q.choices } }\n case 'score':\n return {\n type: 'score',\n instructions: q.instructions,\n criteria: q.levels.map((level) => {\n const description = scoreLevelDescription(level)\n return description ? `${scoreLevelLabel(level)}: ${description}` : scoreLevelLabel(level)\n }),\n }\n }\n}\n\nfunction num(v: unknown): number | undefined {\n return typeof v === 'number' && Number.isFinite(v) ? v : undefined\n}\n\nfunction numberMap(v: unknown): Record<string, number> | undefined {\n if (!v || typeof v !== 'object' || Array.isArray(v))\n return undefined\n const out: Record<string, number> = {}\n for (const [k, p] of Object.entries(v)) {\n const n = num(p)\n if (n !== undefined)\n out[k] = n\n }\n return out\n}\n\nfunction fromWireAnswer(name: string, raw: unknown, question: DecisionQuestion | undefined): DecisionAnswer {\n if (!raw || typeof raw !== 'object')\n throw new DecisionInvalidResponseError(`answer \"${name}\" is not an object`)\n const a = raw as Record<string, unknown>\n const confidence = num(a.confidence)\n switch (a.type) {\n case 'noul':\n return { type: 'predicate', probability: num(a.noul) ?? Number.NaN }\n case 'choice': {\n const probabilities = numberMap(a.probabilities)\n return {\n type: 'choice',\n choice: String(a.choice),\n ...(probabilities ? { probabilities } : {}),\n ...(confidence !== undefined ? { confidence } : {}),\n }\n }\n case 'score': {\n const map = numberMap(a.probabilities)\n const levels = question?.type === 'score' ? question.levels.length : map ? Object.keys(map).length : 0\n const probabilities = map ? Array.from({ length: levels }, (_, i) => map[String(i)] ?? 0) : undefined\n return {\n type: 'score',\n score: num(a.score) ?? Number.NaN,\n ...(probabilities ? { probabilities } : {}),\n ...(confidence !== undefined ? { confidence } : {}),\n }\n }\n case 'refusal':\n return { type: 'refusal', ...(typeof a.message === 'string' ? { message: a.message } : {}) }\n default:\n throw new DecisionInvalidResponseError(`answer \"${name}\" has unknown type \"${String(a.type)}\"`)\n }\n}\n\nasync function errorMessage(res: Response): Promise<string> {\n const text = await res.text().catch(() => '')\n try {\n const json = JSON.parse(text) as { error?: { message?: unknown } }\n if (typeof json.error?.message === 'string')\n return json.error.message\n }\n catch {}\n return text.slice(0, 500) || `HTTP ${res.status}`\n}\n\n/**\n * The native Decisions endpoint of OpenRouter as a {@link ProviderDecisions}.\n * Always available: the key is checked by the server, not locally.\n *\n * @param options - Key, headers and test overrides.\n * @param options.apiKey - OpenRouter API key, sent as a bearer token.\n * @param options.headers - Request headers, such as attribution headers.\n * @param options.url - Endpoint override, for tests.\n * @param options.fetch - Fetch override, for tests.\n */\nexport function openrouterDecisions(options: {\n apiKey: string\n headers: Record<string, string>\n url?: string\n fetch?: typeof fetch\n}): ProviderDecisions {\n const doFetch = options.fetch ?? fetch\n return {\n defaultModel: OPENROUTER_DECISION_MODELS[0],\n models: OPENROUTER_DECISION_MODELS,\n availability: () => ({ available: true }),\n async decide(request: ProviderDecisionRequest, signal: AbortSignal): Promise<ProviderDecisionResponse> {\n const body = {\n model: request.model,\n state: toState(request.input),\n questions: Object.fromEntries(Object.entries(request.questions).map(([name, q]) => [name, toWireQuestion(q)])),\n }\n const res = await doFetch(options.url ?? OPENROUTER_DECISIONS_URL, {\n method: 'POST',\n headers: { ...options.headers, 'authorization': `Bearer ${options.apiKey}`, 'content-type': 'application/json' },\n body: JSON.stringify(body),\n signal,\n })\n if (!res.ok)\n throw new DecisionHttpError(res.status, await errorMessage(res))\n let json: Record<string, unknown>\n try {\n json = await res.json() as Record<string, unknown>\n }\n catch {\n throw new DecisionInvalidResponseError('response is not JSON')\n }\n const rawAnswers = json.answers\n if (!rawAnswers || typeof rawAnswers !== 'object' || Array.isArray(rawAnswers))\n throw new DecisionInvalidResponseError('response has no answers object')\n const answers: Record<string, DecisionAnswer> = {}\n for (const [name, raw] of Object.entries(rawAnswers))\n answers[name] = fromWireAnswer(name, raw, request.questions[name])\n const usage = (json.usage ?? {}) as Record<string, unknown>\n const cost = num(usage.cost)\n return {\n answers,\n usage: { input: num(usage.input_tokens) ?? 0, output: num(usage.output_tokens) ?? 0, ...(cost !== undefined ? { cost } : {}) },\n model: typeof json.model === 'string' ? json.model : request.model,\n ...(typeof json.id === 'string' ? { id: json.id } : {}),\n }\n },\n }\n}\n","import type { Provider, ProviderCapabilities } from '.'\nimport type { PromptCacheKeyOption } from './prompt-cache-key'\nimport { openaiCompat } from './openai-compat'\nimport { openrouterDecisions } from './openrouter-decisions'\n\nconst BASE_URL = 'https://openrouter.ai/api/v1'\n/** Model the OpenRouter provider uses when none is configured. */\nexport const OPENROUTER_DEFAULT_MODEL = 'anthropic/claude-opus-5.5'\n\n// Hyphenated slugs (`-4-6`, `-5-1`) that persisted sessions may carry, mapped to\n// the dotted slugs OpenRouter serves (`.4.6`, `.5.1`). Normalized on the wire so\n// an old persisted id keeps streaming. Keep in sync with\n// `openrouterDescriptor.modelAliases` (chat layer) which mirrors this for\n// metadata lookups — the provider layer can't import the chat descriptor\n// without a layering cycle.\nconst MODEL_ALIASES: Readonly<Record<string, string>> = {\n 'anthropic/claude-sonnet-4-6': 'anthropic/claude-sonnet-4.6',\n 'anthropic/claude-fable-5-1': 'anthropic/claude-fable-5.1',\n}\n\n/** Options for {@link openrouter}. */\nexport interface OpenRouterParams {\n /** API key. Falls back to the `OPENROUTER_API_KEY` environment variable. */\n apiKey?: string\n /**\n * Model used when a request does not set one.\n * @default 'anthropic/claude-opus-5.5'\n */\n defaultModel?: string\n /**\n * Provider capability flags. OpenRouter itself is a router — whether vision,\n * native image-in-tool-result, or document/PDF input are supported depends on\n * the downstream model. Default: `{ vision: true, imageInToolResult: false,\n * documents: true }` — matches the default `anthropic/claude-opus-5.5` model\n * (vision + PDF capable; OpenRouter forwards the OpenAI `file` content part to\n * Anthropic/OpenAI/Gemini routes).\n *\n * Override when routing to a known-text-only model (e.g. `meta-llama/llama-3-8b-instruct`),\n * setting the relevant flags to `false`.\n */\n capabilities?: ProviderCapabilities\n /**\n * PDF-parsing engine for OpenRouter's `file-parser` plugin. Applied only when\n * a request carries a forwarded PDF/`file` part. Default `'pdf-text'` (free\n * text-only extraction, safe on any downstream model). Set `'native'` to use\n * the downstream model's own file support, or `'mistral-ocr'` for\n * scanned/image PDFs. See {@link OpenAICompatParams.pdfEngine}.\n */\n pdfEngine?: 'native' | 'pdf-text' | 'mistral-ocr'\n /**\n * Prompt-cache affinity key, sent as `prompt_cache_key`. Off by default.\n *\n * OpenRouter reads this field as its sticky-routing key, so enabling it pins a\n * session's turns to the provider endpoint that already holds its cache —\n * complementing the automatic stickiness it applies after a cached request.\n * `'session'` keys on the agent's session id. See `./prompt-cache-key.ts`.\n */\n promptCacheKey?: PromptCacheKeyOption\n /**\n * Additionally send the affinity key as this HTTP header, for gateways in\n * front of OpenRouter that route on a header rather than a body field.\n */\n promptCacheKeyHeader?: string\n}\n\nfunction getApiKey(params?: OpenRouterParams): string {\n // Resolution order aligned with other providers — explicit params win, env\n // is the fallback. See cerebras.ts for the rationale.\n if (typeof params?.apiKey === 'string' && params.apiKey.length > 0)\n return params.apiKey\n\n if (process.env.OPENROUTER_API_KEY)\n return process.env.OPENROUTER_API_KEY\n\n throw new Error('No OpenRouter API key found. Pass `apiKey` or set OPENROUTER_API_KEY in your environment.')\n}\n\nconst ATTRIBUTION_HEADERS: Readonly<Record<string, string>> = {\n 'HTTP-Referer': 'https://github.com/Tahul/zidane',\n 'X-Title': 'zidane',\n}\n\n/**\n * Maps legacy OpenRouter model ids to their current slugs and returns other ids unchanged.\n *\n * @param modelId - Model id as stored or requested.\n */\nexport function normalizeOpenRouterModelId(modelId: string): string {\n return MODEL_ALIASES[modelId] ?? modelId\n}\n\n/**\n * OpenRouter provider.\n *\n * Thin wrapper around {@link openaiCompat} with OpenRouter-specific defaults\n * (base URL, default model) and required attribution headers.\n *\n * @param params - API key, default model, capabilities, PDF engine and prompt-cache key settings.\n * @example\n * ```ts\n * import { createAgent } from 'zidane'\n * import { openrouter } from 'zidane/providers/openrouter'\n *\n * const agent = createAgent({\n * provider: openrouter({ apiKey: process.env.OPENROUTER_API_KEY }),\n * })\n * await agent.run({ prompt: 'Say hello.' })\n * ```\n */\nexport function openrouter(params?: OpenRouterParams): Provider {\n const apiKey = getApiKey(params)\n const base = openaiCompat({\n name: 'openrouter',\n label: 'OpenRouter',\n apiKey,\n baseURL: BASE_URL,\n defaultModel: normalizeOpenRouterModelId(params?.defaultModel || OPENROUTER_DEFAULT_MODEL),\n extraHeaders: ATTRIBUTION_HEADERS,\n capabilities: params?.capabilities ?? { vision: true, imageInToolResult: false, documents: true },\n // Make PDF parsing deterministic. OpenRouter routes to many models, so the\n // default must work on ANY of them: `'pdf-text'` (free, text-only\n // extraction) never 400s regardless of the downstream model's file support.\n // `'native'` would route to the model's own file handling (richer — page\n // images — for gpt-4o / Gemini / Claude) but 400s on text-only models, so\n // it's opt-in via `pdfEngine: 'native'` (or `'mistral-ocr'` for scans).\n pdfEngine: params?.pdfEngine ?? 'pdf-text',\n ...(params?.promptCacheKey !== undefined ? { promptCacheKey: params.promptCacheKey } : {}),\n ...(params?.promptCacheKeyHeader !== undefined ? { promptCacheKeyHeader: params.promptCacheKeyHeader } : {}),\n // OpenRouter honors `cache_control` markers for Anthropic + Gemini routes and\n // silently ignores them for routes that cache automatically. Safe to turn on\n // by default — the caller can still flip `behavior.cache = false` to opt out\n // without needing to re-instantiate the provider.\n cacheBreakpoints: true,\n // OpenRouter speaks the normalized `reasoning` request field and round-trips\n // structured `reasoning_details` on assistant messages. Captured into\n // `provider_reasoning` blocks and echoed back to preserve extended-reasoning\n // state across turns on the same upstream route.\n supportsReasoning: true,\n })\n\n return {\n ...base,\n decisions: openrouterDecisions({ apiKey, headers: ATTRIBUTION_HEADERS }),\n async stream(options, callbacks) {\n return await base.stream({\n ...options,\n model: normalizeOpenRouterModelId(options.model),\n }, callbacks)\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prompts-D2lPHLOV.d.ts","names":[],"sources":["../src/tools/prompts.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6Ba;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aA8HiB,cAAA;;;WAKL,YAAA;;;;;;;;KAmBb,qBAAqB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"google.js","names":["catalogLookup"],"sources":["../../src/providers/google.ts"],"sourcesContent":["/**\n * Google Gemini providers, on pi-ai's Google streams.\n *\n * - {@link google}: the Gemini API (Google AI Studio), authenticated by an\n * API key.\n * - {@link googleVertex}: Vertex AI, authenticated by Google Cloud\n * credentials (gcloud Application Default Credentials or a credentials\n * file) or a Vertex API key.\n *\n * - {@link googleCompatible}: the same plumbing over another Gemini-wire\n * backend (an extension's transport, models and auth).\n *\n * Gemini signs its reasoning: thought signatures ride on text parts, thought\n * parts and function calls, and Gemini 3 rejects a tool-use step whose\n * function calls come back without theirs. pi-ai sends nothing in their\n * place, so these providers persist them on the blocks that carried them\n * (`signature`, `signatureProducer`) and replay them only to the route that\n * issued them, whatever the model: Google's guidance is to resend a session's\n * thought blocks as received, model switches included.\n */\nimport type {\n AssistantMessageEventStream,\n AssistantMessage as PiAssistantMessage,\n JsonObject as PiJsonObject,\n Message as PiMessage,\n Model as PiModel,\n ThinkingBudgets as PiThinkingBudgets,\n Tool as PiTool,\n Usage as PiUsage,\n SimpleStreamOptions,\n TranscriptContext,\n} from '@earendil-works/pi-ai'\nimport type { GoogleVertexOptions } from '@earendil-works/pi-ai/api/google-vertex'\nimport type { Provider, ProviderCapabilities, StreamCallbacks, StreamOptions, ToolSpec, TurnResult } from '.'\nimport type { ClassifiedError } from '../errors'\nimport type { GeminiSignatureScope, SessionContentBlock, SessionMessage, ToolResultDocumentContent, TurnFinishReason, TurnUsage } from '../types'\nimport type { ModelCostRates } from './cost'\nimport type { ModelCatalog } from './model-catalog'\nimport type { OAuthParams } from './oauth'\nimport { mkdtempSync, rmSync, writeFileSync } from 'node:fs'\nimport { lstat, readdir, rm } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport { normalizeContext } from '@earendil-works/pi-ai'\nimport { getBuiltinModel } from '@earendil-works/pi-ai/providers/all'\nimport { classifyErrorPrelude, classifyProviderLimit, isRetryableHttpStatus, matchesContextExceeded, matchesToolPairingError, providerLimitReason } from '../errors'\nimport { unsupportedMediaError } from '../prompt'\nimport { reasoningWireAction, SYNTHETIC_TOOL_RESULT_PLACEHOLDER } from '../session/messages'\nimport { systemNotesAsText } from '../system-notes'\nimport { renderSystemForWire } from '../system-prompt'\nimport { assertResolvedMediaBlock, documentBlockMarker } from '../types'\nimport { fillEstimatedCost } from './cost'\nimport { GOOGLE_VERTEX_OAUTH_ID } from './google-oauth'\nimport { lookupModel as catalogLookup, mergeCatalogEntry } from './model-catalog'\nimport { pinnedAccountMissingError, readAccountOAuthCredential, readOAuthCredentials, resolveOAuthApiKey } from './oauth'\nimport { assistantMessage, toolResultsMessage, userMessage } from './openai-compat'\nimport { sanitizeToolSpecs } from './schema-sanitize'\nimport { createToolNameBoundary } from './tool-name-boundary'\n\n/** Zidane provider (and signature route) names of the two Google backends. */\nexport type GoogleRouteName = 'google' | 'google-vertex'\n\ntype GoogleApi = 'google-generative-ai' | 'google-vertex'\n/**\n * pi-ai model record on a Gemini wire. A {@link googleCompatible} backend\n * builds its own with `api: 'google-generative-ai'` (the wire pi-ai's Gemini\n * converters speak) and its own `provider`.\n */\nexport type GoogleWireModel = PiModel<GoogleApi>\ntype GoogleModel = GoogleWireModel\n/** What both pi-ai entry points accept here. Tool choice goes through `onPayload`. */\nexport type GoogleStreamOptions = SimpleStreamOptions & Pick<GoogleVertexOptions, 'thinking'>\n/** One pi-ai Gemini stream entry point. */\nexport type GoogleStreamFn = (model: GoogleWireModel, context: TranscriptContext, options: GoogleStreamOptions) => AssistantMessageEventStream\n\n/**\n * pi-ai's `stream` / `streamSimple` pair for one backend, loaded on first\n * use. `streamSimple` takes a `reasoning` level (and `thinkingBudgets`);\n * `stream` takes an explicit `thinking` config (adaptive thinking).\n */\nexport interface GoogleStreams {\n /** Takes an explicit `thinking` config (adaptive thinking). */\n stream: GoogleStreamFn\n /** Takes a `reasoning` level and optional `thinkingBudgets`. */\n streamSimple: GoogleStreamFn\n}\n\n/** Model used when a request names none. Served on free-tier Gemini API keys. */\nexport const GOOGLE_DEFAULT_MODEL = 'gemini-3.8-flash'\n\n/** A Google model pi-ai hasn't bundled yet: a bundled `template` with the same thinking shape, under its own id. */\nexport interface GoogleExtraModel {\n /** Model id sent to the API. */\n id: string\n /** Display name. */\n name: string\n /** A bundled model with the same thinking levels and budgets. */\n template: string\n /** Context window in tokens. */\n contextWindow: number\n /** Largest output in tokens. */\n maxTokens: number\n /** A function, so a dated price change applies to long-running hosts. */\n rates: () => Required<ModelCostRates>\n}\n\n/**\n * Models pi-ai hasn't bundled yet, served on both routes. A pi-ai release\n * that bundles one supersedes its entry (bundled metadata always wins), so\n * delete the entry then.\n */\nexport const GOOGLE_EXTRA_MODELS: readonly GoogleExtraModel[] = []\n\nconst lookupBuiltin = getBuiltinModel as (provider: string, modelId: string) => GoogleModel | undefined\n\nfunction builtinModel(route: GoogleRouteName, modelId: string): GoogleModel | undefined {\n try {\n return lookupBuiltin(route, modelId)\n }\n catch {\n return undefined\n }\n}\n\n/**\n * pi-ai model record for `modelId` on `route`: the bundled entry, else a\n * {@link GOOGLE_EXTRA_MODELS} overlay, else the default model's shape under\n * the requested id. A catalog entry overlays whichever applies.\n *\n * @param route - Backend the request goes to.\n * @param modelId - Requested model id.\n * @param catalog - Per-run catalog override.\n */\nexport function resolveGoogleModel(route: GoogleRouteName, modelId: string, catalog?: ModelCatalog): GoogleModel {\n const entry = catalogLookup(route, modelId, catalog)\n const bundled = builtinModel(route, modelId)\n if (bundled)\n return mergeCatalogEntry(bundled, entry)\n\n const extra = GOOGLE_EXTRA_MODELS.find(m => m.id === modelId)\n const template = builtinModel(route, extra?.template ?? GOOGLE_DEFAULT_MODEL)\n if (!template)\n throw new Error(`Google model registry (${route}) is missing ${extra?.template ?? GOOGLE_DEFAULT_MODEL}`)\n if (extra) {\n return mergeCatalogEntry({\n ...template,\n id: extra.id,\n name: extra.name,\n contextWindow: extra.contextWindow,\n maxTokens: extra.maxTokens,\n cost: extra.rates(),\n }, entry)\n }\n return mergeCatalogEntry({ ...template, id: modelId, name: modelId }, entry)\n}\n\nfunction formatTools(tools: ToolSpec[]): PiTool[] {\n // pi-ai sends `parametersJsonSchema` (full JSON Schema); the OpenAI pass\n // still fixes the root shapes (`$ref`, `anyOf`, nullable roots) MCP servers\n // publish and Gemini rejects as well.\n return sanitizeToolSpecs(tools, { profile: 'openai' }).map(t => ({\n name: t.name,\n description: t.description ?? '',\n parameters: t.inputSchema as PiTool['parameters'],\n }))\n}\n\nfunction documentMarker(doc: ToolResultDocumentContent): string {\n return documentBlockMarker(doc, 'document omitted')\n}\n\nfunction emptyUsage(): PiUsage {\n return {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n totalTokens: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n }\n}\n\nfunction piUserMessage(content: SessionContentBlock[], provider: string): PiMessage | null {\n for (const b of content) {\n if (b.type === 'audio')\n throw unsupportedMediaError('audio', provider)\n if (b.type === 'video')\n throw unsupportedMediaError('video', provider)\n }\n const parts: Exclude<Extract<PiMessage, { role: 'user' }>['content'], string> = []\n for (const block of content) {\n if (block.type === 'text') {\n parts.push({ type: 'text', text: block.text })\n }\n else if (block.type === 'image') {\n assertResolvedMediaBlock(block, 'Google wire messages')\n parts.push({ type: 'image', data: block.data, mimeType: block.mediaType })\n }\n else if (block.type === 'document') {\n // pi-ai's content union is text | image: no file part to carry a PDF.\n assertResolvedMediaBlock(block, 'Google wire messages')\n parts.push({ type: 'text', text: documentMarker(block) })\n }\n }\n if (parts.length === 0)\n return null\n if (parts.length === 1 && parts[0]!.type === 'text')\n return { role: 'user', content: parts[0]!.text, timestamp: Date.now() }\n return { role: 'user', content: parts, timestamp: Date.now() }\n}\n\nfunction piToolResultMessage(\n result: Extract<SessionContentBlock, { type: 'tool_result' }>,\n toolName: string,\n provider: string,\n): PiMessage {\n const content = typeof result.output === 'string'\n ? [{ type: 'text' as const, text: result.output }]\n : result.output.map((block) => {\n if (block.type === 'image') {\n assertResolvedMediaBlock(block, 'Google wire messages')\n return { type: 'image' as const, data: block.data, mimeType: block.mediaType }\n }\n if (block.type === 'audio')\n throw unsupportedMediaError('audio', provider)\n if (block.type === 'video')\n throw unsupportedMediaError('video', provider)\n if (block.type === 'document') {\n assertResolvedMediaBlock(block, 'Google wire messages')\n return { type: 'text' as const, text: documentMarker(block) }\n }\n return { type: 'text' as const, text: block.text }\n })\n return {\n role: 'toolResult',\n toolCallId: result.callId,\n // Gemini pairs a functionResponse with its call by name.\n toolName,\n content,\n isError: result.isError ?? false,\n timestamp: Date.now(),\n }\n}\n\n/**\n * One assistant turn for pi-ai. A turn holding this route's signatures is\n * stamped with the TARGET model, so pi-ai treats it as its own and replays\n * the signatures (Google accepts them across its models). Any other turn is\n * stamped foreign: pi-ai then sends its reasoning as plain text and its\n * calls unsigned.\n */\nfunction piAssistantMessage(content: SessionContentBlock[], model: GoogleModel, route: GeminiSignatureScope): PiAssistantMessage {\n const native = content.some(block =>\n (block.type === 'text' || block.type === 'tool_call' || block.type === 'thinking')\n && block.signature !== undefined\n && block.signatureProducer === route)\n const own = (block: { signature?: string, signatureProducer?: string }): string | undefined =>\n native && block.signatureProducer === route ? block.signature : undefined\n\n const piContent: PiAssistantMessage['content'] = []\n for (const block of content) {\n if (block.type === 'text') {\n const signature = own(block)\n piContent.push({ type: 'text', text: block.text, ...(signature ? { textSignature: signature } : {}) })\n }\n else if (block.type === 'thinking') {\n const action = reasoningWireAction(block, route)\n if (action === 'drop')\n continue\n const signature = action === 'keep' ? own(block) : undefined\n piContent.push({ type: 'thinking', thinking: block.text, ...(signature ? { thinkingSignature: signature } : {}) })\n }\n else if (block.type === 'tool_call') {\n const signature = own(block)\n piContent.push({\n type: 'toolCall',\n id: block.id,\n name: block.name,\n arguments: block.input as PiJsonObject,\n ...(signature ? { thoughtSignature: signature } : {}),\n })\n }\n // `redacted_thinking`, `provider_reasoning` and server-tool blocks belong\n // to other providers' wires.\n }\n\n return {\n role: 'assistant',\n content: piContent,\n api: model.api,\n provider: native ? model.provider : 'zidane',\n model: native ? model.id : 'history',\n usage: emptyUsage(),\n // pi-ai skips `error` / `aborted` turns outright; a stored turn always replays.\n stopReason: 'stop',\n timestamp: Date.now(),\n }\n}\n\n/**\n * Converts session messages to pi-ai messages for a Google backend.\n *\n * Unlike the Responses wire, an assistant turn stays whole: Gemini signs only\n * the FIRST function call of a parallel step, so splitting the calls into\n * separate model turns would leave the others unsigned. Its tool results\n * follow in call order (pi-ai folds them into one user turn), with the\n * synthetic placeholder for any the history lost.\n *\n * @param messages - Session messages, tool names already on the wire.\n * @param model - Target model.\n * @param route - Signature scope of the target (the backend's route name by default).\n * @param provider - Provider named in unsupported-media errors. Defaults to `route`.\n */\nexport function toGooglePiMessages(messages: SessionMessage[], model: GoogleModel, route: GeminiSignatureScope, provider: string = route): PiMessage[] {\n // System notes have no native slot on this wire: send them as `<system-reminder>` text.\n messages = systemNotesAsText(messages)\n const out: PiMessage[] = []\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]!\n if (msg.role === 'assistant') {\n out.push(piAssistantMessage(msg.content, model, route))\n const calls = msg.content.filter((b): b is Extract<SessionContentBlock, { type: 'tool_call' }> => b.type === 'tool_call')\n if (calls.length === 0)\n continue\n const next = messages[i + 1]\n const results = new Map(\n (next?.role === 'user' ? next.content : [])\n .filter((b): b is Extract<SessionContentBlock, { type: 'tool_result' }> => b.type === 'tool_result')\n .map(r => [r.callId, r]),\n )\n for (const call of calls) {\n const result = results.get(call.id)\n ?? { type: 'tool_result' as const, callId: call.id, output: SYNTHETIC_TOOL_RESULT_PLACEHOLDER, isError: true }\n out.push(piToolResultMessage(result, call.name, provider))\n }\n if (next?.role === 'user') {\n // Results whose call isn't in the turn above were removed by the\n // canonical pairing repair; never send one unpaired.\n const rest = piUserMessage(next.content.filter(b => b.type !== 'tool_result'), provider)\n if (rest)\n out.push(rest)\n i++\n }\n continue\n }\n const userMsg = piUserMessage(msg.content.filter(b => b.type !== 'tool_result'), provider)\n if (userMsg)\n out.push(userMsg)\n }\n return out\n}\n\n/**\n * Converts pi-ai's final assistant message to a session message, tagging\n * every thought signature with the route that issued it.\n *\n * @param message - pi-ai assistant message.\n * @param route - Signature scope that produced it.\n */\nexport function fromGooglePiAssistantMessage(message: PiAssistantMessage, route: GeminiSignatureScope): SessionMessage {\n const signed = (signature: string | undefined) =>\n signature ? { signature, signatureProducer: route } : {}\n const content: SessionContentBlock[] = []\n for (const block of message.content) {\n if (block.type === 'text')\n content.push({ type: 'text', text: block.text, ...signed(block.textSignature) })\n else if (block.type === 'thinking')\n content.push({ type: 'thinking', text: block.thinking, ...signed(block.thinkingSignature) })\n else if (block.type === 'toolCall')\n content.push({ type: 'tool_call', id: block.id, name: block.name, input: block.arguments, ...signed(block.thoughtSignature) })\n }\n return { role: 'assistant', content }\n}\n\nfunction mapStopReason(stopReason: string | undefined, hasToolCalls: boolean): TurnFinishReason {\n switch (stopReason) {\n case 'toolUse':\n return 'tool-calls'\n case 'length':\n return 'length'\n case 'error':\n return 'error'\n case 'aborted':\n return 'other'\n default:\n return hasToolCalls ? 'tool-calls' : 'stop'\n }\n}\n\n/** Forced tool choice, written into Gemini's `functionCallingConfig`. */\nfunction applyToolChoice(payload: unknown, options: StreamOptions, toWire: (name: string) => string): unknown {\n const choice = options.toolChoice\n if (!choice || choice.type === 'auto')\n return payload\n const params = payload as { config?: { toolConfig?: { functionCallingConfig?: Record<string, unknown> } } }\n if (!params.config?.toolConfig)\n return payload\n params.config.toolConfig.functionCallingConfig = choice.type === 'tool' && choice.name\n ? { mode: 'ANY', allowedFunctionNames: [toWire(choice.name)] }\n : { mode: 'ANY' }\n return params\n}\n\n/**\n * Transient Gemini failures worth a loop-level retry once pi-ai's own retries\n * (408 / 409 / 429 / 5xx before the stream opens) are spent.\n */\nconst TRANSIENT_GOOGLE_MESSAGE_RE = /RESOURCE_EXHAUSTED|UNAVAILABLE|DEADLINE_EXCEEDED|overloaded|high demand|rate.?limit|try again later/i\n\n/** Gemini's `RetryInfo` detail in a 429 body: `\"retryDelay\": \"34s\"`. */\nconst RETRY_DELAY_RE = /\"retryDelay\"\\s*:\\s*\"(\\d+(?:\\.\\d+)?)s\"/\n\n/** pi-ai formats HTTP failures as `<status>: <body>`. */\nfunction leadingStatus(message: string): number | undefined {\n const match = /^(\\d{3})\\b/.exec(message)\n return match ? Number(match[1]) : undefined\n}\n\ninterface GoogleErrorBody { error?: { code?: unknown, message?: unknown, status?: unknown } }\n\nfunction parseGoogleErrorBody(text: string): GoogleErrorBody['error'] | undefined {\n try {\n const parsed = JSON.parse(text) as GoogleErrorBody | null\n return parsed && typeof parsed.error === 'object' && parsed.error ? parsed.error : undefined\n }\n catch {\n return undefined\n }\n}\n\n/**\n * The stream error pi-ai reports, as Google wrote it. `@google/genai` wraps a\n * non-JSON response as `{\"error\":{\"message\":\"<body>\"}}`, so Google's own\n * `{\"error\":{…}}` can arrive JSON-encoded inside it.\n *\n * @param raw - pi-ai's `errorMessage`: `<status>: <body>` or the SDK's message.\n * @returns The innermost message prefixed with its HTTP and RPC status, the\n * status, and the innermost body (it carries details such as `retryDelay`).\n */\nfunction unwrapGoogleError(raw: string): { message: string, status?: number, body?: string } {\n let status = leadingStatus(raw)\n let rpcStatus: string | undefined\n let text = status === undefined ? raw : raw.replace(/^\\d{3}:\\s*/, '')\n let message: string | undefined\n let body = raw\n for (let error = parseGoogleErrorBody(text); error; error = parseGoogleErrorBody(text)) {\n body = text\n if (typeof error.code === 'number')\n status = error.code\n if (typeof error.status === 'string' && /^[A-Z_]+$/.test(error.status))\n rpcStatus = error.status\n if (typeof error.message !== 'string')\n break\n message = text = error.message.trim()\n }\n if (!message)\n return { message: raw, ...(status !== undefined ? { status } : {}) }\n const prefix = [status, rpcStatus].filter(part => part !== undefined).join(' ')\n return { message: prefix ? `${prefix}: ${message}` : message, ...(status !== undefined ? { status } : {}), body }\n}\n\n/**\n * Classify a Gemini API / Vertex AI error.\n *\n * @param err - Error thrown by pi-ai or the SDK.\n * @param label - Product a limit's message names; routes over other services (Antigravity) pass their own.\n */\nexport function classifyGoogleError(err: unknown, label = 'Gemini'): ClassifiedError | null {\n const prelude = classifyErrorPrelude(err)\n if (prelude === 'not-object')\n return null\n if (prelude === 'aborted')\n return { kind: 'aborted' }\n const anyErr = err as { message?: unknown, status?: unknown, body?: unknown }\n const message = typeof anyErr.message === 'string' ? anyErr.message : ''\n if (matchesContextExceeded(message))\n return { kind: 'context_exceeded', providerCode: 'context_length_exceeded', message }\n if (matchesToolPairingError(message))\n return { kind: 'tool_pairing_corruption', message }\n if (!message)\n return null\n const status = typeof anyErr.status === 'number' ? anyErr.status : leadingStatus(message)\n const retryable = (status !== undefined && isRetryableHttpStatus(status)) || TRANSIENT_GOOGLE_MESSAGE_RE.test(message)\n const reason = providerLimitReason({ status, message })\n if (reason) {\n const delay = RETRY_DELAY_RE.exec(typeof anyErr.body === 'string' ? anyErr.body : message)\n return classifyProviderLimit(\n { reason, provider: label, ...(delay ? { retryAfterMs: Number(delay[1]) * 1000 } : {}) },\n { ...(status !== undefined ? { providerCode: String(status) } : {}), retryable },\n )\n }\n return {\n kind: 'provider_error',\n ...(status !== undefined ? { providerCode: String(status) } : {}),\n message,\n ...(retryable ? { retryable: true } : {}),\n }\n}\n\n/** Every budget level at `tokens`: pi-ai picks the level, the caller fixed the budget. */\nfunction budgetsAt(tokens: number): PiThinkingBudgets {\n return { minimal: tokens, low: tokens, medium: tokens, high: tokens }\n}\n\n/** Credentials and settings one request goes out with. */\nexport interface GoogleRequestAuth {\n /** Sent to the stream as `options.apiKey` (an API key, or a bearer token for a custom transport). */\n apiKey?: string\n /**\n * Sent to the stream as `options.env`, which pi-ai reads before\n * `process.env` (project, location, credentials file). A custom transport\n * reads its own per-request settings here, e.g. the account's project.\n */\n env?: Record<string, string>\n /** Removes what the request needed only while it ran. */\n dispose?: () => void\n}\n\n/**\n * A Gemini-wire backend for {@link googleCompatible}: where requests go\n * (`load`), how they authenticate (`auth`) and which models it serves\n * (`resolveModel`). Message conversion, thought-signature bookkeeping, tool\n * names, thinking levels, usage and cost stay in the shared plumbing.\n */\nexport interface GoogleCompatibleRoute {\n /**\n * Provider name (`Provider.name`, error copy) and the default signature\n * scope. Must not be a built-in provider name (`google`,\n * `google-vertex`, `anthropic`, `openai`).\n */\n name: string\n /**\n * pi-ai stream functions for the backend, loaded on first use. pi-ai's\n * `api/google-generative-ai` adapter is the reference: a custom transport\n * emits the same events, applies `options.onPayload` to the SDK-shaped\n * params (`{ model, contents, config }`) before sending, and reports errors\n * as `<status>: <body>` so they classify by HTTP status.\n */\n load: () => Promise<GoogleStreams>\n /** Credentials and settings for one request, resolved per turn. */\n auth: (callbacks: StreamCallbacks) => GoogleRequestAuth | Promise<GoogleRequestAuth>\n /** Whether the provider runs on an OAuth credential. */\n isOAuth: boolean\n /**\n * pi-ai model record for a requested model id, with `api:\n * 'google-generative-ai'`. Its `cost` rates price each turn: zero rates\n * report no cost (quota-backed access).\n *\n * @param modelId - Requested model id.\n * @param catalog - Per-run catalog override.\n */\n resolveModel: (modelId: string, catalog?: ModelCatalog) => GoogleWireModel\n /**\n * Signature scope of a model: the tag its thought signatures carry, and\n * the only scope they replay to. Defaults to `name`, right when every model\n * behind the backend accepts the others' signatures (Gemini does). A\n * backend fronting several model families returns one scope per family,\n * so switching families mid-session sends earlier reasoning unsigned.\n *\n * @param modelId - Model id of the turn.\n */\n signatureScope?: (modelId: string) => string\n /** Error classification. Defaults to {@link classifyGoogleError}. */\n classifyError?: (err: unknown) => ClassifiedError | null\n}\n\n/** Built-in routes, plus the registry lookup only they have. */\ninterface GoogleRoute extends Omit<GoogleCompatibleRoute, 'resolveModel'> {\n resolveModel?: GoogleCompatibleRoute['resolveModel']\n}\n\n/** Names a {@link googleCompatible} route can't take: built-in providers and signature producers. */\nconst RESERVED_ROUTE_NAMES: ReadonlySet<string> = new Set(['google', 'google-vertex', 'anthropic', 'openai', 'zidane'])\n\n/** Settings shared by the Google providers. */\nexport interface GoogleSharedParams {\n /**\n * Model used when a request does not set one.\n * @default 'gemini-3.8-flash'\n */\n defaultModel?: string\n /**\n * Provider capability flags. Gemini takes images in prompts and in tool\n * results; audio, video and PDFs degrade to text markers (pi-ai's content\n * union is text | image).\n */\n capabilities?: ProviderCapabilities\n /** Extra HTTP headers sent on every request. */\n extraHeaders?: Record<string, string>\n}\n\nfunction createGoogleProvider(route: GoogleRoute, params: GoogleSharedParams | undefined): Provider {\n const defaultModel = params?.defaultModel || GOOGLE_DEFAULT_MODEL\n const capabilities: ProviderCapabilities = params?.capabilities ?? {\n vision: true,\n imageInToolResult: true,\n audio: false,\n video: false,\n documents: false,\n }\n\n return {\n name: route.name,\n meta: { defaultModel, isOAuth: route.isOAuth, capabilities },\n formatTools,\n userMessage,\n assistantMessage,\n toolResultsMessage,\n classifyError: route.classifyError ?? classifyGoogleError,\n\n async stream(options: StreamOptions, callbacks: StreamCallbacks): Promise<TurnResult> {\n const auth = await route.auth(callbacks)\n try {\n return await streamTurn(auth, options, callbacks)\n }\n finally {\n auth.dispose?.()\n }\n },\n }\n\n async function streamTurn(auth: GoogleRequestAuth, options: StreamOptions, callbacks: StreamCallbacks): Promise<TurnResult> {\n const modelId = options.model || defaultModel\n const model = route.resolveModel\n ? route.resolveModel(modelId, options.modelCatalog)\n : resolveGoogleModel(route.name as GoogleRouteName, modelId, options.modelCatalog)\n const scope = signatureScopeOf(route, model.id)\n const tools = options.tools as PiTool[]\n const nameBoundary = createToolNameBoundary(options.messages, tools.map(tool => tool.name))\n // pi-ai's stream entry points take a `TranscriptContext`: the prompt and\n // tools folded into a leading system message.\n const context = normalizeContext({\n systemPrompt: renderSystemForWire(options.system),\n messages: toGooglePiMessages(nameBoundary.messages, model, scope, route.name),\n tools: tools.map(tool => ({ ...tool, name: nameBoundary.toWire(tool.name) })),\n })\n const api = await route.load()\n const base: GoogleStreamOptions = {\n ...(auth.apiKey ? { apiKey: auth.apiKey } : {}),\n ...(auth.env ? { env: auth.env } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n signal: options.signal,\n ...(params?.extraHeaders ? { headers: params.extraHeaders } : {}),\n onPayload: (payload: unknown) => applyToolChoice(payload, options, nameBoundary.toWire),\n }\n\n let s: AssistantMessageEventStream\n if (options.thinking === 'adaptive' && model.reasoning) {\n // pi-ai has no adaptive level: thinking on, no level or budget, so the\n // model thinks as much as it decides, with thought summaries.\n const { buildBaseOptions } = await import('@earendil-works/pi-ai/api/simple-options')\n s = api.stream(model, context, { ...buildBaseOptions(model, context, base), thinking: { enabled: true } })\n }\n else {\n const reasoning = options.thinking && options.thinking !== 'off' && options.thinking !== 'adaptive'\n ? options.thinking\n : undefined\n // `streamSimple` clamps the level to what the model supports and sends\n // `thinkingLevel` (Gemini 3+) or a token budget (2.5), or turns\n // thinking off when none is set.\n s = api.streamSimple(model, context, {\n ...base,\n ...(reasoning ? { reasoning } : {}),\n ...(reasoning && options.thinkingBudget !== undefined ? { thinkingBudgets: budgetsAt(options.thinkingBudget) } : {}),\n })\n }\n\n let finalMessage: PiAssistantMessage | undefined\n let text = ''\n let thinking = ''\n for await (const event of s) {\n if (event.type === 'text_delta') {\n text += event.delta\n callbacks.onText(event.delta)\n }\n else if (event.type === 'thinking_delta') {\n thinking += event.delta\n callbacks.onThinking?.(event.delta)\n }\n else if (event.type === 'thinking_end') {\n const delta = event.content.startsWith(thinking)\n ? event.content.slice(thinking.length)\n : (thinking ? '' : event.content)\n if (delta) {\n thinking += delta\n callbacks.onThinking?.(delta)\n }\n }\n else if (event.type === 'toolcall_start' || event.type === 'toolcall_delta') {\n callbacks.onToolCallDelta?.()\n }\n else if (event.type === 'done') {\n finalMessage = event.message\n }\n else if (event.type === 'error') {\n const { message, ...details } = unwrapGoogleError(event.error.errorMessage || `Google ${route.name} API error`)\n throw Object.assign(new Error(message), details)\n }\n }\n finalMessage ??= await s.result()\n\n const toolCalls = finalMessage.content\n .filter(block => block.type === 'toolCall')\n .map(block => ({ id: block.id, name: nameBoundary.fromWire(block.name), input: block.arguments as Record<string, unknown> }))\n const assistantTurn = fromGooglePiAssistantMessage(finalMessage, scope)\n assistantTurn.content = assistantTurn.content.map(block =>\n block.type === 'tool_call' ? { ...block, name: nameBoundary.fromWire(block.name) } : block,\n )\n const finishReason = mapStopReason(finalMessage.stopReason, toolCalls.length > 0)\n const usage: TurnUsage = await fillEstimatedCost({\n input: finalMessage.usage.input,\n output: finalMessage.usage.output,\n cacheRead: finalMessage.usage.cacheRead || undefined,\n ...(finalMessage.usage.reasoning ? { thinking: finalMessage.usage.reasoning } : {}),\n cost: finalMessage.usage.cost.total || undefined,\n finishReason,\n modelId,\n }, route.name, undefined, options.modelCatalog)\n\n return {\n assistantMessage: assistantTurn,\n text: text || finalMessage.content.flatMap(block => block.type === 'text' ? [block.text] : []).join(''),\n toolCalls,\n done: toolCalls.length === 0,\n usage,\n }\n }\n}\n\n/**\n * The scope a model's thought signatures carry. A custom route's scope can't\n * impersonate a built-in producer, whose signatures it would then replay.\n */\nfunction signatureScopeOf(route: GoogleRoute, modelId: string): GeminiSignatureScope {\n const scope = route.signatureScope?.(modelId) ?? route.name\n if (scope !== route.name && RESERVED_ROUTE_NAMES.has(scope))\n throw new Error(`${route.name}: signature scope \"${scope}\" is reserved for a built-in provider`)\n return scope\n}\n\n/**\n * Creates a provider over another Gemini-wire backend: an extension supplies\n * the transport, auth and model records; message conversion, thought\n * signatures (tagged with the route's scope, never replayed elsewhere), tool\n * names, thinking levels, usage and cost come from the same plumbing as\n * {@link google} and {@link googleVertex}.\n *\n * @param route - The backend: name, transport, auth and models.\n * @param params - Default model, capabilities and extra headers.\n *\n * @example\n * ```ts\n * import { googleCompatible } from 'zidane/providers'\n *\n * const provider = googleCompatible({\n * name: 'my-gateway',\n * isOAuth: false,\n * load: async () => myGeminiTransport,\n * auth: () => ({ apiKey: process.env.MY_GATEWAY_KEY }),\n * resolveModel: id => myModels[id],\n * }, { defaultModel: 'gemini-3.8-flash' })\n * ```\n */\nexport function googleCompatible(route: GoogleCompatibleRoute, params?: GoogleSharedParams): Provider {\n if (!route.name || RESERVED_ROUTE_NAMES.has(route.name))\n throw new Error(`googleCompatible: route name \"${route.name}\" is reserved for a built-in provider`)\n return createGoogleProvider(route, params)\n}\n\n/**\n * pi-ai's Gemini-wire building blocks, for a {@link googleCompatible}\n * transport: the converters, signature helpers and event stream pi-ai's own\n * Gemini adapter (`api/google-generative-ai`) is made of.\n */\nexport interface GoogleWireKit {\n /** Transcript to Gemini `Content[]`. */\n convertMessages: typeof import('@earendil-works/pi-ai/api/google-shared')['convertMessages']\n /** Tools to Gemini function declarations (`parametersJsonSchema`, or legacy `parameters`). */\n convertTools: typeof import('@earendil-works/pi-ai/api/google-shared')['convertTools']\n /** Whether a response part is thought content (`thought: true`), not just signature-bearing. */\n isThinkingPart: typeof import('@earendil-works/pi-ai/api/google-shared')['isThinkingPart']\n /** Keeps a block's last non-empty `thoughtSignature` when later deltas omit it. */\n retainThoughtSignature: typeof import('@earendil-works/pi-ai/api/google-shared')['retainThoughtSignature']\n /** Whether the model needs explicit ids on function calls and responses. */\n requiresToolCallId: typeof import('@earendil-works/pi-ai/api/google-shared')['requiresToolCallId']\n /** Gemini's raw `finishReason` string to a stop reason. */\n mapStopReasonString: typeof import('@earendil-works/pi-ai/api/google-shared')['mapStopReasonString']\n /** Function-calling mode for a tool choice; `VALIDATED` when a tool asks for strict sampling. */\n resolveGoogleFunctionCallingMode: typeof import('@earendil-works/pi-ai/api/google-shared')['resolveGoogleFunctionCallingMode']\n /** Whether the model enforces required parameters in validated tool calling (Gemini 3+). */\n supportsGoogleStrictToolSampling: typeof import('@earendil-works/pi-ai/api/google-shared')['supportsGoogleStrictToolSampling']\n /** A new event stream for the transport to push the assistant message into. */\n createAssistantMessageEventStream: typeof import('@earendil-works/pi-ai')['createAssistantMessageEventStream']\n /** Keeps the leading system message and drops later ones, for an API without mid-conversation system messages. */\n collapseSystemMessages: typeof import('@earendil-works/pi-ai')['collapseSystemMessages']\n /** The transcript's leading system message, if any. */\n getInitialSystemMessage: typeof import('@earendil-works/pi-ai')['getInitialSystemMessage']\n /** Tools in effect after every transcript delta is applied. */\n getCurrentTools: typeof import('@earendil-works/pi-ai')['getCurrentTools']\n /** A system message rendered as a full prompt: content, then sections. */\n getSystemMessageText: typeof import('@earendil-works/pi-ai')['getSystemMessageText']\n /** Cost of a usage record at the model's prices. */\n calculateCost: typeof import('@earendil-works/pi-ai')['calculateCost']\n /** The level if the model supports it, else the next higher supported one, else the next lower. */\n clampThinkingLevel: typeof import('@earendil-works/pi-ai')['clampThinkingLevel']\n}\n\n/**\n * Load the {@link GoogleWireKit} from the HOST's pi-ai. An extension's\n * transport gets it through `zidane/providers` (mapped to the host's module)\n * instead of importing pi-ai itself: one pi-ai copy, the exact wire the\n * host's pi-ai speaks, and it resolves inside compiled binaries too. pi-ai's\n * bare specifiers can't be host-mapped the way `zidane` is: the mapping's\n * loader would re-import the specifier it intercepts. Loaded on first call,\n * since `@google/genai` comes with it.\n */\nexport async function loadGoogleWireKit(): Promise<GoogleWireKit> {\n const [shared, core] = await Promise.all([\n import('@earendil-works/pi-ai/api/google-shared'),\n import('@earendil-works/pi-ai'),\n ])\n return {\n convertMessages: shared.convertMessages,\n convertTools: shared.convertTools,\n isThinkingPart: shared.isThinkingPart,\n retainThoughtSignature: shared.retainThoughtSignature,\n requiresToolCallId: shared.requiresToolCallId,\n mapStopReasonString: shared.mapStopReasonString,\n resolveGoogleFunctionCallingMode: shared.resolveGoogleFunctionCallingMode,\n supportsGoogleStrictToolSampling: shared.supportsGoogleStrictToolSampling,\n createAssistantMessageEventStream: core.createAssistantMessageEventStream,\n collapseSystemMessages: core.collapseSystemMessages,\n getInitialSystemMessage: core.getInitialSystemMessage,\n getCurrentTools: core.getCurrentTools,\n getSystemMessageText: core.getSystemMessageText,\n calculateCost: core.calculateCost,\n clampThinkingLevel: core.clampThinkingLevel,\n }\n}\n\nasync function loadGeminiApi(): Promise<GoogleStreams> {\n return (await import('@earendil-works/pi-ai/api/google-generative-ai')) as unknown as GoogleStreams\n}\nasync function loadVertexApi(): Promise<GoogleStreams> {\n return (await import('@earendil-works/pi-ai/api/google-vertex')) as unknown as GoogleStreams\n}\n\n/** Options for {@link google}. */\nexport interface GoogleParams extends GoogleSharedParams {\n /** Gemini API key. Defaults to `GEMINI_API_KEY`, then `GOOGLE_API_KEY`. */\n apiKey?: string\n}\n\n/**\n * Creates the Google Gemini provider on the Gemini API (Google AI Studio).\n * Authenticates with `apiKey`, else `GEMINI_API_KEY`, else `GOOGLE_API_KEY`.\n *\n * @param params - API key, default model, capabilities and extra headers.\n *\n * @example\n * ```ts\n * import { createAgent } from 'zidane'\n * import { google } from 'zidane/providers/google'\n *\n * const agent = createAgent({\n * provider: google({ apiKey: process.env.GEMINI_API_KEY }),\n * })\n * await agent.run({ prompt: 'Say hello.' })\n * ```\n */\nexport function google(params?: GoogleParams): Provider {\n return createGoogleProvider({\n name: 'google',\n load: loadGeminiApi,\n isOAuth: false,\n auth: () => {\n const apiKey = params?.apiKey || process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY\n if (!apiKey)\n throw new Error('No Gemini API key found. Set GEMINI_API_KEY, or add a key in the Google Gemini provider settings.')\n return { apiKey }\n },\n }, params)\n}\n\n/** Options for {@link googleVertex}. */\nexport interface GoogleVertexParams extends GoogleSharedParams {\n /**\n * Vertex AI API key (express mode). Defaults to `GOOGLE_CLOUD_API_KEY`.\n * Without one, requests authenticate with Google Cloud credentials.\n */\n apiKey?: string\n /** Google Cloud project. Defaults to `GOOGLE_CLOUD_PROJECT`, then `GCLOUD_PROJECT`. */\n project?: string\n /** Vertex AI location. Defaults to `GOOGLE_CLOUD_LOCATION`, then `global`. */\n location?: string\n /**\n * Service-account or authorized-user credentials file. Defaults to\n * `GOOGLE_APPLICATION_CREDENTIALS`, then gcloud's Application Default\n * Credentials (`gcloud auth application-default login`).\n */\n credentialsFile?: string\n /**\n * Run on one stored \"Sign in with Google\" account (its stable id) rather\n * than the active one. See {@link OAuthParams.account}.\n */\n account?: OAuthParams['account']\n}\n\n/** The fields a \"Sign in with Google\" grant carries beyond the token triple. */\ninterface VertexGrant {\n refresh: string\n projectId: string\n clientId: string\n clientSecret: string\n}\n\nconst VERTEX_DIR_PREFIX = 'zidane-vertex-'\nconst VERTEX_DIR_RE = /^zidane-vertex-[A-Za-z0-9]{6}$/\n/** Older than any request: its process crashed or was killed before cleanup. */\nconst STALE_VERTEX_DIR_MS = 60 * 60 * 1000\nlet nextVertexSweepAt = 0\n\n/**\n * Remove this user's credentials dirs that a crashed request left behind;\n * they hold a refresh token. Listing the temp dir can take hundreds of\n * milliseconds, so it runs in the background, at most once an hour.\n */\nfunction sweepStaleVertexDirs(): void {\n const now = Date.now()\n if (now < nextVertexSweepAt)\n return\n nextVertexSweepAt = now + STALE_VERTEX_DIR_MS\n const root = tmpdir()\n const uid = process.getuid?.()\n const sweepOne = async (name: string): Promise<void> => {\n const dir = join(root, name)\n const stat = await lstat(dir)\n if (stat.isDirectory() && (uid === undefined || stat.uid === uid) && now - stat.mtimeMs > STALE_VERTEX_DIR_MS)\n await rm(dir, { recursive: true, force: true })\n }\n // Best effort: a dir removed concurrently, or not ours to remove, is skipped.\n void readdir(root)\n .then(names => Promise.allSettled(names.filter(name => VERTEX_DIR_RE.test(name)).map(sweepOne)))\n .catch(() => {})\n}\n\n/**\n * Request auth from the stored \"Sign in with Google\" grant (the pinned\n * account's, else the active one), or `undefined` when none is stored.\n *\n * The access token rotates through zidane's OAuth path (cross-process locks,\n * persistence, refresh hooks, a clear \"sign in again\" for a revoked grant).\n * Vertex itself authenticates from an `authorized_user` credentials file\n * holding the refresh token: pi-ai's Vertex client takes no bare access\n * token. The file lives in a private temp dir for the length of the request.\n */\nasync function signedInAuth(\n params: GoogleVertexParams | undefined,\n callbacks: StreamCallbacks | undefined,\n): Promise<GoogleRequestAuth | undefined> {\n const account = params?.account\n const read = () => account\n ? readAccountOAuthCredential(GOOGLE_VERTEX_OAUTH_ID, account)\n : readOAuthCredentials()[GOOGLE_VERTEX_OAUTH_ID]\n if (!read()) {\n if (account)\n throw new Error(pinnedAccountMissingError('google-vertex'))\n return undefined\n }\n await resolveOAuthApiKey({\n provider: 'google-vertex',\n providerId: GOOGLE_VERTEX_OAUTH_ID,\n ...(account ? { params: { account } } : {}),\n missingError: 'No Google sign-in found for Vertex AI. Sign in with Google again.',\n refreshError: reason => `Google sign-in refresh failed. Sign in with Google again. ${reason}`,\n }, callbacks)\n const grant = read() as Partial<VertexGrant> | undefined\n if (!grant?.refresh || !grant.clientId || !grant.clientSecret || !grant.projectId)\n throw new Error('This Google sign-in is missing its OAuth client or project. Sign in with Google again.')\n\n const project = params?.project || grant.projectId\n sweepStaleVertexDirs()\n const dir = mkdtempSync(join(tmpdir(), VERTEX_DIR_PREFIX))\n const file = join(dir, 'credentials.json')\n try {\n writeFileSync(file, JSON.stringify({\n type: 'authorized_user',\n client_id: grant.clientId,\n client_secret: grant.clientSecret,\n refresh_token: grant.refresh,\n quota_project_id: project,\n }), { mode: 0o600 })\n }\n catch (err) {\n rmSync(dir, { recursive: true, force: true })\n throw err\n }\n return {\n env: {\n GOOGLE_CLOUD_PROJECT: project,\n GOOGLE_CLOUD_LOCATION: params?.location || process.env.GOOGLE_CLOUD_LOCATION || 'global',\n GOOGLE_APPLICATION_CREDENTIALS: file,\n },\n dispose: () => rmSync(dir, { recursive: true, force: true }),\n }\n}\n\n/**\n * Credentials and settings for a Vertex AI request, read per turn so a\n * credential configured after the provider was built still applies. In\n * order: a pinned account's sign-in, a Vertex API key, the active \"Sign in\n * with Google\" grant, then Google Cloud credentials for the project.\n *\n * @param params - Explicit settings; environment variables fill the rest.\n * @param callbacks - Stream callbacks, for the OAuth refresh hook.\n */\nexport async function resolveVertexAuth(params?: GoogleVertexParams, callbacks?: StreamCallbacks): Promise<GoogleRequestAuth> {\n if (params?.account)\n return (await signedInAuth(params, callbacks))!\n const apiKey = params?.apiKey || process.env.GOOGLE_CLOUD_API_KEY\n if (apiKey)\n return { apiKey }\n const signedIn = await signedInAuth(params, callbacks)\n if (signedIn)\n return signedIn\n const project = params?.project || process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT\n if (!project)\n throw new Error('Vertex AI needs a Google Cloud project. Set GOOGLE_CLOUD_PROJECT, or configure it in the Google Vertex AI provider settings.')\n const location = params?.location || process.env.GOOGLE_CLOUD_LOCATION || 'global'\n const credentialsFile = params?.credentialsFile || process.env.GOOGLE_APPLICATION_CREDENTIALS\n return {\n env: {\n GOOGLE_CLOUD_PROJECT: project,\n GOOGLE_CLOUD_LOCATION: location,\n ...(credentialsFile ? { GOOGLE_APPLICATION_CREDENTIALS: credentialsFile } : {}),\n },\n }\n}\n\n/**\n * Creates the Google Vertex AI provider. Authenticates with a pinned\n * `account`'s Google sign-in, else a Vertex API key (`apiKey` or\n * `GOOGLE_CLOUD_API_KEY`), else the active \"Sign in with Google\" grant, else\n * Google Cloud credentials for `project` in `location`. See\n * {@link resolveVertexAuth}.\n *\n * @param params - Credentials, project, location, default model, capabilities and extra headers.\n *\n * @example\n * ```ts\n * import { createAgent } from 'zidane'\n * import { googleVertex } from 'zidane/providers/google'\n *\n * // After `gcloud auth application-default login`:\n * const agent = createAgent({\n * provider: googleVertex({ project: 'my-project' }),\n * })\n * await agent.run({ prompt: 'Say hello.' })\n * ```\n */\nexport function googleVertex(params?: GoogleVertexParams): Provider {\n return createGoogleProvider({\n name: 'google-vertex',\n load: loadVertexApi,\n isOAuth: !!params?.account || !(params?.apiKey || process.env.GOOGLE_CLOUD_API_KEY),\n auth: callbacks => resolveVertexAuth(params, callbacks),\n }, params)\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"xai.js","names":[],"sources":["../../src/providers/xai.ts"],"sourcesContent":["import type { Provider, ProviderCapabilities, StreamCallbacks, StreamOptions, TurnResult } from '.'\nimport type { OAuthParams } from './oauth'\nimport { XAI_OAUTH_PROVIDER_ID, xaiBaseUrl } from '../chat/oauth-page/xai'\nimport { extractRuntimeCredentials, isOAuthAccessToken, resolveOAuthApiKey } from './oauth'\nimport { openaiCompat } from './openai-compat'\n\nconst DEFAULT_MODEL = 'grok-4.6'\n\n/** Options for {@link xai}. */\nexport interface XaiParams extends OAuthParams {\n /**\n * Model used when a request does not set one.\n * @default 'grok-4.6'\n */\n defaultModel?: string\n /**\n * Provider capability flags. Grok models are vision-capable; default\n * `{ vision: true, imageInToolResult: false }`. Override for text-only\n * deployments.\n */\n capabilities?: ProviderCapabilities\n /** Extra HTTP headers sent on every request. */\n extraHeaders?: Record<string, string>\n}\n\n/**\n * xAI Grok provider — supports both a static API key (`XAI_API_KEY`) and the\n * SuperGrok / X Premium+ OAuth subscription.\n *\n * Both auth modes hit the same OpenAI-compatible endpoint (`https://api.x.ai/v1`\n * unless `XAI_BASE_URL` or `PI_XAI_BASE_URL` overrides it),\n * so the wire handling is entirely {@link openaiCompat}. The only difference is\n * the bearer:\n *\n * - **API key**: `XAI_API_KEY` (or `params.apiKey`) → used verbatim.\n * - **OAuth**: no static key → {@link resolveOAuthApiKey} resolves + lazily\n * refreshes the stored `xai-oauth` token on every turn.\n *\n * `resolveOAuthApiKey` unifies the two: a real API key in `XAI_API_KEY` is\n * returned as-is, while an OAuth access token (or no env value at all) falls\n * through to the refreshable stored credentials. So this single factory serves\n * both paths without branching at construction time.\n *\n * @param params - API key or OAuth credentials, default model, capabilities and extra headers.\n *\n * @example\n * ```ts\n * import { createAgent } from 'zidane'\n * import { xai } from 'zidane/providers/xai'\n *\n * const agent = createAgent({\n * provider: xai({ apiKey: process.env.XAI_API_KEY }),\n * })\n * await agent.run({ prompt: 'Say hello.' })\n * ```\n */\nexport function xai(params?: XaiParams): Provider {\n const defaultModel = params?.defaultModel || DEFAULT_MODEL\n const baseURL = xaiBaseUrl()\n const capabilities: ProviderCapabilities = params?.capabilities ?? {\n vision: true,\n imageInToolResult: false,\n }\n const baseCredentials = extractRuntimeCredentials(params)\n let runtimeCredentials = baseCredentials\n\n // Factory-time snapshot for the static `meta.isOAuth` display flag only (the\n // terminal header's `oauth`/`key` badge). The real bearer resolves per turn\n // in `stream`, so this is best-effort, mirroring anthropic's pattern. It's\n // OAuth unless a genuine static API key is present: a `xai-…` key → key mode;\n // runtime OAuth creds, a JWT access token, or no static key (stored creds\n // used) → oauth mode.\n // A pinned account is that account's OAuth grant, whatever the env holds.\n const staticKey = params?.apiKey ?? (params?.account ? undefined : process.env.XAI_API_KEY)\n const isOAuth = baseCredentials !== undefined || !staticKey || isOAuthAccessToken(staticKey)\n\n /**\n * Build the openai-compat delegate for a resolved bearer. Cheap — the factory\n * only wires closures — so we re-create it per turn with the freshly resolved\n * (possibly refreshed) OAuth token rather than baking a stale key in once.\n */\n function delegateFor(apiKey: string): Provider {\n return openaiCompat({\n name: 'xai',\n label: 'xAI',\n apiKey,\n baseURL,\n defaultModel,\n capabilities,\n extraHeaders: params?.extraHeaders,\n })\n }\n\n // A delegate built with a placeholder key supplies the non-stream methods\n // (formatTools, userMessage, message builders, classifyError). Only `stream`\n // resolves the real bearer, so the placeholder never reaches the wire.\n const skeleton = delegateFor('placeholder-resolved-at-stream')\n\n return {\n ...skeleton,\n name: 'xai',\n // Reuse the delegate's normalized capability flags (openaiCompat fills the\n // audio/video/documents defaults) so the advertised shape matches the wire.\n meta: { ...skeleton.meta, defaultModel, isOAuth },\n\n async stream(options: StreamOptions, callbacks: StreamCallbacks): Promise<TurnResult> {\n const apiKey = await resolveOAuthApiKey(\n {\n provider: 'xai',\n providerId: XAI_OAUTH_PROVIDER_ID,\n params: runtimeCredentials ? { ...params, ...runtimeCredentials } : params,\n envKey: 'XAI_API_KEY',\n missingError: 'No xAI credentials found. Set XAI_API_KEY or run `bun run auth --xai` first.',\n refreshError: reason => `xAI OAuth token refresh failed. Run \\`bun run auth --xai\\` again. ${reason}`,\n },\n {\n ...callbacks,\n async onOAuthRefresh(ctx) {\n // Keep param-sourced credentials current so a long-lived provider\n // instance reuses the rotated token instead of re-refreshing.\n if (ctx.source === 'params') {\n runtimeCredentials = {\n access: ctx.credentials.access,\n refresh: ctx.credentials.refresh,\n expires: ctx.credentials.expires,\n }\n }\n await callbacks.onOAuthRefresh?.(ctx)\n },\n },\n )\n\n return delegateFor(apiKey).stream(options, callbacks)\n },\n }\n}\n"],"mappings":";;;;AAMA,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDtB,SAAgB,IAAI,QAA8B;CAChD,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,UAAU,WAAW;CAC3B,MAAM,eAAqC,QAAQ,gBAAgB;EACjE,QAAQ;EACR,mBAAmB;CACrB;CACA,MAAM,kBAAkB,0BAA0B,MAAM;CACxD,IAAI,qBAAqB;CASzB,MAAM,YAAY,QAAQ,WAAW,QAAQ,UAAU,KAAA,IAAY,QAAQ,IAAI;CAC/E,MAAM,UAAU,oBAAoB,KAAA,KAAa,CAAC,aAAa,mBAAmB,SAAS;;;;;;CAO3F,SAAS,YAAY,QAA0B;EAC7C,OAAO,aAAa;GAClB,MAAM;GACN,OAAO;GACP;GACA;GACA;GACA;GACA,cAAc,QAAQ;EACxB,CAAC;CACH;CAKA,MAAM,WAAW,YAAY,gCAAgC;CAE7D,OAAO;EACL,GAAG;EACH,MAAM;EAGN,MAAM;GAAE,GAAG,SAAS;GAAM;GAAc;EAAQ;EAEhD,MAAM,OAAO,SAAwB,WAAiD;GA2BpF,OAAO,YAAY,MA1BE,mBACnB;IACE,UAAU;IACV,YAAY;IACZ,QAAQ,qBAAqB;KAAE,GAAG;KAAQ,GAAG;IAAmB,IAAI;IACpE,QAAQ;IACR,cAAc;IACd,eAAc,WAAU,qEAAqE;GAC/F,GACA;IACE,GAAG;IACH,MAAM,eAAe,KAAK;KAGxB,IAAI,IAAI,WAAW,UACjB,qBAAqB;MACnB,QAAQ,IAAI,YAAY;MACxB,SAAS,IAAI,YAAY;MACzB,SAAS,IAAI,YAAY;KAC3B;KAEF,MAAM,UAAU,iBAAiB,GAAG;IACtC;GACF,CACF,CAEyB,CAAC,CAAC,OAAO,SAAS,SAAS;EACtD;CACF;AACF"}
|