zidane 5.8.3 → 5.8.5

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.
Files changed (55) hide show
  1. package/dist/agent-CL4nT5Ti.d.ts.map +1 -1
  2. package/dist/chat.d.ts +2 -2
  3. package/dist/chat.js +2 -2
  4. package/dist/{errors-CoQnKRf1.js → errors-B-GeaKTX.js} +24 -2
  5. package/dist/{errors-CoQnKRf1.js.map → errors-B-GeaKTX.js.map} +1 -1
  6. package/dist/{fetch-url-CPxfiXDa.js → fetch-url-D0M3oft5.js} +2 -2
  7. package/dist/{fetch-url-CPxfiXDa.js.map → fetch-url-D0M3oft5.js.map} +1 -1
  8. package/dist/{headless-BfEQtRfX.js → headless-c7MDO-iF.js} +53 -31
  9. package/dist/headless-c7MDO-iF.js.map +1 -0
  10. package/dist/headless.d.ts +1 -1
  11. package/dist/headless.js +1 -1
  12. package/dist/{index-DdjlsREW.d.ts → index-BDMVtgHD.d.ts} +5 -1
  13. package/dist/{index-DdjlsREW.d.ts.map → index-BDMVtgHD.d.ts.map} +1 -1
  14. package/dist/index.d.ts +1 -1
  15. package/dist/index.js +10 -10
  16. package/dist/{interpolate-TySiqKzc.js → interpolate-CmcrnzDZ.js} +2 -2
  17. package/dist/{interpolate-TySiqKzc.js.map → interpolate-CmcrnzDZ.js.map} +1 -1
  18. package/dist/{login-Ck6dmcMH.js → login-DYQ6LgLP.js} +4 -4
  19. package/dist/{login-Ck6dmcMH.js.map → login-DYQ6LgLP.js.map} +1 -1
  20. package/dist/{mcp-Br3b1Xm3.js → mcp-adAkHM-0.js} +5 -2
  21. package/dist/mcp-adAkHM-0.js.map +1 -0
  22. package/dist/mcp.js +1 -1
  23. package/dist/{messages-CvRQTdbR.js → messages-Dhva-Ewy.js} +7 -2
  24. package/dist/messages-Dhva-Ewy.js.map +1 -0
  25. package/dist/{presets-DIweYdlN.js → presets-6SoIBrzL.js} +2 -2
  26. package/dist/{presets-DIweYdlN.js.map → presets-6SoIBrzL.js.map} +1 -1
  27. package/dist/presets.d.ts +1 -1
  28. package/dist/presets.js +1 -1
  29. package/dist/{providers-h4HJPbbv.js → providers-ByITfqRA.js} +119 -95
  30. package/dist/providers-ByITfqRA.js.map +1 -0
  31. package/dist/providers.js +2 -2
  32. package/dist/session/sqlite.js +1 -1
  33. package/dist/{session-BzLou2_-.js → session-7CKYn9qT.js} +2 -2
  34. package/dist/{session-BzLou2_-.js.map → session-7CKYn9qT.js.map} +1 -1
  35. package/dist/session.js +2 -2
  36. package/dist/skills.js +1 -1
  37. package/dist/tools/fetch-url.js +1 -1
  38. package/dist/tools/web-search.js +2 -2
  39. package/dist/{tools-DLRIhCl1.js → tools-DOUtulS5.js} +6 -6
  40. package/dist/{tools-DLRIhCl1.js.map → tools-DOUtulS5.js.map} +1 -1
  41. package/dist/tools.d.ts +1 -1
  42. package/dist/tools.js +1 -1
  43. package/dist/{transcript-anchors-Dc0WlxnA.js → transcript-anchors-B2h3qt3S.js} +9 -9
  44. package/dist/{transcript-anchors-Dc0WlxnA.js.map → transcript-anchors-B2h3qt3S.js.map} +1 -1
  45. package/dist/{transcript-anchors-BJpOyLPm.d.ts → transcript-anchors-DYsnGyel.d.ts} +2 -2
  46. package/dist/{transcript-anchors-BJpOyLPm.d.ts.map → transcript-anchors-DYsnGyel.d.ts.map} +1 -1
  47. package/dist/tui.d.ts +1 -1
  48. package/dist/tui.js +7 -7
  49. package/dist/types.d.ts +1 -1
  50. package/dist/types.js +1 -1
  51. package/package.json +1 -1
  52. package/dist/headless-BfEQtRfX.js.map +0 -1
  53. package/dist/mcp-Br3b1Xm3.js.map +0 -1
  54. package/dist/messages-CvRQTdbR.js.map +0 -1
  55. package/dist/providers-h4HJPbbv.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { c as classifyErrorPrelude, d as matchesContextExceeded, l as errorMessage, u as isRetryableHttpStatus } from "./errors-CoQnKRf1.js";
2
- import { C as fillEstimatedCost, S as sanitizeToolSpecs, b as userMessage, d as toAnthropic, h as assistantMessage, j as splitSystemPrompt, k as renderSystemForWire, l as fromAnthropic, v as openaiCompat, y as toolResultsMessage } from "./messages-CvRQTdbR.js";
1
+ import { c as classifyErrorPrelude, d as matchesContextExceeded, f as matchesToolPairingError, l as errorMessage, u as isRetryableHttpStatus } from "./errors-B-GeaKTX.js";
2
+ import { C as fillEstimatedCost, S as sanitizeToolSpecs, b as userMessage, d as toAnthropic, h as assistantMessage, j as splitSystemPrompt, k as renderSystemForWire, l as fromAnthropic, n as SYNTHETIC_TOOL_RESULT_PLACEHOLDER, v as openaiCompat, y as toolResultsMessage } from "./messages-Dhva-Ewy.js";
3
3
  import { dirname, resolve } from "node:path";
4
4
  import { getModel } from "@earendil-works/pi-ai";
5
5
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
@@ -586,25 +586,6 @@ function matchSseErrorEvent(message) {
586
586
  }
587
587
  }
588
588
  /**
589
- * Phrasings Anthropic uses for the wire-level `tool_use` / `tool_result`
590
- * adjacency rejection. The local pre-send pairing repair
591
- * ({@link ensureToolResultPairing}) should catch every corruption mode
592
- * before the request leaves the harness — but a 400 still slipping
593
- * through is the canonical "the harness's defenses failed" signal, so
594
- * surface it as a typed `tool_pairing_corruption` error rather than a
595
- * generic provider_error.
596
- */
597
- const TOOL_PAIRING_ERROR_PATTERNS = [
598
- /tool_use[^a-z0-9]+ids?[^a-z0-9]+were[^a-z0-9]+found[^a-z0-9]+without[^a-z0-9]+tool_result/i,
599
- /tool_result[^a-z0-9]+must[^a-z0-9]+be[^a-z0-9]+preceded[^a-z0-9]+by[^a-z0-9]+a[^a-z0-9]+tool_call/i,
600
- /unexpected[^a-z0-9]+tool_result[^a-z0-9]+block/i,
601
- /tool_use[^a-z0-9]+block.*requires.*tool_result/i
602
- ];
603
- function matchesToolPairingError(message) {
604
- if (typeof message !== "string" || message.length === 0) return false;
605
- return TOOL_PAIRING_ERROR_PATTERNS.some((re) => re.test(message));
606
- }
607
- /**
608
589
  * Classify an Anthropic SDK / HTTP error for typed-error wrapping.
609
590
  *
610
591
  * - `prompt is too long` (400 invalid_request_error) → `context_exceeded`.
@@ -1247,87 +1228,125 @@ function formatTools(tools) {
1247
1228
  parameters: t.inputSchema
1248
1229
  }));
1249
1230
  }
1231
+ function piToolResultMessage(result, toolName = "") {
1232
+ const content = typeof result.output === "string" ? [{
1233
+ type: "text",
1234
+ text: result.output
1235
+ }] : result.output.map((block) => block.type === "image" ? {
1236
+ type: "image",
1237
+ data: block.data,
1238
+ mimeType: block.mediaType
1239
+ } : {
1240
+ type: "text",
1241
+ text: block.text
1242
+ });
1243
+ return {
1244
+ role: "toolResult",
1245
+ toolCallId: result.callId,
1246
+ toolName,
1247
+ content,
1248
+ isError: result.isError ?? false,
1249
+ timestamp: Date.now()
1250
+ };
1251
+ }
1252
+ function piUserMessage(content) {
1253
+ const textBlocks = content.filter((b) => b.type === "text");
1254
+ const imageBlocks = content.filter((b) => b.type === "image");
1255
+ if (imageBlocks.length === 0 && textBlocks.length === 0) return null;
1256
+ if (imageBlocks.length === 0 && textBlocks.length === 1) return {
1257
+ role: "user",
1258
+ content: textBlocks[0].text,
1259
+ timestamp: Date.now()
1260
+ };
1261
+ return {
1262
+ role: "user",
1263
+ content: [...imageBlocks.map((img) => ({
1264
+ type: "image",
1265
+ data: img.data,
1266
+ mimeType: img.mediaType
1267
+ })), ...textBlocks.map((block) => ({
1268
+ type: "text",
1269
+ text: block.text
1270
+ }))],
1271
+ timestamp: Date.now()
1272
+ };
1273
+ }
1274
+ function piAssistantMessage(content, modelId) {
1275
+ const piContent = [];
1276
+ for (const block of content) if (block.type === "text") piContent.push({
1277
+ type: "text",
1278
+ text: block.text
1279
+ });
1280
+ else if (block.type === "thinking") {
1281
+ if (block.signatureProducer === "anthropic") continue;
1282
+ piContent.push({
1283
+ type: "thinking",
1284
+ thinking: block.text,
1285
+ thinkingSignature: block.signature
1286
+ });
1287
+ } else if (block.type === "tool_call") piContent.push({
1288
+ type: "toolCall",
1289
+ id: block.id,
1290
+ name: block.name,
1291
+ arguments: block.input
1292
+ });
1293
+ return {
1294
+ role: "assistant",
1295
+ content: piContent,
1296
+ api: "openai-codex-responses",
1297
+ provider: PROVIDER_ID,
1298
+ model: modelId,
1299
+ usage: emptyUsage(),
1300
+ stopReason: "stop",
1301
+ timestamp: Date.now()
1302
+ };
1303
+ }
1250
1304
  function toPiMessages(messages, modelId) {
1251
1305
  const out = [];
1252
- for (const msg of messages) {
1253
- const toolResults = msg.content.filter((b) => b.type === "tool_result");
1254
- if (toolResults.length > 0) {
1255
- for (const result of toolResults) {
1256
- const content = typeof result.output === "string" ? [{
1257
- type: "text",
1258
- text: result.output
1259
- }] : result.output.map((block) => block.type === "image" ? {
1260
- type: "image",
1261
- data: block.data,
1262
- mimeType: block.mediaType
1263
- } : {
1264
- type: "text",
1265
- text: block.text
1266
- });
1267
- out.push({
1268
- role: "toolResult",
1269
- toolCallId: result.callId,
1270
- toolName: "",
1271
- content,
1272
- isError: result.isError ?? false,
1273
- timestamp: Date.now()
1274
- });
1306
+ for (let i = 0; i < messages.length; i++) {
1307
+ const msg = messages[i];
1308
+ const toolCalls = msg.content.filter((b) => b.type === "tool_call");
1309
+ if (msg.role === "assistant" && toolCalls.length > 0) {
1310
+ const next = messages[i + 1];
1311
+ const nextToolResults = next?.role === "user" ? next.content.filter((b) => b.type === "tool_result") : [];
1312
+ const resultById = new Map(nextToolResults.map((result) => [result.callId, result]));
1313
+ let assistantContent = [];
1314
+ for (const block of msg.content) {
1315
+ assistantContent.push(block);
1316
+ if (block.type !== "tool_call") continue;
1317
+ out.push(piAssistantMessage(assistantContent, modelId));
1318
+ assistantContent = [];
1319
+ const result = resultById.get(block.id);
1320
+ if (result) out.push(piToolResultMessage(result, block.name));
1321
+ else out.push(piToolResultMessage({
1322
+ type: "tool_result",
1323
+ callId: block.id,
1324
+ output: SYNTHETIC_TOOL_RESULT_PLACEHOLDER,
1325
+ isError: true
1326
+ }, block.name));
1275
1327
  }
1328
+ if (assistantContent.length > 0) out.push(piAssistantMessage(assistantContent, modelId));
1329
+ if (next?.role === "user") {
1330
+ const userMessage = piUserMessage(next.content.filter((block) => {
1331
+ if (block.type !== "tool_result") return true;
1332
+ return false;
1333
+ }));
1334
+ if (userMessage) out.push(userMessage);
1335
+ i++;
1336
+ }
1337
+ continue;
1338
+ }
1339
+ if (msg.content.filter((b) => b.type === "tool_result").length > 0) {
1340
+ const userMsg = msg.role === "user" ? piUserMessage(msg.content.filter((b) => b.type !== "tool_result")) : null;
1341
+ if (userMsg) out.push(userMsg);
1276
1342
  continue;
1277
1343
  }
1278
- const textBlocks = msg.content.filter((b) => b.type === "text");
1279
- const imageBlocks = msg.content.filter((b) => b.type === "image");
1280
1344
  if (msg.role === "user") {
1281
- if (imageBlocks.length === 0 && textBlocks.length === 1) {
1282
- out.push({
1283
- role: "user",
1284
- content: textBlocks[0].text,
1285
- timestamp: Date.now()
1286
- });
1287
- continue;
1288
- }
1289
- out.push({
1290
- role: "user",
1291
- content: [...imageBlocks.map((img) => ({
1292
- type: "image",
1293
- data: img.data,
1294
- mimeType: img.mediaType
1295
- })), ...textBlocks.map((block) => ({
1296
- type: "text",
1297
- text: block.text
1298
- }))],
1299
- timestamp: Date.now()
1300
- });
1345
+ const userMsg = piUserMessage(msg.content);
1346
+ if (userMsg) out.push(userMsg);
1301
1347
  continue;
1302
1348
  }
1303
- const content = [];
1304
- for (const block of msg.content) if (block.type === "text") content.push({
1305
- type: "text",
1306
- text: block.text
1307
- });
1308
- else if (block.type === "thinking") {
1309
- if (block.signatureProducer === "anthropic") continue;
1310
- content.push({
1311
- type: "thinking",
1312
- thinking: block.text,
1313
- thinkingSignature: block.signature
1314
- });
1315
- } else if (block.type === "tool_call") content.push({
1316
- type: "toolCall",
1317
- id: block.id,
1318
- name: block.name,
1319
- arguments: block.input
1320
- });
1321
- out.push({
1322
- role: "assistant",
1323
- content,
1324
- api: "openai-codex-responses",
1325
- provider: PROVIDER_ID,
1326
- model: modelId,
1327
- usage: emptyUsage(),
1328
- stopReason: "stop",
1329
- timestamp: Date.now()
1330
- });
1349
+ out.push(piAssistantMessage(msg.content, modelId));
1331
1350
  }
1332
1351
  return out;
1333
1352
  }
@@ -1418,6 +1437,11 @@ function classifyOpenAIError(err) {
1418
1437
  providerCode: code ?? "context_length_exceeded",
1419
1438
  message
1420
1439
  };
1440
+ if (matchesToolPairingError(message)) return {
1441
+ kind: "tool_pairing_corruption",
1442
+ providerCode: code ?? "invalid_request_error",
1443
+ message
1444
+ };
1421
1445
  if (message.length > 0) return {
1422
1446
  kind: "provider_error",
1423
1447
  providerCode: code,
@@ -1634,4 +1658,4 @@ function openrouter(params) {
1634
1658
  //#endregion
1635
1659
  export { createCursorOAuthProvider as a, anthropic as c, ANTHROPIC_EXTRA_MODELS as d, FAST_MODE_OPTIONS as f, cursor as i, applyAnthropicCacheBreakpoints as l, openai as n, generatePkce as o, local as r, cerebras as s, openrouter as t, writeFileAtomic as u };
1636
1660
 
1637
- //# sourceMappingURL=providers-h4HJPbbv.js.map
1661
+ //# sourceMappingURL=providers-ByITfqRA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers-ByITfqRA.js","names":["BASE_URL","getApiKey","DEFAULT_MODEL","getApiKey"],"sources":["../src/chat/anthropic-models.ts","../src/atomic-write.ts","../src/providers/oauth.ts","../src/providers/anthropic.ts","../src/providers/cerebras.ts","../src/chat/oauth-page/pkce.ts","../src/chat/oauth-page/cursor.ts","../src/providers/cursor.ts","../src/providers/local.ts","../src/providers/openai.ts","../src/providers/openrouter.ts"],"sourcesContent":["/**\n * Anthropic models not (yet) bundled in `@earendil-works/pi-ai`'s registry.\n *\n * pi-ai ships a static price/metadata registry that lags new Anthropic\n * releases by a dep bump. Until the bump lands, list freshly-shipped models\n * here so they show in the picker, expose the reasoning knob, and get an\n * accurate cost estimate. Entries are merged ahead of pi-ai's list in\n * {@link modelsForDescriptor} and de-duped by id, so once pi-ai catches up\n * the bundled entry simply wins.\n */\n\nimport type { ModelInfo, ModelOption } from './providers'\n\n/**\n * Anthropic \"fast mode\" — `speed: \"fast\"` on the Messages API. ~2.5× output\n * tokens/sec at a per-model price multiplier. Supported on Opus 4.6 / 4.7 / 4.8\n * only; the API errors if sent on any other model, so it's attached just to\n * those entries (see {@link FAST_MODE_OPTIONS}).\n *\n * The multiplier scales ALL rate components (input, output, and both cache\n * rates) uniformly: per Anthropic, \"prompt caching multipliers apply on top of\n * fast mode pricing\" across the full context window. Opus 4.8 is 2× ($5/$25 →\n * $10/$50); Opus 4.6 / 4.7 are a steeper 6× ($5/$25 → $30/$150).\n * See https://platform.claude.com/docs/en/build-with-claude/fast-mode.\n */\nexport const FAST_MODE_OPTION: ModelOption = {\n id: 'fast',\n label: 'Fast mode',\n description: '~2.5× faster output at premium pricing',\n costMultiplier: { input: 2, output: 2, cacheRead: 2, cacheWrite: 2 },\n}\n\nconst FAST_MODE_OPTION_LEGACY: ModelOption = {\n ...FAST_MODE_OPTION,\n description: '~2.5× faster output at 6× pricing',\n costMultiplier: { input: 6, output: 6, cacheRead: 6, cacheWrite: 6 },\n}\n\n/** Model ids that accept `speed: \"fast\"`, mapped to their fast-mode option. */\nexport const FAST_MODE_OPTIONS: Readonly<Record<string, ModelOption>> = {\n 'claude-opus-4-8': FAST_MODE_OPTION,\n 'claude-opus-4-7': FAST_MODE_OPTION_LEGACY,\n 'claude-opus-4-6': FAST_MODE_OPTION_LEGACY,\n}\n\n/**\n * The price multiplier to apply to a model's base rates when fast mode is\n * active, or `undefined` when the model has no fast-mode pricing (i.e. doesn't\n * support it). Mirrors {@link FAST_MODE_OPTIONS} — kept as a separate accessor\n * so the cost layer can stay decoupled from the picker-facing option objects.\n */\nexport function fastModeCostMultiplier(modelId: string): ModelOption['costMultiplier'] {\n return FAST_MODE_OPTIONS[modelId]?.costMultiplier\n}\n\n/**\n * Claude Opus 4.8 — shipped 2026-05-28. Same price/context/output as Opus 4.7\n * ($5/$25 per MTok, 1M context, 128k output), adaptive thinking, vision.\n * See https://www.anthropic.com/news/claude-opus-4-8.\n */\nexport const ANTHROPIC_EXTRA_MODELS: readonly ModelInfo[] = [\n {\n id: 'claude-opus-4-8',\n name: 'Claude Opus 4.8',\n reasoning: true,\n input: ['text', 'image'],\n cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },\n contextWindow: 1_000_000,\n maxTokens: 128_000,\n provider: 'anthropic',\n options: [FAST_MODE_OPTION],\n },\n]\n","/**\n * Synchronous atomic file write helper.\n *\n * Used by the chat-layer state / safelist / credentials / keybindings writers\n * and the OAuth credentials store. The pattern is always the same: write to a\n * sibling temp file, then `renameSync` over the target. `rename(2)` is atomic\n * on the same filesystem, so concurrent readers either see the previous file\n * or the new one — never a half-written intermediate. The temp suffix folds\n * `process.pid` + `Date.now()` so two writers in the same process can't pick\n * the same tmp path.\n *\n * `ensureDir` runs `mkdirSync(dirname(path), { recursive: true })` before\n * the write so callers don't have to repeat the boilerplate. `mode` is\n * forwarded to `writeFileSync` (e.g. `0o600` for credentials files).\n */\n\nimport { mkdirSync, renameSync, writeFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\n\nexport interface AtomicWriteOptions {\n /** When set, create the parent directory recursively before writing. */\n ensureDir?: boolean\n /** Forwarded to `writeFileSync` — typically `0o600` for credentials files. */\n mode?: number\n}\n\nexport function writeFileAtomic(\n path: string,\n contents: string,\n options: AtomicWriteOptions = {},\n): void {\n if (options.ensureDir)\n mkdirSync(dirname(path), { recursive: true })\n const tmp = `${path}.${process.pid}.${Date.now()}.tmp`\n writeFileSync(tmp, contents, options.mode !== undefined ? { mode: options.mode } : undefined)\n renameSync(tmp, path)\n}\n","import type { OAuthCredentials } from '@earendil-works/pi-ai/oauth'\nimport type { StreamCallbacks } from '.'\nimport type { OAuthRefreshHookContext } from '../types'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { getOAuthApiKey } from '@earendil-works/pi-ai/oauth'\nimport { writeFileAtomic } from '../atomic-write'\nimport { errorMessage } from '../errors'\n\n/**\n * Resolve the creds-file path at call time rather than module-load time.\n * Hosts that `chdir` between import and first OAuth use (test suites,\n * multi-project CLIs) previously got a stale path captured at import.\n *\n * Order:\n * 1. `ZIDANE_CREDENTIALS_PATH` — explicit override. The TUI sets this at\n * launch to point at `<storageDir>/credentials.json` so the harness\n * providers find the same file the TUI manages.\n * 2. `cwd/.credentials.json` — legacy default for `bun run auth` users\n * and library consumers who relied on the original location.\n */\nfunction credentialsFilePath(): string {\n return process.env.ZIDANE_CREDENTIALS_PATH ?? resolve(process.cwd(), '.credentials.json')\n}\n\n/**\n * POSIX mode for credentials on disk. Read+write for the owner only — refresh\n * tokens and API keys leak if the file is world-readable on a shared box.\n * Ignored on Windows.\n */\nconst CREDENTIALS_FILE_MODE = 0o600\n\n/**\n * In-process mutex table keyed by provider id. Concurrent `resolveOAuthApiKey`\n * calls for the same provider (typical when a host fans out multiple streams\n * at once) coalesce onto a single refresh. Without this, N concurrent calls\n * each hit `getOAuthApiKey`, producing N writes to `.credentials.json` with\n * last-write-wins semantics — and, in worst-case interleaving, a corrupted\n * file.\n */\nconst refreshLocks = new Map<string, Promise<string>>()\n\nexport interface OAuthParams {\n apiKey?: string\n access?: string\n refresh?: string\n expires?: number\n}\n\n/**\n * Pull a complete `{ access, refresh, expires }` triple out of provider params\n * when (and only when) all three OAuth fields are present and well-typed.\n * Returns `undefined` for the static-api-key path. Shared by the OAuth-capable\n * providers so the runtime-credential guard can't drift between them.\n */\nexport function extractRuntimeCredentials(\n params?: OAuthParams,\n): { access: string, refresh: string, expires: number } | undefined {\n if (\n typeof params?.access === 'string'\n && typeof params.refresh === 'string'\n && typeof params.expires === 'number'\n ) {\n return { access: params.access, refresh: params.refresh, expires: params.expires }\n }\n return undefined\n}\n\nexport interface ResolveOAuthApiKeyOptions<TParams extends OAuthParams = OAuthParams> {\n provider: string\n providerId: string\n params?: TParams\n envKey?: string\n extraCredentialKeys?: (keyof TParams & string)[]\n missingError: string\n refreshError: (reason: string) => string\n readCredentials?: () => Record<string, OAuthCredentials | undefined>\n writeCredentials?: (credentials: Record<string, OAuthCredentials | undefined>) => void\n getOAuthApiKey?: typeof getOAuthApiKey\n}\n\n/**\n * Read the shared credentials file.\n *\n * Returns `{}` when the file is missing OR when the file exists but is corrupted\n * / not valid JSON. Corrupt-file tolerance is important: the refresh-then-persist\n * path below writes atomically, but older builds wrote in place and could have\n * truncated the file on a crash. Treating corruption as \"no stored creds\" lets\n * users re-auth without manually deleting the file.\n *\n * Supports two on-disk shapes:\n * 1. **Legacy** (untagged): `{ \"anthropic\": { access, refresh, expires, ... } }`\n * — written by older `bun run auth`.\n * 2. **New** (kind-tagged): `{ \"anthropic\": { kind: 'oauth', access, refresh, expires, ... } }`\n * — written by the TUI. Entries with `kind: 'apikey'` are skipped — those\n * reach providers via env vars set at TUI launch (see `applyApiKeyEnv`).\n */\nexport function readOAuthCredentials(): Record<string, OAuthCredentials | undefined> {\n const path = credentialsFilePath()\n if (!existsSync(path))\n return {}\n\n try {\n const raw = readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw)\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))\n return {}\n const result: Record<string, OAuthCredentials | undefined> = {}\n for (const [key, value] of Object.entries(parsed)) {\n if (!value || typeof value !== 'object' || Array.isArray(value))\n continue\n const v = value as Record<string, unknown>\n // New schema: explicit `kind` tag.\n if (v.kind === 'apikey')\n continue\n // Both new (`kind: 'oauth'`) and legacy (untagged) entries have `access`;\n // the harmless `kind` field is allowed by `OAuthCredentials`'s\n // `[key: string]: unknown` index signature. Validate the required\n // fields explicitly so the assignment doesn't need a double-cast.\n if (\n typeof v.access === 'string'\n && typeof v.refresh === 'string'\n && typeof v.expires === 'number'\n ) {\n result[key] = { ...v, access: v.access, refresh: v.refresh, expires: v.expires }\n }\n }\n return result\n }\n catch {\n return {}\n }\n}\n\n/**\n * Atomically write `.credentials.json` with mode 0o600.\n *\n * Writes to a sibling temp file first, then renames. `rename(2)` is atomic on\n * the same filesystem, so readers either see the old file or the new one —\n * never a half-written one. This matters when a host has multiple processes\n * pointed at the same creds file.\n *\n * Merges the incoming OAuth entries on top of the raw file contents so that\n * entries this layer doesn't manage (e.g. `kind: 'apikey'` from the TUI\n * wizard) survive an OAuth refresh cycle. Without this merge,\n * `readOAuthCredentials` filters those entries out, and a naive overwrite\n * would delete them.\n */\nexport function writeOAuthCredentials(credentials: Record<string, OAuthCredentials | undefined>) {\n const path = credentialsFilePath()\n\n let existing: Record<string, unknown> = {}\n try {\n if (existsSync(path)) {\n const raw = readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw)\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))\n existing = parsed as Record<string, unknown>\n }\n }\n catch { /* corrupt file — start fresh */ }\n\n const merged = { ...existing, ...credentials }\n // Remove keys explicitly set to undefined (provider was deleted).\n for (const [key, value] of Object.entries(merged)) {\n if (value === undefined)\n delete merged[key]\n }\n\n writeFileAtomic(path, JSON.stringify(merged, null, 2), { mode: CREDENTIALS_FILE_MODE })\n}\n\nexport function credentialsFromParams<TParams extends OAuthParams>(params?: TParams, extraKeys: (keyof TParams & string)[] = []): OAuthCredentials | undefined {\n if (typeof params?.access !== 'string' || typeof params.refresh !== 'string' || typeof params.expires !== 'number')\n return undefined\n\n const extras = Object.fromEntries(\n extraKeys\n .map(key => [key, params[key]])\n .filter(([, value]) => value !== undefined),\n )\n\n return {\n access: params.access,\n refresh: params.refresh,\n expires: params.expires,\n ...extras,\n }\n}\n\nexport async function resolveOAuthApiKey<TParams extends OAuthParams>(\n options: ResolveOAuthApiKeyOptions<TParams>,\n callbacks?: Pick<StreamCallbacks, 'onOAuthRefresh'>,\n): Promise<string> {\n if (typeof options.params?.apiKey === 'string')\n return options.params.apiKey\n\n const paramsCredentials = credentialsFromParams(options.params, options.extraCredentialKeys)\n if (paramsCredentials) {\n return await withRefreshLock(\n `params:${options.providerId}`,\n () => resolveCredentialSource('params', paramsCredentials),\n )\n }\n\n if (typeof options.params?.access === 'string')\n return options.params.access\n\n if (options.envKey && process.env[options.envKey])\n return process.env[options.envKey]!\n\n const readCredentials = options.readCredentials ?? readOAuthCredentials\n const writeCredentials = options.writeCredentials ?? writeOAuthCredentials\n\n return await withRefreshLock(`file:${options.providerId}`, async () => {\n // Read under lock so we're always operating on the latest file state and\n // never interleave read/write against another concurrent resolve.\n const allCredentials = readCredentials()\n const storedCredentials = allCredentials[options.providerId]\n if (!storedCredentials)\n throw new Error(options.missingError)\n\n return await resolveCredentialSource('file', storedCredentials, allCredentials, writeCredentials)\n })\n\n async function resolveCredentialSource(\n source: OAuthRefreshHookContext['source'],\n current: OAuthCredentials,\n allCredentials?: Record<string, OAuthCredentials | undefined>,\n persistCredentials?: (credentials: Record<string, OAuthCredentials | undefined>) => void,\n ): Promise<string> {\n try {\n const refreshOAuthApiKey = options.getOAuthApiKey ?? getOAuthApiKey\n const result = await refreshOAuthApiKey(options.providerId, { [options.providerId]: current } as Record<string, OAuthCredentials>)\n if (!result)\n throw new Error(options.missingError)\n\n if (result.newCredentials !== current) {\n if (source === 'file' && allCredentials && persistCredentials) {\n allCredentials[options.providerId] = result.newCredentials\n persistCredentials(allCredentials)\n }\n\n await callbacks?.onOAuthRefresh?.({\n provider: options.provider,\n providerId: options.providerId,\n source,\n previousCredentials: { ...current },\n credentials: { ...result.newCredentials },\n })\n }\n\n return result.apiKey\n }\n catch (err) {\n throw new Error(options.refreshError(errorMessage(err)))\n }\n }\n}\n\n/**\n * Coalesce concurrent refresh calls onto a single in-flight promise per key.\n * The key combines the source (`params` vs `file`) and provider id, so a\n * per-agent param-only refresh does not starve a separate file-backed one.\n */\nasync function withRefreshLock(key: string, fn: () => Promise<string>): Promise<string> {\n const existing = refreshLocks.get(key)\n if (existing)\n return existing\n\n const task = (async () => {\n try {\n return await fn()\n }\n finally {\n refreshLocks.delete(key)\n }\n })()\n refreshLocks.set(key, task)\n return task\n}\n","// Type-only imports — erased at build time. Safe when the peer dep is not installed\n// at consume time; the types only need to resolve during Zidane's own build\n// (where `@anthropic-ai/sdk` is present as a devDependency).\nimport type Anthropic from '@anthropic-ai/sdk'\nimport type { Model } from '@anthropic-ai/sdk/resources'\nimport type { Provider, StreamCallbacks, ToolResult, ToolSpec, TurnResult } from '.'\nimport type { ClassifiedError } from '../errors'\nimport type { PromptPart, SessionContentBlock, SessionMessage, ThinkingLevel, TurnFinishReason } from '../types'\nimport type { OAuthParams } from './oauth'\nimport { fastModeCostMultiplier } from '../chat/anthropic-models'\nimport { classifyErrorPrelude, isRetryableHttpStatus, matchesContextExceeded, matchesToolPairingError } from '../errors'\nimport { fromAnthropic, toAnthropic } from '../session/messages'\nimport { renderSystemForWire, splitSystemPrompt } from '../system-prompt'\nimport { fillEstimatedCost } from './cost'\nimport { extractRuntimeCredentials, readOAuthCredentials, resolveOAuthApiKey } from './oauth'\nimport { sanitizeToolSpecs } from './schema-sanitize'\n\ntype AnthropicCtor = typeof Anthropic\ntype AnthropicInstance = InstanceType<AnthropicCtor>\n\n// Lazy-loaded SDK class. `@anthropic-ai/sdk` is an OPTIONAL peer dependency — the\n// module is only imported when the anthropic provider actually needs to open a\n// connection, so installing-without-using-it remains free for consumers who route\n// through other providers (openrouter, cerebras, openaiCompat, openai).\nlet _sdkCtor: AnthropicCtor | null = null\n\nasync function loadAnthropicSdk(): Promise<AnthropicCtor> {\n if (_sdkCtor)\n return _sdkCtor\n try {\n const mod = await import('@anthropic-ai/sdk')\n _sdkCtor = mod.default as unknown as AnthropicCtor\n return _sdkCtor\n }\n catch (err) {\n throw new Error(\n 'The `anthropic` provider requires the `@anthropic-ai/sdk` package, which is an optional peer dependency. '\n + 'Install it with your package manager (e.g. `bun add @anthropic-ai/sdk`).',\n err instanceof Error ? { cause: err } : undefined,\n )\n }\n}\n\n/**\n * Server-side context-management config — the body of `context_management` on\n * the Messages API. Typed loosely (Record-of-unknown) so we don't pin a specific\n * SDK schema version: the v0.90 SDK does not yet type this field, but the wire\n * format is stable behind the `context-management-2025-06-27` beta.\n *\n * See: https://docs.anthropic.com/en/docs/build-with-claude/context-management\n */\nexport interface AnthropicContextManagement {\n edits?: Array<Record<string, unknown>>\n [key: string]: unknown\n}\n\nexport interface AnthropicParams extends OAuthParams {\n defaultModel?: string\n /**\n * Optional override for the Anthropic SDK base URL. Honored end-to-end — headers and\n * routing pass through to the forwarded host. Useful for proxies (e.g. corporate\n * gateways, internal router).\n */\n baseURL?: string\n /**\n * Additional `anthropic-beta` flags to opt into. Merged with the OAuth-path\n * defaults (`claude-code-20250219`, `oauth-2025-04-20`); duplicates are\n * de-duped. Examples:\n *\n * - `'context-management-2025-06-27'` — server-side context compaction\n * (token-accurate; pair with {@link AnthropicParams.contextManagement}).\n * - `'token-efficient-tools-2026-03-28'` — terser tool_use wire format.\n * - `'interleaved-thinking-2025-05-14'` — think between tool calls within\n * one turn.\n * - `'redact-thinking-2026-02-12'` — replace large thinking blocks with\n * stubs server-side.\n * - `'prompt-caching-scope-2026-01-05'` — extended prompt-cache scope.\n *\n * Honored on both the OAuth and API-key paths.\n */\n extraBetas?: readonly string[]\n /**\n * Server-side context-management directive. Sent on the request body as\n * `context_management`. Requires the `context-management-2025-06-27` beta —\n * add it to {@link AnthropicParams.extraBetas}.\n *\n * Typed loosely so future Anthropic schema additions land without an SDK\n * bump. A typical compaction edit:\n *\n * ```ts\n * contextManagement: {\n * edits: [{\n * type: 'clear_tool_uses_20250919',\n * trigger: { type: 'input_tokens', value: 180_000 },\n * clear_at_least: { type: 'input_tokens', value: 140_000 },\n * clear_tool_inputs: ['Read', 'Bash', 'Grep'],\n * }],\n * }\n * ```\n */\n contextManagement?: AnthropicContextManagement\n /**\n * Generic pass-through for fields on the Messages API request body that the\n * SDK does not yet type. Spread into the request before the typed fields,\n * so explicit options ({@link AnthropicParams.contextManagement} and the\n * built-in fields like `model` / `tools` / `messages`) win on collision.\n *\n * Forward-compat escape hatch for new Anthropic betas — when a future flag\n * ships before zidane has a dedicated typed knob, set it here without\n * waiting on a release. Most fields will still need the matching beta in\n * {@link AnthropicParams.extraBetas}.\n */\n extraBodyParams?: Record<string, unknown>\n}\n\n/** Beta flags sent unconditionally on the OAuth path (Claude Code parity). */\nconst OAUTH_DEFAULT_BETAS = ['claude-code-20250219', 'oauth-2025-04-20'] as const\n\n/**\n * Beta flag that enables the `speed: \"fast\"` request field (fast mode — up to\n * 2.5× output tokens/sec on Opus 4.6/4.7/4.8 at premium pricing). Sent as an\n * `anthropic-beta` header only on requests that opt into fast mode; absent\n * otherwise so standard requests keep a byte-stable header for prompt caching.\n *\n * See: https://platform.claude.com/docs/en/build-with-claude/fast-mode\n */\nconst FAST_MODE_BETA = 'fast-mode-2026-02-01'\n\n/**\n * Build the `anthropic-beta` header value — OAuth defaults plus caller-supplied\n * extras, de-duped while preserving order. Returns `undefined` when no betas\n * apply (non-OAuth, no extras).\n */\nexport function resolveAnthropicBetas(\n isOAuth: boolean,\n extraBetas?: readonly string[],\n): string | undefined {\n const seen = new Set<string>()\n const out: string[] = []\n if (isOAuth) {\n for (const b of OAUTH_DEFAULT_BETAS) {\n if (!seen.has(b)) { seen.add(b); out.push(b) }\n }\n }\n if (extraBetas) {\n for (const b of extraBetas) {\n if (typeof b === 'string' && b.length > 0 && !seen.has(b)) {\n seen.add(b)\n out.push(b)\n }\n }\n }\n return out.length > 0 ? out.join(',') : undefined\n}\n\nfunction getConfiguredApiKey(anthropicParams?: AnthropicParams): string {\n if (anthropicParams?.apiKey)\n return anthropicParams.apiKey\n\n if (anthropicParams?.access)\n return anthropicParams.access\n\n if (process.env.ANTHROPIC_API_KEY)\n return process.env.ANTHROPIC_API_KEY\n\n // `readOAuthCredentials` tolerates a missing or corrupted file and returns `{}`\n // in both cases, so stale/half-written creds never crash agent construction.\n const access = readOAuthCredentials().anthropic?.access\n if (typeof access === 'string' && access.length > 0)\n return access\n\n throw new Error('No API key found. Run `bun run auth` first.')\n}\n\nfunction createClient(\n SDK: AnthropicCtor,\n apiKey: string,\n isOAuth: boolean,\n baseURL?: string,\n extraBetas?: readonly string[],\n): AnthropicInstance {\n const base = baseURL ? { baseURL } : {}\n const betaHeader = resolveAnthropicBetas(isOAuth, extraBetas)\n if (isOAuth) {\n const defaultHeaders: Record<string, string> = {\n 'anthropic-dangerous-direct-browser-access': 'true',\n 'user-agent': 'zidane/2.0.0',\n 'x-app': 'cli',\n }\n if (betaHeader)\n defaultHeaders['anthropic-beta'] = betaHeader\n return new SDK({\n apiKey: null,\n authToken: apiKey,\n dangerouslyAllowBrowser: true,\n defaultHeaders,\n ...base,\n })\n }\n // API-key path — only emit the beta header when the caller actually opted in.\n const defaultHeaders: Record<string, string> | undefined = betaHeader\n ? { 'anthropic-beta': betaHeader }\n : undefined\n return new SDK({\n apiKey,\n ...(defaultHeaders ? { defaultHeaders } : {}),\n ...base,\n })\n}\n\ntype BudgetedThinkingLevel = Exclude<ThinkingLevel, 'off' | 'adaptive'>\n\n/**\n * Map `ThinkingLevel` budgeted tiers to Anthropic's `output_config.effort`\n * enum. Anthropic exposes `low | medium | high | xhigh | max`; we surface the\n * three middle levels plus a `minimal` alias that collapses to `low` (the\n * closest equivalent — Anthropic does not have a sub-`low` tier).\n */\nconst EFFORT_FOR_LEVEL: Record<BudgetedThinkingLevel, 'low' | 'medium' | 'high'> = {\n minimal: 'low',\n low: 'low',\n medium: 'medium',\n high: 'high',\n}\n\n/**\n * Description of the Anthropic-side thinking configuration derived from a\n * ThinkingLevel. `null` means no thinking-related field should be set on the\n * request.\n *\n * Two shapes:\n * - `adaptive` — `thinking.type='adaptive'`. The model self-budgets per turn.\n * When `effort` is set, also emits `output_config.effort` to hint at the\n * level of reasoning the caller wants. This is the post-Claude-4.6 default\n * for level-based control and avoids the `thinking.type='enabled'`\n * deprecation warning. When `maxTokensCap` is set, the request builder\n * reduces `max_tokens` to `min(max_tokens, maxTokensCap)` — adaptive thinks\n * and replies inside one envelope, so capping the envelope soft-bounds the\n * thinking too.\n * - `enabled` — explicit-budget path: `thinking.type='enabled'` with an\n * explicit `budget_tokens`. `maxTokensBump` is added to the request's\n * `max_tokens` so the budget sits on top of the response cap. The only\n * way to pin a precise token budget; Anthropic emits a deprecation\n * warning for this shape on opus 4.6+, so we only route here when the\n * caller explicitly sets `behavior.thinkingBudget`.\n *\n * In both shapes Anthropic requires `temperature` to be `1`.\n */\nexport type AnthropicThinkingPlan\n = | { kind: 'enabled', budgetTokens: number, maxTokensBump: number }\n | { kind: 'adaptive', effort?: 'low' | 'medium' | 'high', maxTokensCap?: number }\n\n/**\n * Decide how to translate a `ThinkingLevel` into Anthropic's request shape.\n * Pure / synchronous — exported so tests can assert routing without standing\n * up the SDK.\n *\n * Routing rules:\n * - `'off'` → `null` (no thinking field, no effort hint).\n * - `'adaptive'` → adaptive thinking with no effort hint (model decides\n * everything). When `customBudget` is set, it is carried as `maxTokensCap`\n * so the request builder caps `max_tokens` accordingly — adaptive has no\n * native budget knob, but capping the response envelope soft-bounds the\n * thinking that lives inside it.\n * - `'minimal' | 'low' | 'medium' | 'high'` → adaptive thinking with an\n * `effort` hint, unless `customBudget` is provided.\n * - Any level + `customBudget` → explicit-budget `enabled` path. The caller\n * has opted into precise budget control and accepts the Anthropic\n * deprecation warning that comes with it on opus 4.6+. `'adaptive'` is the\n * sole exception: it never falls back to enabled, since adaptive is the\n * current Anthropic API surface for self-budgeted thinking.\n */\nexport function planAnthropicThinking(\n level: ThinkingLevel,\n customBudget?: number,\n): AnthropicThinkingPlan | null {\n if (level === 'off')\n return null\n if (level === 'adaptive') {\n if (typeof customBudget === 'number' && customBudget > 0)\n return { kind: 'adaptive', maxTokensCap: customBudget }\n return { kind: 'adaptive' }\n }\n if (customBudget !== undefined) {\n return { kind: 'enabled', budgetTokens: customBudget, maxTokensBump: customBudget }\n }\n return { kind: 'adaptive', effort: EFFORT_FOR_LEVEL[level] }\n}\n\n/**\n * Map Anthropic's native `stop_reason` to the zidane `TurnFinishReason` union.\n *\n * `pause_turn` and `model_context_window_exceeded` are 4.6+ stop reasons that\n * pre-Z21 collapsed to `'other'` and silently terminated the run. They now\n * map to `'pause'` and `'length'` respectively, and the surrounding caller\n * adjusts the `done` flag so the loop can recover.\n */\nfunction mapStopReason(stopReason: string | null | undefined): TurnFinishReason | undefined {\n if (!stopReason)\n return undefined\n switch (stopReason) {\n case 'end_turn':\n case 'stop_sequence':\n return 'stop'\n case 'tool_use':\n return 'tool-calls'\n case 'max_tokens':\n case 'model_context_window_exceeded':\n // 4.6+: response bumped against the model's context window mid-stream.\n // Treat as a length-class stop so consumers can prune + retry; the\n // partial assistant response is preserved.\n return 'length'\n case 'refusal':\n return 'content-filter'\n // 4.6+: server-side mid-turn pause for long thinking. The loop\n // continues with a synthetic continue message rather than terminating.\n case 'pause_turn':\n return 'pause'\n default:\n return 'other'\n }\n}\n\nconst EPHEMERAL: Anthropic.CacheControlEphemeral = { type: 'ephemeral' }\n\n/**\n * Mutate an Anthropic request in place to add cache breakpoints on the three\n * stable prefixes:\n * 1. System prompt — `cache_control` on the static prefix only (see below).\n * 2. Tool definitions — last tool.\n * 3. Conversation — last content block of the last message.\n *\n * Each breakpoint tells Anthropic to cache the prefix ending at that block;\n * subsequent turns reuse the cached prefix and pay only for the delta. Safe\n * no-op when any prefix is empty (no tools, empty system, etc.).\n *\n * System-prompt boundary handling (`SYSTEM_PROMPT_BOUNDARY`):\n *\n * - When `originalSystem` is provided AND carries the marker, the system\n * block is rewritten as a 2-block array: static (cached) then dynamic\n * (uncached). The caller is expected to have already stripped the marker\n * from `params.system` via {@link renderSystemForWire} — this helper\n * only re-splits to apply `cache_control` cleanly.\n * - When `originalSystem` is omitted or marker-free, the existing single-\n * block treatment applies: `cache_control` on the whole system string.\n * - Array system prompts: existing semantics — `cache_control` lands on the\n * last block. Callers building their own multi-block layout own the\n * breakpoint placement.\n */\nexport function applyAnthropicCacheBreakpoints(\n params: Anthropic.MessageCreateParamsStreaming,\n originalSystem?: string,\n): void {\n if (typeof params.system === 'string') {\n if (params.system.length > 0) {\n // `originalSystem` is the authoritative source for the boundary split\n // — `params.system` may have been pre-rendered by `renderSystemForWire`.\n // Fall back to `params.system` itself when no original was supplied\n // (or an empty original) so an external caller that embedded a marker\n // directly doesn't leak it into the cached block on the wire.\n const splitSource = originalSystem && originalSystem.length > 0\n ? originalSystem\n : params.system\n const parts = splitSystemPrompt(splitSource)\n if (parts.dynamic.length > 0) {\n const blocks: Anthropic.TextBlockParam[] = []\n if (parts.static.length > 0)\n blocks.push({ type: 'text', text: parts.static, cache_control: EPHEMERAL })\n blocks.push({ type: 'text', text: parts.dynamic })\n params.system = blocks\n }\n else {\n // No marker — wrap the (already marker-free) string in a single\n // cached block. `parts.static` equals `splitSource` in this branch.\n params.system = [{ type: 'text', text: parts.static, cache_control: EPHEMERAL }]\n }\n }\n }\n else if (Array.isArray(params.system) && params.system.length > 0) {\n const lastIdx = params.system.length - 1\n params.system = params.system.map((block, i) =>\n i === lastIdx ? { ...block, cache_control: EPHEMERAL } : block,\n )\n }\n\n if (params.tools && params.tools.length > 0) {\n const lastIdx = params.tools.length - 1\n params.tools = params.tools.map((tool, i) =>\n i === lastIdx ? { ...tool, cache_control: EPHEMERAL } : tool,\n ) as Anthropic.ToolUnion[]\n }\n\n if (params.messages.length === 0)\n return\n const lastMsgIdx = params.messages.length - 1\n const lastMsg = params.messages[lastMsgIdx]\n if (typeof lastMsg.content === 'string') {\n if (lastMsg.content.length === 0)\n return\n params.messages[lastMsgIdx] = {\n ...lastMsg,\n content: [{ type: 'text', text: lastMsg.content, cache_control: EPHEMERAL }],\n }\n return\n }\n if (!Array.isArray(lastMsg.content) || lastMsg.content.length === 0)\n return\n const blocks = lastMsg.content\n // `ThinkingBlockParam` and `RedactedThinkingBlockParam` do not accept `cache_control`\n // in the SDK types — walk backward past any trailing thinking blocks to find the\n // nearest cache-eligible block. Returns -1 when every block is a thinking variant,\n // which skips this breakpoint; system + tools still carry the cache prefix.\n let targetIdx = blocks.length - 1\n while (targetIdx >= 0 && isThinkingBlock(blocks[targetIdx]))\n targetIdx -= 1\n if (targetIdx < 0)\n return\n const nextBlocks = blocks.slice()\n nextBlocks[targetIdx] = { ...nextBlocks[targetIdx], cache_control: EPHEMERAL } as typeof nextBlocks[number]\n params.messages[lastMsgIdx] = { ...lastMsg, content: nextBlocks }\n}\n\nfunction isThinkingBlock(block: { type: string }): boolean {\n return block.type === 'thinking' || block.type === 'redacted_thinking'\n}\n\n/**\n * Duck-type check for an Anthropic SDK `APIError` — avoids a runtime dependency\n * on `@anthropic-ai/sdk` so `classifyError` stays usable even when the optional\n * peer dep isn't loaded (e.g. host code calling it on an unrelated provider's\n * error).\n *\n * Anthropic's APIError shape: `.status: number` + `.error` (parsed body, object\n * or null). Plain `Error`s don't have `.status` + `.error`.\n */\nfunction looksLikeAnthropicApiError(err: unknown): boolean {\n if (!err || typeof err !== 'object')\n return false\n const e = err as { status?: unknown, error?: unknown }\n return typeof e.status === 'number' && 'error' in e\n}\n\n/**\n * Anthropic SSE `error` event types that warrant a retry. `overloaded_error`\n * is the headline case (capacity event mid-stream); `api_error` and\n * `timeout_error` are both server-side transient failures. `invalid_request_error`,\n * `authentication_error`, `permission_error`, `not_found_error`, `billing_error`\n * are terminal — retrying them would just hammer a bad request.\n *\n * `rate_limit_error` here would be redundant: the SDK's pre-stream retry\n * handles 429, and a mid-stream `rate_limit_error` is exceedingly rare. We\n * include it anyway for symmetry with the HTTP-level retry policy.\n */\nconst SSE_RETRYABLE_ERROR_TYPES = new Set<string>([\n 'overloaded_error',\n 'api_error',\n 'timeout_error',\n 'rate_limit_error',\n])\n\n/**\n * Try to parse an Anthropic SSE `error` event payload out of a thrown error's\n * message. The SDK's `MessageStream` surfaces mid-stream error events by\n * throwing an `AnthropicError` whose `.message` contains the raw JSON shape:\n *\n * {\"type\":\"error\",\"error\":{\"type\":\"overloaded_error\",\"message\":\"Overloaded\"},\"request_id\":\"req_...\"}\n *\n * Returns the inner `{ type, message }` or `null` when the message isn't\n * the canonical SSE error shape. Tolerant: silently returns `null` for\n * non-string input, non-JSON content, or any shape mismatch.\n */\nfunction matchSseErrorEvent(message: unknown): { type: string, message: string } | null {\n if (typeof message !== 'string' || message.length === 0)\n return null\n // Cheap pre-check to avoid JSON.parse on every error message.\n if (!message.includes('\"type\":\"error\"') && !message.includes('\"type\": \"error\"'))\n return null\n // The message may be the JSON itself or have it embedded (some SDK paths\n // prefix a human prelude). Scan for the first `{` and try from there.\n const start = message.indexOf('{')\n if (start < 0)\n return null\n try {\n const parsed = JSON.parse(message.slice(start)) as unknown\n if (!parsed || typeof parsed !== 'object')\n return null\n const outer = parsed as { type?: unknown, error?: unknown }\n if (outer.type !== 'error' || !outer.error || typeof outer.error !== 'object')\n return null\n const inner = outer.error as { type?: unknown, message?: unknown }\n if (typeof inner.type !== 'string')\n return null\n return {\n type: inner.type,\n message: typeof inner.message === 'string' ? inner.message : inner.type,\n }\n }\n catch {\n return null\n }\n}\n\n/**\n * Classify an Anthropic SDK / HTTP error for typed-error wrapping.\n *\n * - `prompt is too long` (400 invalid_request_error) → `context_exceeded`.\n * - `'tool_use' ids were found without 'tool_result' blocks` /\n * `'tool_result must be preceded by a tool_call'` (400) →\n * `tool_pairing_corruption`. The local repair pass should have caught\n * this — the typed error tells consumers their pre-send pipeline is\n * shipping orphaned blocks somehow (custom `context:transform` hook,\n * bypassed loop, mid-stream session edit) so they can patch the root\n * cause instead of chasing 400s.\n * - Any other Anthropic `APIError`-shaped value → `provider_error` with the\n * native status/type code.\n * - Unknown errors → `null` (loop wraps in `AgentProviderError` generically).\n *\n * Anthropic's wire error shape is `{ type: 'error', error: { type, message } }` — the\n * SDK stores the parsed body on `err.error`. We walk both levels so callers see the\n * most specific `providerCode` we can find.\n */\nexport function classifyAnthropicError(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 interface InnerError { type?: string, message?: string }\n interface AnthError {\n name?: string\n message?: string\n status?: number\n error?: InnerError & { error?: InnerError }\n }\n const anyErr = err as AnthError\n\n // Mid-stream SSE error event — the SDK's `MessageStream` surfaces these by\n // throwing an `AnthropicError` (plain Error subclass, no `.status`) whose\n // `.message` carries the raw SSE error JSON, e.g.\n // `{\"type\":\"error\",\"error\":{\"type\":\"overloaded_error\",\"message\":\"Overloaded\"},\"request_id\":\"...\"}`.\n // The pre-stream HTTP retry inside the SDK can't help here — the response\n // already opened with a 200, then the server emitted `event: error`\n // mid-stream. Classify these so the loop-level retry kicks in.\n //\n // Guarded on `!looksLikeAnthropicApiError(err)` so we don't shadow the\n // structured `APIError` branch below (which also stringifies its body into\n // `.message` and would otherwise match this same pattern).\n if (!looksLikeAnthropicApiError(err)) {\n const sseError = matchSseErrorEvent(anyErr.message)\n if (sseError) {\n return {\n kind: 'provider_error',\n providerCode: sseError.type,\n message: sseError.message,\n retryable: SSE_RETRYABLE_ERROR_TYPES.has(sseError.type),\n }\n }\n return null\n }\n\n // Prefer the inner error when present (Anthropic's nested shape).\n const innerType = anyErr.error?.error?.type\n const outerType = anyErr.error?.type\n const nativeType = innerType && innerType !== 'error' ? innerType : outerType\n const message = anyErr.error?.error?.message\n ?? anyErr.error?.message\n ?? anyErr.message\n ?? ''\n\n if (matchesContextExceeded(message)) {\n return {\n kind: 'context_exceeded',\n providerCode: nativeType ?? 'invalid_request_error',\n message,\n }\n }\n\n if (matchesToolPairingError(message)) {\n return {\n kind: 'tool_pairing_corruption',\n providerCode: nativeType ?? 'invalid_request_error',\n message,\n }\n }\n\n const status = anyErr.status\n const retryable = typeof status === 'number'\n ? isRetryableHttpStatus(status)\n : undefined\n\n return {\n kind: 'provider_error',\n providerCode: nativeType ?? (status ? String(status) : undefined),\n message,\n ...(retryable !== undefined ? { retryable } : {}),\n }\n}\n\n/**\n * Build a user `SessionMessage` from multimodal prompt parts.\n *\n * - Text parts → text blocks.\n * - Image parts → base64 image blocks.\n * - Document parts with `encoding: 'text'` → inlined as a text block with an\n * `<attachment>` header so the model sees a clearly-delimited attachment.\n * - Document parts with `encoding: 'base64'` → serialized as an `<attachment\n * encoding=\"base64\">`-tagged text block. Native Anthropic document/PDF blocks\n * are not yet wired through the SessionContentBlock union, so consumers\n * needing true PDF ingestion should preprocess to text first.\n *\n * The format mirrors `defaultPromptMessage`'s output on shape — Anthropic-specific\n * handling differs only in that `promptMessage` being present tells the agent loop\n * to route PromptPart[] through this function rather than throwing on base64 docs.\n */\nfunction anthropicPromptMessage(parts: PromptPart[]): SessionMessage {\n const content: SessionContentBlock[] = []\n\n for (const part of parts) {\n if (part.type === 'text') {\n if (part.text.length > 0)\n content.push({ type: 'text', text: part.text })\n continue\n }\n\n if (part.type === 'image') {\n content.push({ type: 'image', mediaType: part.mediaType, data: part.data })\n continue\n }\n\n // document\n if (part.encoding === 'text') {\n const header = part.name\n ? `<attachment name=\"${part.name}\" media_type=\"${part.mediaType}\">`\n : `<attachment media_type=\"${part.mediaType}\">`\n content.push({ type: 'text', text: `${header}\\n${part.data}\\n</attachment>` })\n continue\n }\n\n // Base64 documents (e.g. PDF) — serialized as an attachment-tagged marker. The\n // Anthropic message converter (toAnthropic) does not yet map this to the native\n // document block; consumers needing PDF ingestion should preprocess to text for now.\n const header = part.name\n ? `<attachment name=\"${part.name}\" media_type=\"${part.mediaType}\" encoding=\"base64\">`\n : `<attachment media_type=\"${part.mediaType}\" encoding=\"base64\">`\n content.push({ type: 'text', text: `${header}\\n${part.data}\\n</attachment>` })\n }\n\n return { role: 'user', content }\n}\n\nexport function anthropic(\n anthropicParams?: AnthropicParams,\n): Provider {\n const configuredApiKey = getConfiguredApiKey(anthropicParams)\n const isOAuth = configuredApiKey.includes('sk-ant-oat')\n const defaultModel = anthropicParams?.defaultModel || 'claude-opus-4-8'\n let runtimeCredentials = extractRuntimeCredentials(anthropicParams)\n\n return {\n name: 'anthropic',\n meta: {\n defaultModel,\n isOAuth,\n capabilities: {\n vision: true,\n imageInToolResult: true,\n // Anthropic Messages API supports `web_search_20250305` as a\n // server-side tool — the model issues searches and consumes\n // results without a client-visible tool_use round-trip. The\n // canonical `web_search` `ToolDef` ships as a cross-provider\n // fallback; when this capability is set, `formatTools` rewrites\n // it to the server-tool wire shape and drops the function-tool\n // version so the model uses the native path.\n nativeWebSearch: { maxUses: 5 },\n },\n },\n\n formatTools(tools: ToolSpec[]): Anthropic.ToolUnion[] {\n // Sanitize before forwarding — Anthropic 400s on the strict shapes\n // (root `$ref`, root `oneOf|anyOf|allOf`, `type: ['object', 'null']`,\n // missing `properties`, `nullable: true`) that show up in MCP-server\n // schemas. The strict `anthropic` profile coerces those without\n // changing semantics for valid schemas. Warnings are de-duped to\n // `console.warn` so the same bad schema doesn't spam the log every\n // turn.\n //\n // `web_search` is special-cased: when present, it's emitted as the\n // server-tool `web_search_20250305` block and removed from the\n // function-tools list. The model invokes it without a client-side\n // round-trip; Anthropic injects the search results into the\n // assistant message directly. See the `nativeWebSearch` capability\n // declared above.\n const nativeWebSearch = this.meta.capabilities?.nativeWebSearch\n // `hasWebSearch` is the existence check; `fnTools` is the filtered\n // list. Computing existence via `tools.some` (rather than comparing\n // pre/post-filter lengths) makes the rewrite intent obvious at a\n // glance.\n const hasWebSearch = !!nativeWebSearch && tools.some(t => t.name === 'web_search')\n const fnTools = hasWebSearch ? tools.filter(t => t.name !== 'web_search') : tools\n const sanitized = sanitizeToolSpecs(fnTools, { profile: 'anthropic' })\n const out: Anthropic.ToolUnion[] = sanitized.map(t => ({\n name: t.name,\n description: t.description,\n input_schema: t.inputSchema as Anthropic.Tool['input_schema'],\n }))\n if (hasWebSearch && nativeWebSearch) {\n // `max_uses` is optional — omit when the capability doesn't pin a value\n // so Anthropic's server-side default applies.\n const block: Anthropic.WebSearchTool20250305 = {\n type: 'web_search_20250305',\n name: 'web_search',\n }\n if (typeof nativeWebSearch.maxUses === 'number')\n block.max_uses = nativeWebSearch.maxUses\n out.push(block)\n }\n return out\n },\n\n userMessage(content: string): SessionMessage {\n return { role: 'user', content: [{ type: 'text', text: content }] }\n },\n\n assistantMessage(content: string): SessionMessage {\n return { role: 'assistant', content: [{ type: 'text', text: content }] }\n },\n\n toolResultsMessage(results: ToolResult[]): SessionMessage {\n return {\n role: 'user',\n content: results.map(r => ({\n type: 'tool_result' as const,\n callId: r.id,\n output: r.content,\n ...(r.isError ? { isError: true as const } : {}),\n })),\n }\n },\n\n promptMessage: anthropicPromptMessage,\n\n classifyError: classifyAnthropicError,\n\n async countTokens(payload, signal): Promise<number | null> {\n try {\n const SDK = await loadAnthropicSdk()\n const apiKey = await resolveOAuthApiKey(\n {\n provider: 'anthropic',\n providerId: 'anthropic',\n params: runtimeCredentials ? { ...anthropicParams, ...runtimeCredentials } : anthropicParams,\n envKey: 'ANTHROPIC_API_KEY',\n missingError: 'No API key found. Run `bun run auth` first.',\n refreshError: reason => `Anthropic OAuth token refresh failed. ${reason}`,\n },\n )\n const client = createClient(\n SDK,\n apiKey,\n apiKey.includes('sk-ant-oat'),\n anthropicParams?.baseURL,\n anthropicParams?.extraBetas,\n )\n\n // Mirror `stream()`'s wire-payload build so the count matches what is\n // actually sent: OAuth folds the real system prompt into a synthetic\n // user/assistant pair and sends the canonical Claude Code prompt as\n // the system block.\n const wireSystem = renderSystemForWire(payload.system)\n const system = isOAuth\n ? `You are Claude Code, Anthropic's official CLI for Claude.`\n : wireSystem\n const messages: SessionMessage[] = isOAuth && payload.system\n ? [\n { role: 'user', content: [{ type: 'text' as const, text: wireSystem }] },\n { role: 'assistant', content: [{ type: 'text' as const, text: 'Understood. I will proceed with these instructions above the rest of my system prompt.' }] },\n ...payload.messages,\n ]\n : [...payload.messages]\n\n const res = await client.messages.countTokens(\n {\n model: payload.model as Model,\n system,\n tools: payload.tools as Anthropic.Tool[],\n messages: messages.map(m => toAnthropic(m)) as Anthropic.MessageParam[],\n },\n signal ? { signal } : undefined,\n )\n return res.input_tokens\n }\n catch (err) {\n // Unreachable under the active auth / network — caller falls back to\n // the heuristic. Surface the cause when debugging so a silent auth /\n // scope rejection (e.g. OAuth lacking the count endpoint) is visible.\n if (process.env.ZIDANE_DEBUG_COUNT)\n console.error('[anthropic.countTokens] failed:', err)\n return null\n }\n },\n\n async stream(options, callbacks: StreamCallbacks): Promise<TurnResult> {\n const SDK = await loadAnthropicSdk()\n const apiKey = await resolveOAuthApiKey(\n {\n provider: 'anthropic',\n providerId: 'anthropic',\n params: runtimeCredentials ? { ...anthropicParams, ...runtimeCredentials } : anthropicParams,\n envKey: 'ANTHROPIC_API_KEY',\n missingError: 'No API key found. Run `bun run auth` first.',\n refreshError: reason => `Anthropic OAuth token refresh failed. Run \\`bun run auth --anthropic\\` 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 }\n }\n await callbacks.onOAuthRefresh?.(ctx)\n },\n },\n )\n // Fast mode (`speed: \"fast\"`) is gated behind the `fast-mode-2026-02-01`\n // beta — without the header Anthropic rejects the body field with\n // `speed: Extra inputs are not permitted`. Inject it here (not in the\n // static default betas) so the header is present exactly when the request\n // will carry `speed: \"fast\"`, keeping non-fast requests byte-stable for\n // the prompt cache.\n const requestBetas = options.modelOptions?.fast\n ? [...(anthropicParams?.extraBetas ?? []), FAST_MODE_BETA]\n : anthropicParams?.extraBetas\n const client = createClient(\n SDK,\n apiKey,\n apiKey.includes('sk-ant-oat'),\n anthropicParams?.baseURL,\n requestBetas,\n )\n\n // System prompt injection is handled by agent.ts — we just pass it through.\n // For OAuth, the Claude Code API requires the system block to start with\n // the canonical Claude Code prompt — we prepend it to the real system prompt.\n // For OAuth, the CC API requires the system block to start with the canonical\n // Claude Code prompt. The real system prompt is injected as user+assistant messages.\n //\n // The boundary marker (`SYSTEM_PROMPT_BOUNDARY`) is structural metadata\n // for `applyAnthropicCacheBreakpoints`; strip it before the bytes hit\n // the wire so it never reaches the model. The original (un-rendered)\n // string is preserved as `options.system` and forwarded to the cache\n // helper below for an accurate static/dynamic split.\n const wireSystem = renderSystemForWire(options.system)\n const system = isOAuth\n ? `You are Claude Code, Anthropic's official CLI for Claude.`\n : wireSystem\n const messages: SessionMessage[] = isOAuth && options.system\n ? [\n { role: 'user', content: [{ type: 'text' as const, text: wireSystem }] },\n { role: 'assistant', content: [{ type: 'text' as const, text: 'Understood. I will proceed with these instructions above the rest of my system prompt.' }] },\n ...options.messages,\n ]\n : [...options.messages]\n const thinking = options.thinking ?? 'off'\n\n const modelId = options.model as Model\n\n // `context_management` is an untyped beta in SDK v0.90; widen `params` with\n // an optional field so we don't have to double-cast through `unknown` to\n // attach it below.\n const params: Anthropic.MessageCreateParamsStreaming & {\n context_management?: AnthropicContextManagement\n speed?: 'fast' | 'standard'\n } = {\n // Forward-compat escape hatch for un-typed beta fields. Spread first so\n // the typed core (model / max_tokens / system / tools / messages /\n // stream) and the explicit `context_management` below override on\n // collision — explicit always wins.\n ...((anthropicParams?.extraBodyParams ?? {}) as Record<string, unknown>),\n model: modelId,\n max_tokens: options.maxTokens,\n system,\n tools: options.tools as Anthropic.ToolUnion[],\n messages: messages.map(m => toAnthropic(m)) as Anthropic.MessageParam[],\n stream: true,\n }\n\n // Server-side context management (beta `context-management-2025-06-27`).\n // Skipped when the caller didn't pass a config — leaving the field off\n // the wire keeps requests valid on accounts that don't have the beta enabled.\n if (anthropicParams?.contextManagement)\n params.context_management = anthropicParams.contextManagement\n\n // Prompt caching — inject `cache_control: { type: 'ephemeral' }` breakpoints\n // on the three largest stable prefixes: system prompt, tool definitions, and\n // the last message's final content block. Three of Anthropic's four allowed\n // breakpoints; leaves headroom for a future thinking-block breakpoint.\n //\n // On the API-key path, `params.system` was derived from\n // `renderSystemForWire(options.system)` so the cache helper can split\n // the original on the `SYSTEM_PROMPT_BOUNDARY` marker and apply\n // `cache_control` to the static prefix only — per-turn churn in the\n // dynamic suffix no longer invalidates the cached doctrine above.\n //\n // On the OAuth path, `params.system` is the canonical Claude Code\n // prompt (`\"You are Claude Code...\"`) — `options.system` lives in the\n // injected user message instead, so we do NOT forward it here. Passing\n // it would replace the CC prompt with the user's doctrine. The user\n // message is still naturally cached via the last-message breakpoint\n // applied below; per-turn churn there bypasses the boundary feature on\n // OAuth, but parity with the pre-feature behavior is preserved.\n //\n // Skipped when `options.cache === false` (opt-out) or on any shape that would\n // produce an invalid request (empty system string, zero tools, empty message list).\n if (options.cache !== false)\n applyAnthropicCacheBreakpoints(params, isOAuth ? undefined : options.system)\n\n // Enable thinking / extended thinking when requested. The default path\n // for level-based control is `thinking.type='adaptive'` plus an\n // `output_config.effort` hint — Anthropic deprecated the explicit\n // `thinking.type='enabled' + budget_tokens` shape on opus 4.6+ and\n // recommends adaptive instead. Callers who need a precise token budget\n // can opt into the explicit-budget path by setting\n // `behavior.thinkingBudget`, accepting Anthropic's deprecation\n // warning in exchange. Either shape requires `temperature=1`.\n //\n // `display: 'summarized'` is set explicitly on both shapes — Opus 4.7\n // and Claude Mythos Preview silently flipped the default to\n // `'omitted'` (signature-only, no text), which makes the SDK fire\n // `thinking` deltas with empty `thinking` content and breaks every\n // host that surfaces traces live. Older models still default to\n // `'summarized'` so this is a no-op there.\n const plan = planAnthropicThinking(thinking, options.thinkingBudget)\n if (plan) {\n if (plan.kind === 'enabled') {\n params.thinking = { type: 'enabled', budget_tokens: plan.budgetTokens, display: 'summarized' }\n params.max_tokens = plan.maxTokensBump + params.max_tokens\n }\n else {\n params.thinking = { type: 'adaptive', display: 'summarized' }\n if (plan.effort)\n params.output_config = { effort: plan.effort }\n // Adaptive has no native budget knob — soft-cap the response envelope\n // (`max_tokens`) so unbounded thinking can't run away. Reduce only;\n // never raise above the caller's request.\n if (typeof plan.maxTokensCap === 'number' && plan.maxTokensCap > 0)\n params.max_tokens = Math.min(params.max_tokens, plan.maxTokensCap)\n }\n params.temperature = 1\n }\n\n // Fast mode (`speed: \"fast\"`) — ~2.5× output throughput at premium\n // pricing. Supported only on Opus 4.6 / 4.7 / 4.8; the model-options\n // surface only offers it on those, and Anthropic 400s a request with\n // `speed` on an unsupported model. `speed` is an untyped beta field in\n // SDK v0.90 (widened on `params` above).\n if (options.modelOptions?.fast)\n params.speed = 'fast'\n\n // Tool choice forcing\n if (options.toolChoice) {\n if (options.toolChoice.type === 'tool' && options.toolChoice.name)\n params.tool_choice = { type: 'tool', name: options.toolChoice.name }\n else if (options.toolChoice.type === 'required')\n params.tool_choice = { type: 'any' }\n else\n params.tool_choice = { type: 'auto' }\n }\n\n const s = client.messages.stream(params, {\n signal: options.signal,\n })\n\n let text = ''\n\n s.on('text', (delta) => {\n text += delta\n callbacks.onText(delta)\n })\n\n if (callbacks.onThinking) {\n s.on('thinking', (delta) => {\n callbacks.onThinking!(delta)\n })\n }\n\n // Server-tool blocks (e.g. `web_search_20250305`) execute on Anthropic's\n // side and arrive in the assistant content stream — not via our tool\n // loop. The SDK fires `contentBlock` once per block as it closes, so\n // listen for the two we care about and dispatch generic callbacks.\n // Other block types (text, thinking, tool_use, …) have their own paths\n // above / in `finalMessage()` — ignored here to avoid double-emission.\n if (callbacks.onServerToolUse || callbacks.onServerToolResult) {\n s.on('contentBlock', (block) => {\n if (block.type === 'server_tool_use') {\n callbacks.onServerToolUse?.({\n id: block.id,\n name: block.name,\n input: (block.input as Record<string, unknown> | undefined) ?? {},\n })\n }\n else if (block.type === 'web_search_tool_result') {\n callbacks.onServerToolResult?.({\n toolUseId: block.tool_use_id,\n toolName: 'web_search',\n content: block.content,\n })\n }\n })\n }\n\n const response = await s.finalMessage()\n\n const toolCalls = response.content\n .filter((b): b is Anthropic.ToolUseBlock => b.type === 'tool_use')\n .map(b => ({ id: b.id, name: b.name, input: b.input as Record<string, unknown> }))\n\n const finishReason = mapStopReason(response.stop_reason)\n\n // `pause_turn` is *not* terminal — the loop has to inject a continue\n // message and run another turn. Without this branch, the previous\n // `toolCalls.length === 0` shortcut would mark the run done at the\n // pause and silently drop the work in flight.\n const isPause = response.stop_reason === 'pause_turn'\n\n return {\n assistantMessage: fromAnthropic({ role: 'assistant', content: response.content }),\n text,\n toolCalls,\n done: !isPause && (response.stop_reason === 'end_turn' || toolCalls.length === 0),\n usage: fillEstimatedCost({\n input: response.usage.input_tokens,\n output: response.usage.output_tokens,\n cacheCreation: response.usage.cache_creation_input_tokens ?? undefined,\n cacheRead: response.usage.cache_read_input_tokens ?? undefined,\n ...(finishReason ? { finishReason } : {}),\n modelId: response.model ?? (options.model as string),\n }, 'anthropic', options.modelOptions?.fast\n ? fastModeCostMultiplier(response.model ?? (options.model as string))\n : undefined),\n }\n },\n }\n}\n","import type { Provider, ProviderCapabilities } from '.'\nimport { openaiCompat } from './openai-compat'\n\nconst BASE_URL = 'https://api.cerebras.ai/v1'\n\nexport interface CerebrasParams {\n apiKey?: string\n defaultModel?: string\n /**\n * Provider capability flags. Cerebras currently serves text-only OSS models\n * (GLM, Llama-family, Qwen-family) — default: `{ vision: false, imageInToolResult: false }`.\n * Override when routing to a vision-capable deployment.\n */\n capabilities?: ProviderCapabilities\n}\n\nfunction getApiKey(params?: CerebrasParams): string {\n // Resolution order is intentionally aligned with `anthropic` + `openai` —\n // explicit params > env var > fail. Host code that composes providers from\n // config (e.g. a YAML-driven CLI) relies on `params.apiKey` winning in all\n // providers, not just some.\n if (typeof params?.apiKey === 'string' && params.apiKey.length > 0)\n return params.apiKey\n\n if (process.env.CEREBRAS_API_KEY)\n return process.env.CEREBRAS_API_KEY\n\n throw new Error('No Cerebras API key found. Pass `apiKey` or set CEREBRAS_API_KEY in your environment.')\n}\n\n/**\n * Cerebras provider.\n *\n * Thin wrapper around {@link openaiCompat} with Cerebras-specific defaults\n * (base URL, default model).\n */\nexport function cerebras(params?: CerebrasParams): Provider {\n const apiKey = getApiKey(params)\n return openaiCompat({\n name: 'cerebras',\n apiKey,\n baseURL: BASE_URL,\n defaultModel: params?.defaultModel || 'zai-glm-4.7',\n capabilities: params?.capabilities ?? { vision: false, imageInToolResult: false },\n })\n}\n","/**\n * PKCE helper. Inlined here (rather than imported from pi-ai) because\n * `@earendil-works/pi-ai/oauth` does not re-export it, and we don't want\n * to reach into `node_modules/.../utils/oauth/pkce.js` — that's an\n * implementation-detail path that breaks on minor upstream rearrangements.\n *\n * Web Crypto API only. Works under Bun + Node 22+ without any node:crypto\n * import (matches pi-ai's own behavior). Output is base64url per RFC 7636.\n */\n\nfunction base64UrlEncode(bytes: Uint8Array): string {\n let binary = ''\n for (const byte of bytes)\n binary += String.fromCharCode(byte)\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n}\n\nexport interface PkcePair {\n /** Random verifier used in the token-exchange step. */\n verifier: string\n /** SHA-256(verifier) sent on the authorize URL. */\n challenge: string\n}\n\nexport async function generatePkce(): Promise<PkcePair> {\n const verifierBytes = new Uint8Array(32)\n crypto.getRandomValues(verifierBytes)\n const verifier = base64UrlEncode(verifierBytes)\n\n const data = new TextEncoder().encode(verifier)\n const hashBuffer = await crypto.subtle.digest('SHA-256', data)\n const challenge = base64UrlEncode(new Uint8Array(hashBuffer))\n\n return { verifier, challenge }\n}\n","/**\n * Cursor OAuth flow.\n *\n * Unlike Anthropic / OpenAI Codex (loopback-redirect PKCE), Cursor uses a\n * **poll-based** PKCE flow with no local callback server:\n *\n * 1. Generate a PKCE verifier + challenge and a random UUID.\n * 2. Open the browser to `cursor.com/loginDeepControl?challenge&uuid&mode&redirectTarget`.\n * 3. Poll `api2.cursor.sh/auth/poll?uuid&verifier` until tokens come back\n * (HTTP 404 = \"not ready yet\", keep polling with backoff).\n * 4. Refresh via `POST api2.cursor.sh/auth/exchange_user_api_key` with\n * `Authorization: Bearer <refresh>`.\n *\n * Token expiry is derived from the access token's JWT `exp` claim (minus a\n * 5-minute safety margin), falling back to +1h when the claim is missing.\n *\n * Flow adapted from https://github.com/ndraiman/pi-cursor-provider, itself\n * derived from https://github.com/ephraimduncan/opencode-cursor.\n *\n * Cursor's auth + inference protocol is unofficial and undocumented — re-verify\n * the endpoints/params below if login starts failing.\n */\n\nimport type {\n OAuthCredentials,\n OAuthLoginCallbacks,\n OAuthProviderInterface,\n} from '@earendil-works/pi-ai/oauth'\nimport { generatePkce } from './pkce'\n\n/** pi-ai / zidane OAuth provider id. Also the credentials-file key. */\nexport const CURSOR_OAUTH_PROVIDER_ID = 'cursor'\n\nconst CURSOR_LOGIN_URL = 'https://cursor.com/loginDeepControl'\nconst CURSOR_POLL_URL = 'https://api2.cursor.sh/auth/poll'\nconst CURSOR_REFRESH_URL = 'https://api2.cursor.sh/auth/exchange_user_api_key'\n\nconst POLL_MAX_ATTEMPTS = 150\nconst POLL_BASE_DELAY_MS = 1000\nconst POLL_MAX_DELAY_MS = 10_000\nconst POLL_BACKOFF_MULTIPLIER = 1.2\nconst POLL_MAX_CONSECUTIVE_ERRORS = 3\n\n/** Fallback lifetime when the JWT carries no `exp`. */\nconst DEFAULT_TOKEN_TTL_MS = 3600 * 1000\n/** Refresh slightly early so requests don't race expiry. */\nconst TOKEN_EXPIRY_SKEW_MS = 5 * 60 * 1000\n\ninterface CursorTokenResponse {\n accessToken: string\n refreshToken: string\n}\n\n/**\n * Derive expiry (epoch ms) from a JWT's `exp` claim, minus a safety skew.\n * Returns `now + 1h` for malformed tokens so a missing claim never wedges\n * refresh into an immediate-expire loop.\n */\nexport function cursorTokenExpiry(token: string): number {\n try {\n const parts = token.split('.')\n const payload = parts[1]\n if (parts.length !== 3 || !payload)\n return Date.now() + DEFAULT_TOKEN_TTL_MS\n\n const json = JSON.parse(atob(payload.replace(/-/g, '+').replace(/_/g, '/'))) as { exp?: unknown }\n if (typeof json.exp === 'number')\n return json.exp * 1000 - TOKEN_EXPIRY_SKEW_MS\n }\n catch {\n // fall through to default\n }\n return Date.now() + DEFAULT_TOKEN_TTL_MS\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise(r => setTimeout(r, ms))\n}\n\n/**\n * Poll Cursor's auth endpoint until login completes. `404` means the user\n * hasn't finished the browser flow yet; anything else non-2xx is a hard error.\n */\nasync function pollForTokens(\n uuid: string,\n verifier: string,\n callbacks: OAuthLoginCallbacks,\n): Promise<CursorTokenResponse> {\n let wait = POLL_BASE_DELAY_MS\n let consecutiveErrors = 0\n\n for (let attempt = 0; attempt < POLL_MAX_ATTEMPTS; attempt++) {\n if (callbacks.signal?.aborted)\n throw new Error('Cursor login aborted')\n\n await delay(wait)\n\n try {\n const url = `${CURSOR_POLL_URL}?uuid=${encodeURIComponent(uuid)}&verifier=${encodeURIComponent(verifier)}`\n const response = await fetch(url, { signal: callbacks.signal })\n\n if (response.status === 404) {\n consecutiveErrors = 0\n wait = Math.min(wait * POLL_BACKOFF_MULTIPLIER, POLL_MAX_DELAY_MS)\n continue\n }\n\n if (response.ok) {\n const data = await response.json() as Partial<CursorTokenResponse>\n if (!data.accessToken || !data.refreshToken)\n throw new Error(`Cursor poll response missing tokens: ${JSON.stringify(data)}`)\n return { accessToken: data.accessToken, refreshToken: data.refreshToken }\n }\n\n throw new Error(`Cursor poll failed (${response.status})`)\n }\n catch (err) {\n if (callbacks.signal?.aborted)\n throw new Error('Cursor login aborted')\n consecutiveErrors++\n if (consecutiveErrors >= POLL_MAX_CONSECUTIVE_ERRORS)\n throw err instanceof Error ? err : new Error(String(err))\n callbacks.onProgress?.('Waiting for Cursor login to complete…')\n }\n }\n\n throw new Error('Cursor authentication timed out')\n}\n\nexport async function loginCursor(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const { verifier, challenge } = await generatePkce()\n const uuid = crypto.randomUUID()\n\n const authUrl = new URL(CURSOR_LOGIN_URL)\n authUrl.searchParams.set('challenge', challenge)\n authUrl.searchParams.set('uuid', uuid)\n authUrl.searchParams.set('mode', 'login')\n authUrl.searchParams.set('redirectTarget', 'cli')\n\n callbacks.onAuth({\n url: authUrl.toString(),\n instructions: 'A browser window should open. Complete login in Cursor to finish.',\n })\n\n const tokens = await pollForTokens(uuid, verifier, callbacks)\n\n return {\n access: tokens.accessToken,\n refresh: tokens.refreshToken,\n expires: cursorTokenExpiry(tokens.accessToken),\n }\n}\n\nexport async function refreshCursorToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n const response = await fetch(CURSOR_REFRESH_URL, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${credentials.refresh}`,\n 'Content-Type': 'application/json',\n },\n body: '{}',\n })\n\n if (!response.ok) {\n const text = await response.text().catch(() => '')\n throw new Error(`Cursor token refresh failed (${response.status}): ${text || response.statusText}`)\n }\n\n const data = await response.json() as Partial<CursorTokenResponse>\n if (!data.accessToken)\n throw new Error(`Cursor token refresh response missing access token: ${JSON.stringify(data)}`)\n\n return {\n access: data.accessToken,\n // Cursor may omit a rotated refresh token — keep the existing one.\n refresh: data.refreshToken || credentials.refresh,\n expires: cursorTokenExpiry(data.accessToken),\n }\n}\n\n/**\n * Build a Cursor `OAuthProviderInterface`. Shape matches Anthropic / Codex so\n * it drops into `BUILTIN_PROVIDERS` and `src/auth.ts` unchanged.\n *\n * No `renderPage` parameter: Cursor's poll flow has no local callback server,\n * so there is no post-redirect page to theme.\n */\nexport function createCursorOAuthProvider(): OAuthProviderInterface {\n return {\n id: CURSOR_OAUTH_PROVIDER_ID,\n name: 'Cursor',\n usesCallbackServer: false,\n login: loginCursor,\n refreshToken: refreshCursorToken,\n getApiKey: credentials => credentials.access,\n }\n}\n","import type { Provider, StreamCallbacks } from '.'\nimport { CURSOR_OAUTH_PROVIDER_ID } from '../chat/oauth-page/cursor'\nimport { resolveOAuthApiKey } from './oauth'\nimport { openaiCompat } from './openai-compat'\n\n/**\n * Cursor provider (OAuth).\n *\n * Auth is fully wired: `bun run auth --cursor` (or the TUI wizard) logs in via\n * Cursor's poll-based PKCE flow and persists credentials; this provider resolves\n * + refreshes the OAuth token on every turn via {@link resolveOAuthApiKey}.\n *\n * Inference is **not** wired yet. Cursor does not expose an OpenAI-compatible\n * HTTP endpoint — it speaks a protobuf/Connect agent protocol over HTTP/2 to\n * `api2.cursor.sh`. Implementing `stream()` requires porting that transport\n * (generated protobuf schemas + an HTTP/2 streaming client) in-process, which\n * is intentionally left as a follow-up. Until then `stream()` resolves the\n * token (proving auth works) and then throws a clear, actionable error.\n *\n * The `openaiCompat` base supplies the message-format helpers (`formatTools`,\n * `userMessage`, `toolResultsMessage`, …) so the provider satisfies the full\n * `Provider` contract and slots into the registry; only `stream` is overridden.\n */\nexport interface CursorParams {\n /** Bypass OAuth resolution with an explicit token (mainly for tests). */\n apiKey?: string\n defaultModel?: string\n}\n\nconst DEFAULT_MODEL = 'claude-4.6-sonnet'\n\nconst NOT_IMPLEMENTED_MESSAGE\n = 'Cursor OAuth login works, but inference over Cursor is not implemented yet. '\n + 'Cursor uses a protobuf/HTTP-2 agent protocol (not an OpenAI-compatible API), '\n + 'so the streaming transport still needs to be ported. Use another provider for now.'\n\nexport function cursor(params?: CursorParams): Provider {\n const defaultModel = params?.defaultModel || DEFAULT_MODEL\n\n // Base only provides the format/serialization methods; `baseURL` is never\n // hit because we override `stream` below.\n const base = openaiCompat({\n name: 'cursor',\n apiKey: params?.apiKey ?? 'oauth',\n baseURL: 'https://api2.cursor.sh',\n defaultModel,\n capabilities: { vision: true, imageInToolResult: false },\n })\n\n return {\n ...base,\n meta: { ...base.meta, defaultModel },\n async stream(options, callbacks: StreamCallbacks) {\n // Resolve (and lazily refresh) the OAuth token so auth failures surface\n // here with the right remediation, distinct from the not-implemented path.\n await resolveOAuthApiKey(\n {\n provider: 'cursor',\n providerId: CURSOR_OAUTH_PROVIDER_ID,\n params,\n missingError: 'No Cursor credentials found. Run `bun run auth --cursor` first.',\n refreshError: reason => `Cursor OAuth token refresh failed. Run \\`bun run auth --cursor\\` again. ${reason}`,\n },\n callbacks,\n )\n void options\n throw new Error(NOT_IMPLEMENTED_MESSAGE)\n },\n }\n}\n","import type { Provider, ProviderCapabilities } from '.'\nimport { openaiCompat } from './openai-compat'\n\nexport interface LocalParams {\n /**\n * Base URL of the local OpenAI-compatible server. `/chat/completions` is\n * appended. Examples:\n * - Ollama: `http://localhost:11434/v1`\n * - vLLM: `http://localhost:8000/v1`\n * - LM Studio: `http://localhost:1234/v1`\n * - Lemonade: `http://localhost:8000/api/v1`\n * - llama.cpp: `http://localhost:8080/v1`\n *\n * Resolution order: explicit `params.baseURL` > `LOCAL_LLM_BASE_URL` env >\n * throw.\n */\n baseURL?: string\n /**\n * Optional bearer key. Most local servers don't authenticate; some (vLLM\n * with `--api-key`, gateway proxies, llama.cpp with `--api-key`) do.\n * Falls back to `LOCAL_LLM_API_KEY`, then to a placeholder string accepted\n * by unauthenticated endpoints.\n */\n apiKey?: string\n /**\n * Default model id. Local runtimes have no fixed catalogue — whatever the\n * user has loaded (e.g. `llama3.1:8b`, `qwen2.5-coder`, a HF repo path).\n * Falls back to `LOCAL_LLM_DEFAULT_MODEL`.\n */\n defaultModel?: string\n /**\n * Provider capability flags. Defaults to text-only — typical OSS local\n * deployment. Override when pointing at a vision-capable runtime (e.g.\n * Ollama serving a multimodal model, vLLM with a VLM).\n */\n capabilities?: ProviderCapabilities\n}\n\nfunction getBaseURL(params?: LocalParams): string {\n if (typeof params?.baseURL === 'string' && params.baseURL.length > 0)\n return params.baseURL\n if (process.env.LOCAL_LLM_BASE_URL)\n return process.env.LOCAL_LLM_BASE_URL\n throw new Error(\n 'No local LLM base URL found. Pass `baseURL` or set LOCAL_LLM_BASE_URL '\n + '(e.g. http://localhost:11434/v1 for Ollama, http://localhost:8000/v1 for vLLM).',\n )\n}\n\nfunction getApiKey(params?: LocalParams): string {\n if (typeof params?.apiKey === 'string' && params.apiKey.length > 0)\n return params.apiKey\n if (process.env.LOCAL_LLM_API_KEY)\n return process.env.LOCAL_LLM_API_KEY\n // Most local servers don't authenticate; send a placeholder so the factory's\n // Authorization header is well-formed (servers that ignore the header are\n // unaffected; servers that strict-check will be configured via env anyway).\n return 'no-key'\n}\n\nfunction getDefaultModel(params?: LocalParams): string | undefined {\n if (typeof params?.defaultModel === 'string' && params.defaultModel.length > 0)\n return params.defaultModel\n if (process.env.LOCAL_LLM_DEFAULT_MODEL)\n return process.env.LOCAL_LLM_DEFAULT_MODEL\n return undefined\n}\n\n/**\n * Local OpenAI-compatible LLM provider.\n *\n * Thin wrapper around {@link openaiCompat} for self-hosted runtimes that\n * speak the standard `POST /chat/completions` + SSE dialect: Ollama, vLLM,\n * LM Studio, Lemonade, llama.cpp's server, text-generation-webui, etc.\n *\n * Caching and reasoning are left off — local runtimes typically strict-\n * validate the request schema and would 400 on the extra fields. Override\n * `capabilities` when pointing at a vision-capable deployment.\n */\nexport function local(params?: LocalParams): Provider {\n return openaiCompat({\n name: 'local',\n apiKey: getApiKey(params),\n baseURL: getBaseURL(params),\n defaultModel: getDefaultModel(params),\n capabilities: params?.capabilities ?? { vision: false, imageInToolResult: false },\n })\n}\n","import type {\n AssistantMessage as PiAssistantMessage,\n Context as PiContext,\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, TurnFinishReason } from '../types'\nimport type { OAuthParams } from './oauth'\nimport { getModel } from '@earendil-works/pi-ai'\nimport { streamOpenAICodexResponses } from '@earendil-works/pi-ai/openai-codex-responses'\nimport { classifyErrorPrelude, isRetryableHttpStatus, matchesContextExceeded, matchesToolPairingError } from '../errors'\nimport { SYNTHETIC_TOOL_RESULT_PLACEHOLDER } from '../session/messages'\nimport { renderSystemForWire } from '../system-prompt'\nimport { fillEstimatedCost } from './cost'\nimport { extractRuntimeCredentials, resolveOAuthApiKey } from './oauth'\nimport {\n assistantMessage,\n toolResultsMessage,\n userMessage,\n} from './openai-compat'\nimport { sanitizeToolSpecs } from './schema-sanitize'\n\nconst PROVIDER_ID = 'openai-codex'\nconst DEFAULT_MODEL = 'gpt-5.4'\n\ntype CodexModel = PiModel<'openai-codex-responses'>\n\nexport interface OpenAIParams extends OAuthParams {\n accountId?: string\n defaultModel?: string\n transport?: 'sse' | 'websocket' | 'auto'\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(modelId: string): CodexModel {\n const model = lookupModel(PROVIDER_ID, modelId)\n if (model)\n return model\n\n const fallback = lookupModel(PROVIDER_ID, DEFAULT_MODEL)\n if (!fallback)\n throw new Error(`OpenAI Codex model registry is missing the default model: ${DEFAULT_MODEL}`)\n\n return { ...fallback, id: modelId, name: modelId }\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 return sanitized.map(t => ({\n name: t.name,\n description: t.description,\n parameters: t.inputSchema as PiTool['parameters'],\n }))\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 => block.type === 'image'\n ? { type: 'image' as const, data: block.data, mimeType: block.mediaType }\n : { type: 'text' as const, text: block.text })\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 const textBlocks = content.filter(b => b.type === 'text')\n const imageBlocks = content.filter(b => b.type === 'image')\n\n if (imageBlocks.length === 0 && textBlocks.length === 0)\n return null\n\n if (imageBlocks.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 => ({ type: 'image' as const, data: img.data, mimeType: img.mediaType })),\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 // Drop thinking blocks minted by another provider — Anthropic signatures\n // are not valid OpenAI `encrypted_content` and Responses API rejects them.\n if (block.signatureProducer === 'anthropic')\n continue\n piContent.push({ type: 'thinking', thinking: block.text, thinkingSignature: block.signature })\n }\n else if (block.type === 'tool_call') {\n piContent.push({ type: 'toolCall', id: block.id, name: block.name, arguments: block.input })\n }\n // `redacted_thinking` (Anthropic-only) and `provider_reasoning` (OpenRouter\n // envelope) are intentionally dropped — Codex Responses 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\nexport function toPiMessages(messages: SessionMessage[], modelId: string): PiMessage[] {\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\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) {\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')\n}\n\n/**\n * Transient pi-ai error patterns worth a loop-level retry. pi-ai already retries\n * 429 / 5xx pre-stream 3× internally (see `openai-codex-responses.js`); by the\n * time the error reaches us, that budget is exhausted. The loop-level retry\n * with its longer backoff is a second line of defense for capacity events\n * that persist past pi-ai's short retry window, plus mid-stream emissions\n * (pi-ai surfaces those as plain `Error`s with no status).\n *\n * Mirrors pi-ai's own `isRetryableError` regex so the two retry layers\n * recognize the 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 * Retryable hint is set when pi-ai's own retry budget is exhausted on a\n * transient failure — pattern-matched against `message` since pi-ai strips\n * structured fields on plain-Error throws. Set `behavior.retry.maxAttempts: 1`\n * to disable the loop-level retry.\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 return {\n kind: 'provider_error',\n providerCode: code,\n message,\n ...(retryable ? { retryable: true } : {}),\n }\n }\n\n return null\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 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): 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: 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\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 },\n },\n formatTools,\n userMessage,\n assistantMessage,\n toolResultsMessage,\n classifyError: classifyOpenAIError,\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 res = await fetch('https://api.openai.com/v1/responses/input_tokens', {\n method: 'POST',\n headers: {\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(payload.messages),\n tools: toResponsesTools(payload.tools),\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 model = resolveModel(modelId)\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 // 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 const context: PiContext = {\n systemPrompt: renderSystemForWire(options.system),\n messages: toPiMessages(options.messages, modelId),\n tools: options.tools as PiTool[],\n }\n // OpenAI's `reasoning_effort` accepts the budgeted levels only. `'adaptive'`\n // is Anthropic-specific (model self-budgets); when supplied here we degrade\n // to no reasoning rather than forwarding an unknown value the API would reject.\n const reasoningLevel\n = options.thinking && options.thinking !== 'off' && options.thinking !== 'adaptive'\n ? options.thinking\n : undefined\n const stream = streamOpenAICodexResponses(model, context, {\n apiKey,\n maxTokens: options.maxTokens,\n signal: options.signal,\n transport: params?.transport,\n reasoningEffort: reasoningLevel,\n reasoningSummary: reasoningLevel ? 'auto' : undefined,\n onPayload: payload => applyPayloadOverrides(payload, options),\n })\n\n let finalMessage: PiAssistantMessage | undefined\n let text = ''\n let thinking = ''\n\n for await (const event of stream) {\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 === 'done') {\n finalMessage = event.message\n }\n else if (event.type === 'error') {\n throw new Error(event.error.errorMessage || 'OpenAI Codex API error')\n }\n }\n\n finalMessage ??= await stream.result()\n text ||= extractText(finalMessage)\n\n const toolCalls = extractToolCalls(finalMessage)\n const assistantTurn = fromPiAssistantMessage(finalMessage)\n const finishReason: TurnFinishReason = toolCalls.length > 0 ? 'tool-calls' : 'stop'\n\n return {\n assistantMessage: assistantTurn,\n text,\n toolCalls,\n done: toolCalls.length === 0,\n usage: toTurnUsage(finalMessage.usage, finishReason, modelId),\n }\n },\n }\n}\n","import type { Provider, ProviderCapabilities } from '.'\nimport { openaiCompat } from './openai-compat'\n\nconst BASE_URL = 'https://openrouter.ai/api/v1'\n\nexport interface OpenRouterParams {\n apiKey?: string\n defaultModel?: string\n /**\n * Provider capability flags. OpenRouter itself is a router — whether vision or\n * native image-in-tool-result are supported depends on the downstream model.\n * Default: `{ vision: true, imageInToolResult: false }` — matches the default\n * `anthropic/claude-sonnet-4-6` model (vision-capable via companion user-message\n * fallback since OpenRouter exposes Claude over the Chat Completions dialect).\n *\n * Override when routing to a known-text-only model (e.g. `meta-llama/llama-3-8b-instruct`).\n */\n capabilities?: ProviderCapabilities\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\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 */\nexport function openrouter(params?: OpenRouterParams): Provider {\n const apiKey = getApiKey(params)\n return openaiCompat({\n name: 'openrouter',\n apiKey,\n baseURL: BASE_URL,\n defaultModel: params?.defaultModel || 'anthropic/claude-sonnet-4-6',\n extraHeaders: {\n 'HTTP-Referer': 'https://github.com/Tahul/zidane',\n 'X-Title': 'zidane',\n },\n capabilities: params?.capabilities ?? { vision: true, imageInToolResult: false },\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"],"mappings":"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"}
package/dist/providers.js CHANGED
@@ -1,3 +1,3 @@
1
- import { c as anthropic, i as cursor, l as applyAnthropicCacheBreakpoints, n as openai, r as local, s as cerebras, t as openrouter } from "./providers-h4HJPbbv.js";
2
- import { S as sanitizeToolSpecs, _ as mapOAIFinishReason, g as classifyOpenAICompatError, m as OpenAICompatHttpError, v as openaiCompat, x as sanitizeToolSchema } from "./messages-CvRQTdbR.js";
1
+ import { c as anthropic, i as cursor, l as applyAnthropicCacheBreakpoints, n as openai, r as local, s as cerebras, t as openrouter } from "./providers-ByITfqRA.js";
2
+ import { S as sanitizeToolSpecs, _ as mapOAIFinishReason, g as classifyOpenAICompatError, m as OpenAICompatHttpError, v as openaiCompat, x as sanitizeToolSchema } from "./messages-Dhva-Ewy.js";
3
3
  export { OpenAICompatHttpError, anthropic, applyAnthropicCacheBreakpoints, cerebras, classifyOpenAICompatError, cursor, local, mapOAIFinishReason, openai, openaiCompat, openrouter, sanitizeToolSchema, sanitizeToolSpecs };
@@ -1,4 +1,4 @@
1
- import { l as errorMessage } from "../errors-CoQnKRf1.js";
1
+ import { l as errorMessage } from "../errors-B-GeaKTX.js";
2
2
  import { dirname } from "node:path";
3
3
  import { copyFileSync, existsSync, mkdirSync } from "node:fs";
4
4
  import { Database } from "bun:sqlite";
@@ -1,4 +1,4 @@
1
- import { p as toWireMessages } from "./messages-CvRQTdbR.js";
1
+ import { p as toWireMessages } from "./messages-Dhva-Ewy.js";
2
2
  //#region src/session/file-map.ts
3
3
  function toMeta(data) {
4
4
  return {
@@ -477,4 +477,4 @@ function generateId() {
477
477
  //#endregion
478
478
  export { createFileMapStore as a, createMemoryStore as i, loadSession as n, createRemoteStore as r, createSession as t };
479
479
 
480
- //# sourceMappingURL=session-BzLou2_-.js.map
480
+ //# sourceMappingURL=session-7CKYn9qT.js.map