zidane 5.1.12 → 5.1.13

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 (50) hide show
  1. package/dist/{agent-D0pXl4CO.d.ts → agent-skiQGYs2.d.ts} +8 -2
  2. package/dist/agent-skiQGYs2.d.ts.map +1 -0
  3. package/dist/chat.d.ts +43 -6
  4. package/dist/chat.d.ts.map +1 -1
  5. package/dist/chat.js +2 -2
  6. package/dist/{index-n4STKh9s.d.ts → index-CjPh6CRE.d.ts} +2 -2
  7. package/dist/{index-n4STKh9s.d.ts.map → index-CjPh6CRE.d.ts.map} +1 -1
  8. package/dist/{index-C9A_Ah4R.d.ts → index-YM7SipFz.d.ts} +2 -2
  9. package/dist/{index-C9A_Ah4R.d.ts.map → index-YM7SipFz.d.ts.map} +1 -1
  10. package/dist/index.d.ts +3 -3
  11. package/dist/index.js +6 -6
  12. package/dist/{login-CQNaKTLJ.js → login-Cc6Q-Fpu.js} +2 -2
  13. package/dist/{login-CQNaKTLJ.js.map → login-Cc6Q-Fpu.js.map} +1 -1
  14. package/dist/mcp.d.ts +1 -1
  15. package/dist/{messages-DiAiNhxA.js → messages-CIkO_aCH.js} +40 -4
  16. package/dist/messages-CIkO_aCH.js.map +1 -0
  17. package/dist/{presets-CYNTGGXg.js → presets-Ce79MK4J.js} +2 -2
  18. package/dist/{presets-CYNTGGXg.js.map → presets-Ce79MK4J.js.map} +1 -1
  19. package/dist/presets.d.ts +2 -2
  20. package/dist/presets.js +1 -1
  21. package/dist/{providers-6bqfXUd1.js → providers-CvriFHFU.js} +27 -8
  22. package/dist/providers-CvriFHFU.js.map +1 -0
  23. package/dist/providers.d.ts +1 -1
  24. package/dist/providers.js +2 -2
  25. package/dist/session/sqlite.d.ts +1 -1
  26. package/dist/{session-pS4Vt4dl.js → session-DtLD1Sl1.js} +2 -1
  27. package/dist/{session-pS4Vt4dl.js.map → session-DtLD1Sl1.js.map} +1 -1
  28. package/dist/session.d.ts +1 -1
  29. package/dist/session.js +2 -2
  30. package/dist/skills.d.ts +2 -2
  31. package/dist/{tool-formatters-BkbbrFyr.d.ts → tool-formatters-0aOMYbH-.d.ts} +71 -5
  32. package/dist/tool-formatters-0aOMYbH-.d.ts.map +1 -0
  33. package/dist/{tools-BoHVy2UM.js → tools-BG2wMa3X.js} +2 -2
  34. package/dist/{tools-BoHVy2UM.js.map → tools-BG2wMa3X.js.map} +1 -1
  35. package/dist/tools.d.ts +2 -2
  36. package/dist/tools.js +1 -1
  37. package/dist/tui.d.ts +44 -11
  38. package/dist/tui.d.ts.map +1 -1
  39. package/dist/tui.js +945 -276
  40. package/dist/tui.js.map +1 -1
  41. package/dist/{turn-operations-BMGp7jXI.js → turn-operations-CDmQ2h-T.js} +490 -55
  42. package/dist/turn-operations-CDmQ2h-T.js.map +1 -0
  43. package/dist/types-Bx_F8jet.js.map +1 -1
  44. package/dist/types.d.ts +2 -2
  45. package/package.json +1 -1
  46. package/dist/agent-D0pXl4CO.d.ts.map +0 -1
  47. package/dist/messages-DiAiNhxA.js.map +0 -1
  48. package/dist/providers-6bqfXUd1.js.map +0 -1
  49. package/dist/tool-formatters-BkbbrFyr.d.ts.map +0 -1
  50. package/dist/turn-operations-BMGp7jXI.js.map +0 -1
@@ -1,4 +1,40 @@
1
1
  import { o as matchesContextExceeded } from "./errors-D1lhd6mX.js";
2
+ import { getModel } from "@mariozechner/pi-ai";
3
+ //#region src/providers/cost.ts
4
+ /**
5
+ * Fill in `usage.cost` from pi-ai's bundled price registry when the
6
+ * provider didn't report one. Provider-reported cost (e.g. OpenRouter's
7
+ * `total_cost`, OpenAI's pi-ai-computed total) always wins — we only
8
+ * estimate when `usage.cost` is undefined.
9
+ *
10
+ * Lookup is `(provider, usage.modelId)`. On a miss (unknown / unbundled
11
+ * model), `cost` stays undefined and the footer indicator hides — better
12
+ * than fabricating a $0.
13
+ *
14
+ * The number is an estimate: token counts come from the API, rates from
15
+ * the locally-bundled registry that refreshes with `@mariozechner/pi-ai`
16
+ * version bumps. If a provider changes prices between bumps the figure
17
+ * will drift until the dep updates.
18
+ */
19
+ function fillEstimatedCost(usage, provider) {
20
+ if (usage.cost !== void 0) return usage;
21
+ if (!usage.modelId) return usage;
22
+ let model;
23
+ try {
24
+ model = getModel(provider, usage.modelId);
25
+ } catch {
26
+ return usage;
27
+ }
28
+ const rates = model?.cost;
29
+ if (!rates) return usage;
30
+ const total = ((rates.input ?? 0) * (usage.input ?? 0) + (rates.output ?? 0) * (usage.output ?? 0) + (rates.cacheRead ?? 0) * (usage.cacheRead ?? 0) + (rates.cacheWrite ?? 0) * (usage.cacheCreation ?? 0)) / 1e6;
31
+ if (total <= 0) return usage;
32
+ return {
33
+ ...usage,
34
+ cost: total
35
+ };
36
+ }
37
+ //#endregion
2
38
  //#region src/providers/openai-compat.ts
3
39
  const TOOL_RESULTS_TAG = "__zidane_tool_results__";
4
40
  const ASSISTANT_TOOL_CALLS_TAG = "__zidane_assistant_tc__";
@@ -639,7 +675,7 @@ function openaiCompat(params) {
639
675
  text: result.text,
640
676
  toolCalls: result.toolCalls,
641
677
  done: result.finishReason === "stop" || result.toolCalls.length === 0,
642
- usage: {
678
+ usage: fillEstimatedCost({
643
679
  input: result.usage.input,
644
680
  output: result.usage.output,
645
681
  ...result.usage.cacheRead !== void 0 ? { cacheRead: result.usage.cacheRead } : {},
@@ -647,7 +683,7 @@ function openaiCompat(params) {
647
683
  ...result.usage.cost !== void 0 ? { cost: result.usage.cost } : {},
648
684
  ...finishReason ? { finishReason } : {},
649
685
  modelId
650
- }
686
+ }, name)
651
687
  };
652
688
  }
653
689
  };
@@ -1111,6 +1147,6 @@ function autoDetectAndConvert(msg) {
1111
1147
  return fromAnthropic(msg);
1112
1148
  }
1113
1149
  //#endregion
1114
- export { toAnthropic as a, assistantMessage as c, openaiCompat as d, toolResultsMessage as f, sanitizeOrphanedToolCalls as i, classifyOpenAICompatError as l, fromAnthropic as n, toOpenAI as o, userMessage as p, fromOpenAI as r, OpenAICompatHttpError as s, autoDetectAndConvert as t, mapOAIFinishReason as u };
1150
+ export { toAnthropic as a, assistantMessage as c, openaiCompat as d, toolResultsMessage as f, sanitizeOrphanedToolCalls as i, classifyOpenAICompatError as l, fillEstimatedCost as m, fromAnthropic as n, toOpenAI as o, userMessage as p, fromOpenAI as r, OpenAICompatHttpError as s, autoDetectAndConvert as t, mapOAIFinishReason as u };
1115
1151
 
1116
- //# sourceMappingURL=messages-DiAiNhxA.js.map
1152
+ //# sourceMappingURL=messages-CIkO_aCH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages-CIkO_aCH.js","names":[],"sources":["../src/providers/cost.ts","../src/providers/openai-compat.ts","../src/session/messages.ts"],"sourcesContent":["import type { TurnUsage } from '../types'\nimport { getModel } from '@mariozechner/pi-ai'\n\n/**\n * Fill in `usage.cost` from pi-ai's bundled price registry when the\n * provider didn't report one. Provider-reported cost (e.g. OpenRouter's\n * `total_cost`, OpenAI's pi-ai-computed total) always wins — we only\n * estimate when `usage.cost` is undefined.\n *\n * Lookup is `(provider, usage.modelId)`. On a miss (unknown / unbundled\n * model), `cost` stays undefined and the footer indicator hides — better\n * than fabricating a $0.\n *\n * The number is an estimate: token counts come from the API, rates from\n * the locally-bundled registry that refreshes with `@mariozechner/pi-ai`\n * version bumps. If a provider changes prices between bumps the figure\n * will drift until the dep updates.\n */\nexport function fillEstimatedCost(usage: TurnUsage, provider: string): TurnUsage {\n if (usage.cost !== undefined)\n return usage\n if (!usage.modelId)\n return usage\n\n let model\n try {\n // pi-ai's `getModel` throws on unknown keys; treat as a miss.\n // pi-ai's `getModel` is typed for `KnownProvider` × keyof models[P];\n // we accept arbitrary strings (the openai-compat adapter routes both\n // known and user-defined endpoint names through this helper) and let\n // the function's runtime throw on a miss.\n model = (getModel as unknown as (p: string, m: string) => unknown)(provider, usage.modelId)\n }\n catch {\n return usage\n }\n\n const rates = (model as { cost?: { input?: number, output?: number, cacheRead?: number, cacheWrite?: number } } | undefined)?.cost\n if (!rates)\n return usage\n\n const total\n = ((rates.input ?? 0) * (usage.input ?? 0)\n + (rates.output ?? 0) * (usage.output ?? 0)\n + (rates.cacheRead ?? 0) * (usage.cacheRead ?? 0)\n + (rates.cacheWrite ?? 0) * (usage.cacheCreation ?? 0)) / 1_000_000\n\n if (total <= 0)\n return usage\n\n return { ...usage, cost: total }\n}\n","/**\n * OpenAI-compatible provider factory + shared utilities.\n *\n * `openaiCompat(params)` returns a `Provider` that talks to any OpenAI-compatible\n * HTTP endpoint (OpenRouter, Cerebras, Baseten, Fireworks, Groq, local LM servers, ...).\n * Helpers (`consumeSSE`, `toOAIMessages`, ...) are shared by the bespoke `openrouter`\n * and `cerebras` wrappers, which pin defaults on top of this factory.\n */\n\nimport type { Provider, ProviderCapabilities, StreamCallbacks, StreamOptions, ToolResult, ToolSpec, TurnResult } from '.'\nimport type { ClassifiedError } from '../errors'\nimport type { SessionContentBlock, SessionMessage, ThinkingLevel, ToolResultContent, TurnFinishReason } from '../types'\nimport { matchesContextExceeded } from '../errors'\nimport { fillEstimatedCost } from './cost'\n\n// ---------------------------------------------------------------------------\n// OpenAI-compatible types\n// ---------------------------------------------------------------------------\n\nexport interface OAIMessage {\n role: 'system' | 'user' | 'assistant' | 'tool'\n content?: unknown\n tool_calls?: { id: string, type: 'function', function: { name: string, arguments: string } }[]\n tool_call_id?: string\n /**\n * OpenRouter normalized reasoning envelope. Echoed back unmodified on assistant\n * messages so the gateway can resume an extended-reasoning chain on the\n * upstream route. Ignored by hosts that don't speak the envelope.\n */\n reasoning_details?: unknown[]\n}\n\nexport interface OAITool {\n type: 'function'\n function: { name: string, description: string, parameters: Record<string, unknown> }\n}\n\n// Sentinel tags zidane uses to round-trip tool_calls / tool_results through\n// the OpenAI-compat session shape. `toOpenAI` writes them; `fromOpenAI` reads\n// them back. The `__zidane_` prefix avoids collisions with any literal `_tag`\n// value a host might emit on real wire messages.\nexport const TOOL_RESULTS_TAG = '__zidane_tool_results__'\nexport const ASSISTANT_TOOL_CALLS_TAG = '__zidane_assistant_tc__'\n\n// ---------------------------------------------------------------------------\n// SSE stream parser\n// ---------------------------------------------------------------------------\n\n/**\n * Ceiling on how many bytes may accumulate between two newline boundaries when\n * parsing an SSE stream. A broken or malicious server that emits an unbounded\n * stream of non-newline bytes would otherwise grow `buffer` without end and\n * eventually OOM the host. 8 MB is safely above the largest tool-call arg\n * JSON we reasonably expect and still catches a pathological stream in ~1 s on\n * a 10 MB/s connection.\n */\nconst SSE_MAX_BUFFER_BYTES = 8 * 1024 * 1024\n\nexport class OpenAICompatStreamError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'OpenAICompatStreamError'\n }\n}\n\nexport async function consumeSSE(\n response: Response,\n callbacks: StreamCallbacks,\n signal?: AbortSignal,\n) {\n const reader = response.body!.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n let text = ''\n let thinking = ''\n let finishReason = 'stop'\n let usage: { input: number, output: number, cost?: number, cacheRead?: number, cacheCreation?: number } = { input: 0, output: 0 }\n const tcMap = new Map<number, { id: string, name: string, args: string }>()\n // OpenRouter `reasoning_details` deltas, keyed by item index. Items are merged\n // field-by-field: text/summary concatenate, signature/data/format/id/type are\n // last-write-wins (they only appear once per item in practice).\n const reasoningMap = new Map<number, Record<string, unknown>>()\n let sawReasoningDetails = false\n\n try {\n while (true) {\n if (signal?.aborted)\n break\n const { done, value } = await reader.read()\n if (done)\n break\n\n buffer += decoder.decode(value, { stream: true })\n // Cap the line-less buffer. Any single event must fit under the ceiling.\n if (buffer.length > SSE_MAX_BUFFER_BYTES) {\n throw new OpenAICompatStreamError(\n `SSE buffer exceeded ${SSE_MAX_BUFFER_BYTES} bytes without a line boundary — upstream may be streaming non-SSE data.`,\n )\n }\n const lines = buffer.split('\\n')\n buffer = lines.pop() || ''\n\n for (const line of lines) {\n if (!line.startsWith('data: '))\n continue\n const data = line.slice(6).trim()\n if (data === '[DONE]')\n continue\n\n let chunk: Record<string, unknown>\n try {\n chunk = JSON.parse(data) as Record<string, unknown>\n }\n catch {\n // Malformed JSON frame — skip (SSE keepalives, injected comments, etc.)\n continue\n }\n\n const choices = chunk.choices as Array<Record<string, unknown>> | undefined\n const choice = choices?.[0]\n if (!choice)\n continue\n const fr = choice.finish_reason as string | undefined\n if (fr)\n finishReason = fr\n\n const delta = choice.delta as Record<string, unknown> | undefined\n\n // OpenRouter normalized reasoning envelope. Items arrive as deltas keyed\n // by `index`; merge into a stable list and stream the visible text portion\n // through `onThinking` so the UI sees reasoning live.\n const reasoningDeltaArr = delta?.reasoning_details as Array<Record<string, unknown>> | undefined\n if (reasoningDeltaArr && reasoningDeltaArr.length > 0) {\n sawReasoningDetails = true\n for (const item of reasoningDeltaArr) {\n const idx = (typeof item.index === 'number' ? item.index : 0)\n const existing = reasoningMap.get(idx) ?? {}\n // Concatenate text/summary across deltas.\n if (typeof item.text === 'string') {\n existing.text = ((existing.text as string | undefined) ?? '') + item.text\n thinking += item.text\n callbacks.onThinking?.(item.text)\n }\n if (typeof item.summary === 'string') {\n existing.summary = ((existing.summary as string | undefined) ?? '') + item.summary\n thinking += item.summary\n callbacks.onThinking?.(item.summary)\n }\n // Last-write-wins for opaque fields.\n for (const key of ['type', 'signature', 'data', 'format', 'id'] as const) {\n const v = item[key]\n if (typeof v === 'string')\n existing[key] = v\n }\n reasoningMap.set(idx, existing)\n }\n }\n\n // Legacy text-only reasoning fields (DeepSeek `reasoning_content`,\n // pre-`reasoning_details` OpenRouter, Qwen-thinking, …). Suppressed\n // when the structured envelope is in flight to avoid double-counting\n // the same reasoning text into the `thinking` buffer.\n if (!sawReasoningDetails) {\n const thinkingDelta = (delta?.reasoning_content ?? delta?.reasoning) as string | undefined\n if (thinkingDelta) {\n thinking += thinkingDelta\n callbacks.onThinking?.(thinkingDelta)\n }\n }\n\n const contentDelta = delta?.content as string | undefined\n if (contentDelta) {\n text += contentDelta\n callbacks.onText(contentDelta)\n }\n\n const toolCallsDelta = delta?.tool_calls as Array<{\n index: number\n id?: string\n function?: { name?: string, arguments?: string }\n }> | undefined\n if (toolCallsDelta) {\n for (const tc of toolCallsDelta) {\n const existing = tcMap.get(tc.index)\n if (existing) {\n if (tc.function?.arguments)\n existing.args += tc.function.arguments\n }\n else {\n tcMap.set(tc.index, {\n id: tc.id || `call_${tc.index}`,\n name: tc.function?.name || '',\n args: tc.function?.arguments || '',\n })\n }\n }\n }\n\n const chunkUsage = chunk.usage as\n | {\n prompt_tokens?: number\n completion_tokens?: number\n total_cost?: number\n cache_discount?: number\n prompt_tokens_details?: {\n cached_tokens?: number\n cache_creation_input_tokens?: number\n cache_write_tokens?: number\n }\n cache_creation_input_tokens?: number\n }\n | undefined\n if (chunkUsage) {\n const cachedRead = chunkUsage.prompt_tokens_details?.cached_tokens\n // OpenRouter surfaces cache writes via `prompt_tokens_details.cache_creation_input_tokens`\n // (Anthropic passthrough) or `cache_write_tokens` (normalized form). Either is cumulative\n // for the request, so pick whichever the route populated.\n const cachedWrite = chunkUsage.prompt_tokens_details?.cache_creation_input_tokens\n ?? chunkUsage.prompt_tokens_details?.cache_write_tokens\n ?? chunkUsage.cache_creation_input_tokens\n usage = {\n input: chunkUsage.prompt_tokens ?? 0,\n output: chunkUsage.completion_tokens ?? 0,\n cost: chunkUsage.total_cost ?? undefined,\n ...(typeof cachedRead === 'number' && cachedRead > 0 ? { cacheRead: cachedRead } : {}),\n ...(typeof cachedWrite === 'number' && cachedWrite > 0 ? { cacheCreation: cachedWrite } : {}),\n }\n }\n }\n }\n }\n finally {\n reader.releaseLock()\n }\n\n // Tool call JSON is accumulated across many deltas. If the stream truncates\n // mid-object (network hiccup, server crash) `tc.args` won't parse — fall\n // back to an empty input and surface a stream error rather than letting the\n // whole turn reject with `SyntaxError: Unexpected end of JSON input`, which\n // gives callers no actionable signal.\n const toolCalls: Array<{ id: string, name: string, input: Record<string, unknown> }> = []\n for (const tc of tcMap.values()) {\n if (!tc.args) {\n toolCalls.push({ id: tc.id, name: tc.name, input: {} })\n continue\n }\n try {\n toolCalls.push({ id: tc.id, name: tc.name, input: JSON.parse(tc.args) as Record<string, unknown> })\n }\n catch (err) {\n throw new OpenAICompatStreamError(\n `Tool call \"${tc.name}\" (${tc.id}) arguments were truncated or malformed: ${(err as Error).message}`,\n )\n }\n }\n\n // Sort by index so `reasoning_details` round-trip preserves item order.\n const reasoningDetails = Array.from(reasoningMap.entries())\n .sort(([a], [b]) => a - b)\n .map(([, item]) => item)\n\n return { text, thinking, toolCalls, finishReason, usage, reasoningDetails }\n}\n\n// ---------------------------------------------------------------------------\n// Message conversion: SessionMessage[] → OAIMessage[]\n// ---------------------------------------------------------------------------\n\n/**\n * Encode a single image block as an OpenAI `image_url` multi-part entry.\n */\nfunction toImageUrlPart(img: { mediaType: string, data: string }) {\n return {\n type: 'image_url' as const,\n image_url: { url: `data:${img.mediaType};base64,${img.data}` },\n }\n}\n\n/**\n * Summarize a `tool_result` output for the companion-user-message path — text blocks\n * are joined (separated by `\\n`) so the tool message carries all textual context; image\n * blocks are collected in a flat list for the companion user message.\n *\n * Used only on the fallback path; the native path walks `output` in-order to preserve\n * text↔image interleaving.\n */\nfunction summarizeToolResultOutput(output: string | ToolResultContent[]): {\n text: string\n images: Array<{ mediaType: string, data: string }>\n} {\n if (typeof output === 'string')\n return { text: output, images: [] }\n\n const texts: string[] = []\n const images: Array<{ mediaType: string, data: string }> = []\n for (const block of output) {\n if (block.type === 'text')\n texts.push(block.text)\n else if (block.type === 'image')\n images.push({ mediaType: block.mediaType, data: block.data })\n }\n return { text: texts.join('\\n'), images }\n}\n\n/**\n * Options that influence OpenAI-compat message shaping.\n *\n * `imageInToolResult` defaults to `false`: the loop routes images via a companion\n * user message emitted immediately after the `tool` message. Providers with\n * genuine multi-part tool support can set it to `true` to emit a single\n * multi-part `tool` message instead.\n */\ninterface ToOAIOptions {\n imageInToolResult?: boolean\n /**\n * Host accepts OpenRouter-style `reasoning_details` echoed back on assistant\n * messages. When `true`, `provider_reasoning` blocks whose `producer`/`model`\n * match the active route are forwarded; when `false` (default), they are\n * silently dropped to avoid 400s on hosts that strict-validate the schema.\n */\n supportsReasoning?: boolean\n /**\n * Active model id. Used to gate `provider_reasoning` blocks — reasoning state\n * is bound to the route that produced it, so a model switch invalidates the\n * embedded signatures.\n */\n model?: string\n}\n\nexport function toOAIMessages(system: string, messages: SessionMessage[], options: ToOAIOptions = {}): OAIMessage[] {\n const out: OAIMessage[] = [{ role: 'system', content: system }]\n const nativeImageInTool = options.imageInToolResult === true\n const reasoningEnabled = options.supportsReasoning === true\n const activeModel = options.model\n\n for (const msg of messages) {\n const toolResults = msg.content.filter(b => b.type === 'tool_result') as Extract<SessionContentBlock, { type: 'tool_result' }>[]\n const toolCalls = msg.content.filter(b => b.type === 'tool_call') as Extract<SessionContentBlock, { type: 'tool_call' }>[]\n const textBlocks = msg.content.filter(b => b.type === 'text') as Extract<SessionContentBlock, { type: 'text' }>[]\n const imageBlocks = msg.content.filter(b => b.type === 'image') as Extract<SessionContentBlock, { type: 'image' }>[]\n // Provider-bound reasoning state — attached to the assistant message below\n // when the host supports it AND the active route matches the producer.\n const reasoningBlocks = reasoningEnabled\n ? (msg.content.filter((b) => {\n if (b.type !== 'provider_reasoning')\n return false\n if (b.producer !== 'openrouter')\n return false\n if (b.model && activeModel && b.model !== activeModel)\n return false\n return true\n }) as Extract<SessionContentBlock, { type: 'provider_reasoning' }>[])\n : []\n const reasoningDetails = reasoningBlocks.flatMap(b => b.details)\n\n // Tool results → individual tool messages (plus optional companion user message for images)\n if (toolResults.length > 0) {\n for (const tr of toolResults) {\n // Pure-string output → text-only fast path, wire-identical to pre-multimodal behavior.\n if (typeof tr.output === 'string') {\n out.push({ role: 'tool', tool_call_id: tr.callId, content: tr.output })\n continue\n }\n\n // Native multi-part path — walk blocks in order so text↔image interleaving is preserved.\n if (nativeImageInTool) {\n const parts = tr.output.map(block => block.type === 'image'\n ? toImageUrlPart({ mediaType: block.mediaType, data: block.data })\n : { type: 'text' as const, text: block.text })\n out.push({ role: 'tool', tool_call_id: tr.callId, content: parts })\n continue\n }\n\n // Companion-user-message fallback (Claude Desktop / Cline pattern).\n // Works on any Chat Completions endpoint that accepts images in user messages.\n const { text, images } = summarizeToolResultOutput(tr.output)\n if (images.length === 0) {\n // Structured array happened to be text-only — collapse to pure-text path.\n out.push({ role: 'tool', tool_call_id: tr.callId, content: text })\n continue\n }\n\n const noun = images.length === 1 ? 'image' : 'images'\n const attachedMarker = `[${images.length} ${noun} attached — see next user message]`\n const toolMarker = text.length > 0 ? `${text}\\n\\n${attachedMarker}` : attachedMarker\n out.push({ role: 'tool', tool_call_id: tr.callId, content: toolMarker })\n\n out.push({\n role: 'user',\n content: [\n ...images.map(toImageUrlPart),\n { type: 'text' as const, text: `(${noun} returned by tool call ${tr.callId})` },\n ],\n })\n }\n continue\n }\n\n // Tool calls → assistant message with tool_calls array\n if (toolCalls.length > 0) {\n const textContent = textBlocks.length > 0 ? textBlocks[0].text : null\n const m: OAIMessage = {\n role: 'assistant',\n content: textContent,\n tool_calls: toolCalls.map(tc => ({\n id: tc.id,\n type: 'function' as const,\n function: { name: tc.name, arguments: JSON.stringify(tc.input) },\n })),\n }\n if (reasoningDetails.length > 0)\n m.reasoning_details = reasoningDetails\n out.push(m)\n continue\n }\n\n // Images → multimodal array\n if (imageBlocks.length > 0) {\n const parts: unknown[] = imageBlocks.map(img => ({\n type: 'image_url',\n image_url: { url: `data:${img.mediaType};base64,${img.data}` },\n }))\n for (const b of textBlocks) {\n parts.push({ type: 'text', text: b.text })\n }\n const m: OAIMessage = { role: msg.role, content: parts }\n if (msg.role === 'assistant' && reasoningDetails.length > 0)\n m.reasoning_details = reasoningDetails\n out.push(m)\n continue\n }\n\n // Pure text\n let pushed: OAIMessage\n if (textBlocks.length === 1) {\n pushed = { role: msg.role, content: textBlocks[0].text }\n }\n else if (textBlocks.length > 1) {\n pushed = { role: msg.role, content: textBlocks.map(b => ({ type: 'text', text: b.text })) }\n }\n else {\n pushed = { role: msg.role, content: null }\n }\n if (msg.role === 'assistant' && reasoningDetails.length > 0)\n pushed.reasoning_details = reasoningDetails\n out.push(pushed)\n }\n\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Prompt caching\n// ---------------------------------------------------------------------------\n\nconst EPHEMERAL = { type: 'ephemeral' as const }\n\n/**\n * Add `cache_control: { type: 'ephemeral' }` breakpoints to the system message's\n * last text part and the last message's final content part.\n *\n * Mutates `messages` in place. Converts plain-string content into a single-element\n * content array so the cache marker can attach — this shape is accepted verbatim by\n * OpenRouter's Anthropic and Gemini routes and ignored by routes with automatic\n * caching (OpenAI, DeepSeek, Grok, Groq, Moonshot).\n *\n * Skip conditions (safe no-ops):\n * - Empty messages array.\n * - Assistant messages with no text (tool-call-only) — attaching a cache marker to a\n * `tool_calls` block has no defined semantics, so we skip and let the prior\n * system/tools breakpoints carry caching.\n */\nexport function applyOAICacheBreakpoints(messages: OAIMessage[]): void {\n if (messages.length === 0)\n return\n\n const first = messages[0]\n if (first.role === 'system')\n markLastContentPart(first)\n\n const lastIdx = messages.length - 1\n if (lastIdx > 0)\n markLastContentPart(messages[lastIdx])\n}\n\n/**\n * Mark the last content part of an OAI message with `cache_control`. Normalizes\n * string content into a `[{ type: 'text', text, cache_control }]` array so the\n * marker has a block to attach to.\n *\n * No-op for messages without string or array content (tool-call-only assistant\n * messages fall through; the system/tools breakpoints carry the cache prefix).\n */\nfunction markLastContentPart(msg: OAIMessage): void {\n if (typeof msg.content === 'string') {\n if (msg.content.length === 0)\n return\n msg.content = [{ type: 'text', text: msg.content, cache_control: EPHEMERAL }]\n return\n }\n if (!Array.isArray(msg.content) || msg.content.length === 0)\n return\n\n const parts = msg.content as Array<Record<string, unknown>>\n const lastBlockIdx = parts.length - 1\n parts[lastBlockIdx] = { ...parts[lastBlockIdx], cache_control: EPHEMERAL }\n}\n\n/**\n * Return a copy of `tools` with `cache_control` on the last entry.\n *\n * OpenRouter accepts the marker alongside the standard `type` + `function` fields\n * and forwards it when routing to Anthropic/Gemini. Leaves the non-cached tools\n * unchanged so the caller's reference is not mutated.\n */\nexport function applyOAIToolCacheBreakpoint(tools: OAITool[]): OAITool[] {\n if (tools.length === 0)\n return tools\n const lastIdx = tools.length - 1\n return tools.map((tool, i) =>\n i === lastIdx ? ({ ...tool, cache_control: EPHEMERAL } as OAITool & { cache_control: typeof EPHEMERAL }) : tool,\n )\n}\n\n// ---------------------------------------------------------------------------\n// Shared message builders\n// ---------------------------------------------------------------------------\n\nexport function formatTools(tools: ToolSpec[]): OAITool[] {\n return tools.map(t => ({\n type: 'function' as const,\n function: { name: t.name, description: t.description, parameters: t.inputSchema },\n }))\n}\n\nexport function userMessage(content: string): SessionMessage {\n return { role: 'user', content: [{ type: 'text', text: content }] }\n}\n\nexport function assistantMessage(content: string): SessionMessage {\n return { role: 'assistant', content: [{ type: 'text', text: content }] }\n}\n\nexport function 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 })),\n }\n}\n\nexport function buildAssistantContent(\n text: string,\n toolCalls: { id: string, name: string, input: Record<string, unknown> }[],\n thinking?: string,\n reasoning?: { details: unknown[], producer: 'openrouter', model?: string },\n): SessionMessage {\n const content: SessionContentBlock[] = []\n // `provider_reasoning` precedes `thinking` so re-attached envelopes arrive\n // before the legacy text mirror in the assistant content list.\n if (reasoning && reasoning.details.length > 0) {\n const block: Extract<SessionContentBlock, { type: 'provider_reasoning' }> = {\n type: 'provider_reasoning',\n producer: reasoning.producer,\n details: reasoning.details,\n }\n if (reasoning.model)\n block.model = reasoning.model\n content.push(block)\n }\n if (thinking)\n content.push({ type: 'thinking', text: thinking })\n if (text)\n content.push({ type: 'text', text })\n for (const tc of toolCalls) {\n content.push({ type: 'tool_call', id: tc.id, name: tc.name, input: tc.input })\n }\n return { role: 'assistant', content }\n}\n\n// ---------------------------------------------------------------------------\n// Error classification\n// ---------------------------------------------------------------------------\n\n/**\n * HTTP error thrown when an OpenAI-compatible endpoint returns a non-OK response.\n *\n * The body is best-effort JSON-parsed; `error.message` / `error.code` / `error.type`\n * are extracted for clean downstream classification.\n */\nexport class OpenAICompatHttpError extends Error {\n readonly status: number\n readonly providerCode?: string\n readonly bodyText: string\n\n constructor(status: number, bodyText: string) {\n let message = bodyText\n let code: string | undefined\n try {\n const parsed = JSON.parse(bodyText)\n message = parsed?.error?.message ?? bodyText\n code = parsed?.error?.code ?? parsed?.error?.type\n }\n catch {\n // Leave message as the raw body.\n }\n super(`HTTP ${status}: ${message}`)\n this.name = 'OpenAICompatHttpError'\n this.status = status\n this.providerCode = code\n this.bodyText = bodyText\n }\n}\n\nconst TRAILING_SLASH_RE = /\\/$/\n\n/**\n * Classify an OpenAI-compatible error into `ClassifiedError`.\n *\n * Recognizes:\n * - `AbortError` (from fetch) → `aborted`.\n * - `OpenAICompatHttpError` with a context-exceeded code or message → `context_exceeded`.\n * - Any other `OpenAICompatHttpError` → `provider_error`.\n *\n * Returns `null` for unrecognized error shapes (the loop falls back to `AgentProviderError`).\n */\nexport function classifyOpenAICompatError(err: unknown): ClassifiedError | null {\n if (!err || typeof err !== 'object')\n return null\n\n if ((err as Error).name === 'AbortError')\n return { kind: 'aborted' }\n\n // A truncated / malformed SSE stream is a transient network-level failure —\n // typically worth a retry from the caller's perspective.\n if (err instanceof OpenAICompatStreamError) {\n return {\n kind: 'provider_error',\n providerCode: 'stream_error',\n message: err.message,\n retryable: true,\n }\n }\n\n if (!(err instanceof OpenAICompatHttpError))\n return null\n\n const code = err.providerCode\n const msg = err.message\n\n if (code === 'context_length_exceeded' || matchesContextExceeded(msg)) {\n return {\n kind: 'context_exceeded',\n providerCode: code ?? 'context_length_exceeded',\n message: msg,\n }\n }\n\n return {\n kind: 'provider_error',\n providerCode: code ?? String(err.status),\n message: msg,\n retryable: isRetryableHttpStatus(err.status),\n }\n}\n\n/**\n * 429 + 5xx (except 501 Not Implemented) are safe to retry with backoff;\n * 4xx other than 429 are terminal (bad request, auth, not found, etc.).\n */\nfunction isRetryableHttpStatus(status: number): boolean {\n if (status === 429)\n return true\n if (status >= 500 && status !== 501)\n return true\n return false\n}\n\n// ---------------------------------------------------------------------------\n// Finish-reason mapping\n// ---------------------------------------------------------------------------\n\n/**\n * Map an OpenAI-compatible `finish_reason` string to the zidane `TurnFinishReason` union.\n */\nexport function mapOAIFinishReason(reason: string | null | undefined): TurnFinishReason | undefined {\n if (!reason)\n return undefined\n switch (reason) {\n case 'stop':\n return 'stop'\n case 'tool_calls':\n case 'function_call':\n return 'tool-calls'\n case 'length':\n return 'length'\n case 'content_filter':\n return 'content-filter'\n default:\n return 'other'\n }\n}\n\n// ---------------------------------------------------------------------------\n// openaiCompat factory\n// ---------------------------------------------------------------------------\n\n/**\n * Auth header config. `scheme` is prepended to the api key with a space, e.g.\n * `{ name: 'Authorization', scheme: 'Bearer' }` → `Authorization: Bearer <key>`.\n * Omit `scheme` for raw header values (e.g. `{ name: 'X-Api-Key' }` → `X-Api-Key: <key>`).\n *\n * Real-world examples:\n * - Default OpenAI / OpenRouter / Cerebras: `{ name: 'Authorization', scheme: 'Bearer' }`.\n * - Baseten: `{ name: 'Authorization', scheme: 'Api-Key' }`.\n * - Some gateways: `{ name: 'X-Api-Key' }`.\n */\nexport interface OpenAICompatAuthHeader {\n name: string\n scheme?: string\n}\n\nexport interface OpenAICompatParams {\n /** Bearer-style API key. */\n apiKey: string\n /** Base URL — `/chat/completions` is appended. */\n baseURL: string\n /** Default model id when `run({ model })` is omitted. */\n defaultModel?: string\n /** Provider name exposed as `Provider.name`. Defaults to `'openai-compat'`. */\n name?: string\n /** Auth header shape. Defaults to `{ name: 'Authorization', scheme: 'Bearer' }`. */\n authHeader?: OpenAICompatAuthHeader\n /** Extra headers sent with every request (e.g. referer, user-agent). */\n extraHeaders?: Record<string, string>\n /**\n * Provider-level capability flags. Routed into the message shaper and the\n * agent loop so images in tool results + user messages are handled correctly\n * for the underlying model.\n *\n * Defaults when omitted: `vision: false`, `imageInToolResult: false` — a\n * conservative assumption matching most OSS text-only OpenAI-compat\n * endpoints. Override when routing to a known vision-capable endpoint\n * (e.g. OpenRouter vision models, Baseten image-capable deployments).\n */\n capabilities?: ProviderCapabilities\n /**\n * Whether this endpoint honors `cache_control: { type: 'ephemeral' }` markers\n * on message content parts and tool definitions.\n *\n * - `true` — inject markers when the caller asks for caching. OpenRouter routes\n * to Anthropic/Gemini forward the markers; routes to OpenAI/DeepSeek/\n * Grok/Groq/Moonshot ignore them (those backends cache automatically).\n * - `false` — never inject markers. Safe default for endpoints that strictly\n * validate the request schema (OpenAI direct, most OSS inference\n * servers) and would reject unknown fields.\n *\n * Default: `false`. The `openrouter` wrapper sets this to `true`.\n */\n cacheBreakpoints?: boolean\n /**\n * Whether this endpoint speaks OpenRouter's normalized reasoning envelope —\n * `reasoning: { effort | max_tokens | exclude }` on requests and structured\n * `reasoning_details[]` on assistant messages, round-tripped to preserve\n * extended-reasoning state across turns.\n *\n * - `true` — map zidane's `behavior.thinking` / `behavior.thinkingBudget` to\n * the request's `reasoning` field, capture `reasoning_details`\n * from streaming responses into `provider_reasoning` blocks, and\n * echo them back on subsequent assistant messages.\n * - `false` — never set the field; drop any stored `provider_reasoning`\n * blocks before sending. Safe default for hosts that strict-\n * validate the request schema.\n *\n * Default: `false`. The `openrouter` wrapper sets this to `true`.\n */\n supportsReasoning?: boolean\n /**\n * Generic pass-through for fields on the Chat Completions request body that\n * zidane does not yet type. Spread into the request before the typed core\n * (model / messages / tools / max_tokens / stream / tool_choice), so\n * explicit options always win on collision.\n *\n * Forward-compat escape hatch for endpoints that ship one-off fields ahead\n * of zidane (e.g. OpenAI `reasoning_effort`, OpenRouter `provider` routing,\n * vendor-specific `safety_level` knobs).\n */\n extraBodyParams?: Record<string, unknown>\n}\n\n/**\n * Map zidane's `ThinkingLevel` + optional explicit budget to the OpenRouter\n * `reasoning` request field. Returns `undefined` when reasoning should not be\n * sent (off, or no level + no budget).\n *\n * - `'low' | 'medium' | 'high'` → `{ effort }`.\n * - `'minimal'` → `{ effort: 'low' }` (closest match in OpenRouter's vocabulary).\n * - `'adaptive'` → `{}` (let upstream decide; OpenRouter passes through).\n * - explicit `thinkingBudget` → `{ max_tokens }` overlaid on the level.\n */\nfunction planOpenRouterReasoning(\n thinking: ThinkingLevel | undefined,\n thinkingBudget: number | undefined,\n): Record<string, unknown> | undefined {\n if ((!thinking || thinking === 'off') && typeof thinkingBudget !== 'number')\n return undefined\n const out: Record<string, unknown> = {}\n if (thinking && thinking !== 'off' && thinking !== 'adaptive') {\n out.effort = thinking === 'minimal' ? 'low' : thinking\n }\n if (typeof thinkingBudget === 'number' && thinkingBudget > 0) {\n out.max_tokens = thinkingBudget\n }\n return out\n}\n\n/**\n * Factory for any OpenAI-compatible HTTP endpoint.\n *\n * Speaks the standard `POST /chat/completions` + `stream: true` + SSE dialect.\n * Thin wrappers (`openrouter`, `cerebras`) call this with pinned defaults.\n *\n * @example Baseten (non-standard auth scheme)\n * ```ts\n * openaiCompat({\n * name: 'baseten',\n * apiKey: process.env.BASETEN_API_KEY!,\n * baseURL: process.env.BASETEN_PROXY_URL!,\n * authHeader: { name: 'Authorization', scheme: 'Api-Key' },\n * })\n * ```\n */\nexport function openaiCompat(params: OpenAICompatParams): Provider {\n const name = params.name ?? 'openai-compat'\n const defaultModel = params.defaultModel ?? 'gpt-4o-mini'\n const authHeaderName = params.authHeader?.name ?? 'Authorization'\n const authHeaderValue = params.authHeader?.scheme\n ? `${params.authHeader.scheme} ${params.apiKey}`\n : (params.authHeader ? params.apiKey : `Bearer ${params.apiKey}`)\n const extraHeaders = params.extraHeaders ?? {}\n const endpoint = `${params.baseURL.replace(TRAILING_SLASH_RE, '')}/chat/completions`\n const capabilities: ProviderCapabilities = {\n vision: params.capabilities?.vision ?? false,\n imageInToolResult: params.capabilities?.imageInToolResult ?? false,\n }\n\n const cacheBreakpointsEnabled = params.cacheBreakpoints === true\n const reasoningEnabled = params.supportsReasoning === true\n\n return {\n name,\n meta: { defaultModel, capabilities },\n formatTools,\n userMessage,\n assistantMessage,\n toolResultsMessage,\n classifyError: classifyOpenAICompatError,\n\n async stream(options: StreamOptions, callbacks: StreamCallbacks): Promise<TurnResult> {\n const modelId = options.model || defaultModel\n const messages = toOAIMessages(options.system, options.messages, {\n imageInToolResult: capabilities.imageInToolResult === true,\n supportsReasoning: reasoningEnabled,\n model: modelId,\n })\n // Prompt caching — insert `cache_control: { type: 'ephemeral' }` breakpoints on\n // the system message's last text part, the last tool definition, and the last\n // message's final content part. Only emitted when the factory was constructed\n // with `cacheBreakpoints: true` (set by the `openrouter` wrapper); endpoints\n // that strict-validate the request schema otherwise reject unknown fields.\n const shouldCache = cacheBreakpointsEnabled && options.cache !== false\n if (shouldCache) {\n applyOAICacheBreakpoints(messages)\n }\n\n // max_tokens must cover both thinking budget and response tokens\n const maxTokens = options.thinkingBudget\n ? options.thinkingBudget + options.maxTokens\n : options.maxTokens\n\n const body: Record<string, unknown> = {\n // Spread first so the typed core below wins on collision — explicit\n // always overrides generic.\n ...(params.extraBodyParams ?? {}),\n model: modelId,\n messages,\n max_tokens: maxTokens,\n stream: true,\n }\n\n // OpenRouter normalized reasoning request field. Only set when the host\n // advertises support — Chat Completions hosts that don't speak it would\n // 400 on the unknown field.\n if (reasoningEnabled) {\n const reasoning = planOpenRouterReasoning(options.thinking, options.thinkingBudget)\n if (reasoning)\n body.reasoning = reasoning\n }\n\n if (options.tools && (options.tools as unknown[]).length > 0) {\n body.tools = shouldCache\n ? applyOAIToolCacheBreakpoint(options.tools as OAITool[])\n : options.tools\n }\n\n if (options.toolChoice) {\n if (options.toolChoice.type === 'tool' && options.toolChoice.name)\n body.tool_choice = { type: 'function', 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 const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n [authHeaderName]: authHeaderValue,\n 'Content-Type': 'application/json',\n ...extraHeaders,\n },\n body: JSON.stringify(body),\n signal: options.signal,\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new OpenAICompatHttpError(response.status, errorText)\n }\n\n const result = await consumeSSE(response, callbacks, options.signal)\n const finishReason = mapOAIFinishReason(result.finishReason)\n\n return {\n assistantMessage: buildAssistantContent(\n result.text,\n result.toolCalls,\n result.thinking,\n reasoningEnabled && result.reasoningDetails.length > 0\n ? { details: result.reasoningDetails, producer: 'openrouter', model: modelId }\n : undefined,\n ),\n text: result.text,\n toolCalls: result.toolCalls,\n done: result.finishReason === 'stop' || result.toolCalls.length === 0,\n usage: fillEstimatedCost({\n input: result.usage.input,\n output: result.usage.output,\n ...(result.usage.cacheRead !== undefined ? { cacheRead: result.usage.cacheRead } : {}),\n ...(result.usage.cacheCreation !== undefined ? { cacheCreation: result.usage.cacheCreation } : {}),\n ...(result.usage.cost !== undefined ? { cost: result.usage.cost } : {}),\n ...(finishReason ? { finishReason } : {}),\n modelId,\n }, name),\n }\n },\n }\n}\n","/**\n * Canonical SessionMessage format with converters from/to Anthropic and OpenAI-compat formats.\n */\n\nimport type { SessionContentBlock, SessionMessage, ToolResultContent } from '../types'\nimport { ASSISTANT_TOOL_CALLS_TAG, TOOL_RESULTS_TAG } from '../providers/openai-compat'\n\ntype ToolCallBlock = Extract<SessionContentBlock, { type: 'tool_call' }>\ntype ToolResultBlock = Extract<SessionContentBlock, { type: 'tool_result' }>\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Decode an Anthropic `tool_result.content` wire value back to zidane's canonical\n * `string | ToolResultContent[]` shape.\n *\n * Anthropic accepts three shapes in the wire: `string`, `Array<{type:'text',text}>`,\n * or `Array<{type:'text'|'image', ...}>`. We collapse to `string` only when every\n * block is text to keep simple cases readable.\n */\nfunction decodeAnthropicToolResultContent(content: unknown): string | ToolResultContent[] {\n if (typeof content === 'string')\n return content\n\n if (!Array.isArray(content))\n return JSON.stringify(content)\n\n const blocks: ToolResultContent[] = []\n for (const raw of content) {\n if (!raw || typeof raw !== 'object')\n continue\n const b = raw as Record<string, unknown>\n if (b.type === 'text' && typeof b.text === 'string') {\n blocks.push({ type: 'text', text: b.text })\n continue\n }\n if (b.type === 'image' && b.source && typeof b.source === 'object') {\n const src = b.source as Record<string, unknown>\n if (src.type === 'base64' && typeof src.data === 'string' && typeof src.media_type === 'string') {\n blocks.push({ type: 'image', mediaType: src.media_type, data: src.data })\n continue\n }\n }\n // Unknown block → stringify into text for visibility.\n blocks.push({ type: 'text', text: JSON.stringify(raw) })\n }\n\n if (blocks.length === 0)\n return ''\n\n const hasNonText = blocks.some(b => b.type !== 'text')\n if (!hasNonText)\n return blocks.map(b => (b as { type: 'text', text: string }).text).join('\\n')\n\n return blocks\n}\n\n/**\n * Encode zidane's canonical `string | ToolResultContent[]` shape to Anthropic's\n * wire format for `tool_result.content`.\n */\nfunction encodeAnthropicToolResultContent(\n output: string | ToolResultContent[],\n): string | Array<{ type: 'text', text: string } | { type: 'image', source: { type: 'base64', media_type: string, data: string } }> {\n if (typeof output === 'string')\n return output\n return output.map((b) => {\n if (b.type === 'text')\n return { type: 'text' as const, text: b.text }\n return {\n type: 'image' as const,\n source: { type: 'base64' as const, media_type: b.mediaType, data: b.data },\n }\n })\n}\n\n// ---------------------------------------------------------------------------\n// fromAnthropic\n// ---------------------------------------------------------------------------\n\nexport function fromAnthropic(msg: { role: string, content: unknown }): SessionMessage {\n const role = msg.role as 'user' | 'assistant'\n const content: SessionContentBlock[] = []\n\n if (typeof msg.content === 'string') {\n content.push({ type: 'text', text: msg.content })\n return { role, content }\n }\n\n if (Array.isArray(msg.content)) {\n for (const block of msg.content) {\n if (!block || typeof block !== 'object')\n continue\n const b = block as Record<string, unknown>\n\n if (b.type === 'text') {\n content.push({ type: 'text', text: b.text as string })\n }\n else if (b.type === 'image') {\n const source = b.source as Record<string, unknown>\n if (source?.type === 'base64') {\n content.push({ type: 'image', mediaType: source.media_type as string, data: source.data as string })\n }\n }\n else if (b.type === 'tool_use') {\n content.push({ type: 'tool_call', id: b.id as string, name: b.name as string, input: b.input as Record<string, unknown> })\n }\n else if (b.type === 'tool_result') {\n const output = decodeAnthropicToolResultContent(b.content)\n const block: Extract<SessionContentBlock, { type: 'tool_result' }> = {\n type: 'tool_result',\n callId: b.tool_use_id as string,\n output,\n }\n if (b.is_error === true)\n block.isError = true\n content.push(block)\n }\n else if (b.type === 'thinking') {\n const block: Extract<SessionContentBlock, { type: 'thinking' }> = {\n type: 'thinking',\n text: (b.thinking as string | undefined) ?? '',\n }\n if (typeof b.signature === 'string') {\n block.signature = b.signature\n // Tag the producer so cross-provider senders can drop foreign signatures.\n block.signatureProducer = 'anthropic'\n }\n content.push(block)\n }\n else if (b.type === 'redacted_thinking') {\n // Encrypted reasoning that must be echoed back unmodified to keep\n // interleaved-thinking + tool-use chains working on Sonnet 3.7+/Opus 4.x.\n content.push({ type: 'redacted_thinking', data: (b.data as string | undefined) ?? '' })\n }\n // Unknown block types are silently skipped\n }\n }\n\n return { role, content }\n}\n\n// ---------------------------------------------------------------------------\n// fromOpenAI\n// ---------------------------------------------------------------------------\n\nexport function fromOpenAI(msg: { role: string, content: unknown }): SessionMessage {\n const role = msg.role as 'user' | 'assistant'\n const content: SessionContentBlock[] = []\n const c: unknown = msg.content\n\n if (c == null) {\n return { role, content }\n }\n\n if (typeof c === 'string') {\n content.push({ type: 'text', text: c })\n return { role, content }\n }\n\n if (typeof c === 'object' && !Array.isArray(c) && (c as { _tag?: unknown })._tag === ASSISTANT_TOOL_CALLS_TAG) {\n const tagged = c as { text?: unknown, tool_calls?: unknown }\n if (typeof tagged.text === 'string' && tagged.text) {\n content.push({ type: 'text', text: tagged.text })\n }\n if (Array.isArray(tagged.tool_calls)) {\n for (const raw of tagged.tool_calls) {\n if (!raw || typeof raw !== 'object')\n continue\n const tc = raw as { id?: string, function?: { name?: string, arguments?: unknown } }\n const rawArgs = tc.function?.arguments\n const input: Record<string, unknown> = rawArgs\n ? (typeof rawArgs === 'string' ? JSON.parse(rawArgs) : rawArgs as Record<string, unknown>)\n : {}\n content.push({ type: 'tool_call', id: tc.id ?? '', name: tc.function?.name ?? '', input })\n }\n }\n return { role, content }\n }\n\n if (typeof c === 'object' && !Array.isArray(c) && (c as { _tag?: unknown })._tag === TOOL_RESULTS_TAG) {\n const tagged = c as { results?: unknown }\n if (Array.isArray(tagged.results)) {\n for (const raw of tagged.results) {\n if (!raw || typeof raw !== 'object')\n continue\n const r = raw as { tool_call_id?: string, content?: string | ToolResultContent[] }\n content.push({ type: 'tool_result', callId: r.tool_call_id ?? '', output: r.content ?? '' })\n }\n }\n return { role, content }\n }\n\n if (Array.isArray(c)) {\n for (const block of c) {\n if (!block || typeof block !== 'object')\n continue\n const b = block as Record<string, unknown>\n\n if (b.type === 'text') {\n content.push({ type: 'text', text: b.text as string })\n }\n else if (b.type === 'image_url') {\n const imageUrl = (b.image_url as Record<string, unknown>)?.url as string\n if (imageUrl?.startsWith('data:')) {\n const [meta, data] = imageUrl.slice(5).split(',', 2)\n const mediaType = meta.replace(';base64', '')\n content.push({ type: 'image', mediaType, data })\n }\n }\n }\n return { role, content }\n }\n\n return { role, content }\n}\n\n// ---------------------------------------------------------------------------\n// toAnthropic\n// ---------------------------------------------------------------------------\n\nexport function toAnthropic(msg: SessionMessage): { role: string, content: unknown } {\n const blocks = msg.content\n // Drop foreign reasoning state. Three independent rejection paths,\n // each driven by an Anthropic API constraint we've hit in production:\n //\n // 1. `signatureProducer === 'openai'` — OpenAI's `encrypted_content`\n // isn't a valid Anthropic HMAC; sending it 400s with an unhelpful\n // \"invalid signature\" error.\n // 2. `type === 'thinking' && !signature` — Anthropic's\n // `ThinkingBlockParam` requires a signature field. A non-Anthropic\n // producer that doesn't sign thinking (Cerebras, Gemini, OSS via\n // OpenAI-compat, etc.) leaves a block in the session that 400s\n // here with `messages.N.content.M.thinking.signature: Field\n // required` the next time the user picks an Anthropic model. Drop\n // them — the model can re-think on its own turn, no info loss\n // beyond the prior provider's chain-of-thought, which Anthropic\n // can't consume anyway.\n // 3. `type === 'provider_reasoning'` — opaque OpenRouter envelope;\n // not an Anthropic block type at all.\n .filter((b) => {\n if (b.type === 'provider_reasoning')\n return false\n if (b.type !== 'thinking')\n return true\n if (b.signatureProducer === 'openai')\n return false\n if (!b.signature)\n return false\n return true\n })\n .map((block) => {\n switch (block.type) {\n case 'text':\n return { type: 'text', text: block.text }\n case 'image':\n return { type: 'image', source: { type: 'base64', media_type: block.mediaType, data: block.data } }\n case 'tool_call':\n return { type: 'tool_use', id: block.id, name: block.name, input: block.input }\n case 'tool_result': {\n const out: Record<string, unknown> = {\n type: 'tool_result',\n tool_use_id: block.callId,\n content: encodeAnthropicToolResultContent(block.output),\n }\n if (block.isError)\n out.is_error = true\n return out\n }\n case 'thinking': {\n // Filter above guarantees `signature` is present and either\n // anthropic-produced or legacy (back-compat for pre-tagging\n // Anthropic sessions where producer was never recorded).\n return { type: 'thinking', thinking: block.text, signature: block.signature }\n }\n case 'redacted_thinking':\n return { type: 'redacted_thinking', data: block.data }\n default:\n return { type: 'text', text: '' }\n }\n })\n\n // Simplify to plain string if only one text block\n if (blocks.length === 1 && blocks[0].type === 'text') {\n return { role: msg.role, content: (blocks[0] as { type: string, text: string }).text }\n }\n\n return { role: msg.role, content: blocks }\n}\n\n// ---------------------------------------------------------------------------\n// toOpenAI\n// ---------------------------------------------------------------------------\n\nexport function toOpenAI(msg: SessionMessage): { role: string, content: unknown } {\n const toolCalls = msg.content.filter(b => b.type === 'tool_call')\n const toolResults = msg.content.filter(b => b.type === 'tool_result')\n const textBlocks = msg.content.filter(b => b.type === 'text')\n const imageBlocks = msg.content.filter(b => b.type === 'image')\n\n // Tool results → tagged format\n if (toolResults.length > 0) {\n return {\n role: msg.role,\n content: {\n _tag: TOOL_RESULTS_TAG,\n results: toolResults.map((b) => {\n const tr = b as Extract<SessionContentBlock, { type: 'tool_result' }>\n return { tool_call_id: tr.callId, content: tr.output }\n }),\n },\n }\n }\n\n // Tool calls → tagged format\n if (toolCalls.length > 0) {\n const textContent = textBlocks.length > 0 ? (textBlocks[0] as Extract<SessionContentBlock, { type: 'text' }>).text : null\n return {\n role: msg.role,\n content: {\n _tag: ASSISTANT_TOOL_CALLS_TAG,\n text: textContent,\n tool_calls: toolCalls.map((b) => {\n const tc = b as Extract<SessionContentBlock, { type: 'tool_call' }>\n return {\n id: tc.id,\n type: 'function',\n function: { name: tc.name, arguments: JSON.stringify(tc.input) },\n }\n }),\n },\n }\n }\n\n // Images → multimodal array\n if (imageBlocks.length > 0) {\n const parts: unknown[] = imageBlocks.map((b) => {\n const img = b as Extract<SessionContentBlock, { type: 'image' }>\n return { type: 'image_url', image_url: { url: `data:${img.mediaType};base64,${img.data}` } }\n })\n for (const b of textBlocks) {\n parts.push({ type: 'text', text: (b as Extract<SessionContentBlock, { type: 'text' }>).text })\n }\n return { role: msg.role, content: parts }\n }\n\n // Pure text → string\n if (textBlocks.length === 1) {\n return { role: msg.role, content: (textBlocks[0] as Extract<SessionContentBlock, { type: 'text' }>).text }\n }\n\n // Multiple text blocks or empty\n if (textBlocks.length > 1) {\n return { role: msg.role, content: textBlocks.map(b => ({ type: 'text', text: (b as Extract<SessionContentBlock, { type: 'text' }>).text })) }\n }\n\n return { role: msg.role, content: null }\n}\n\n// ---------------------------------------------------------------------------\n// autoDetectAndConvert\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// sanitizeOrphanedToolCalls\n// ---------------------------------------------------------------------------\n\n/**\n * Drop assistant `tool_call` blocks whose `id` has no matching\n * `tool_result.callId` in the immediately-following user message, and drop\n * user `tool_result` blocks whose `callId` has no match in the\n * immediately-preceding assistant message.\n *\n * Anthropic strictly requires every `tool_use` block to be paired with a\n * `tool_result` block in the next user message (`messages.N: 'tool_use' ids\n * were found without 'tool_result' blocks immediately after`). OpenAI is\n * looser but still rejects most mismatches. Orphans reach the wire layer from:\n *\n * 1. Interrupted runs (signal, crash, network drop) between persisting the\n * assistant turn (`turn:after`) and persisting its tool results turn\n * (`tool-results:after`).\n * 2. The schema-enforcement path — a synthetic `__output__` assistant\n * tool_call is appended without a matching tool_result. Any resume after\n * that turn would 400 without this pass.\n * 3. Consumer `context:transform` hooks that prune messages without\n * preserving the `tool_use ↔ tool_result` pairing.\n *\n * Strategy: drop the orphan blocks rather than synthesizing fake results —\n * the model never sees a half-done call, so it can't confabulate on phantom\n * outputs. Messages emptied by the cleanup are removed entirely (providers\n * reject empty `content` arrays).\n *\n * Adjacency rules:\n * - Assistant tool_calls are matched against the ORIGINAL next user message\n * (the wire still has to satisfy the per-message adjacency contract).\n * - User tool_results are matched against the previously-emitted message in\n * the cleaned output, so a tool_result whose entire assistant prefix was\n * dropped cascades and gets dropped too.\n *\n * Idempotent: returns the input reference when no orphans are found.\n */\nexport function sanitizeOrphanedToolCalls(messages: SessionMessage[]): SessionMessage[] {\n if (messages.length === 0)\n return messages\n\n const out: SessionMessage[] = []\n let changed = false\n\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]\n\n if (msg.role === 'assistant') {\n const callIds = collectIds<ToolCallBlock>(msg.content, 'tool_call', b => b.id)\n if (callIds.size === 0) {\n out.push(msg)\n continue\n }\n const next = messages[i + 1]\n const matched = next && next.role === 'user'\n ? intersectIds<ToolResultBlock>(next.content, 'tool_result', b => b.callId, callIds)\n : new Set<string>()\n if (matched.size === callIds.size) {\n out.push(msg)\n continue\n }\n const cleaned = msg.content.filter(b => b.type !== 'tool_call' || matched.has(b.id))\n changed = true\n if (cleaned.length > 0)\n out.push({ ...msg, content: cleaned })\n continue\n }\n\n const hasResult = msg.content.some(b => b.type === 'tool_result')\n if (!hasResult) {\n out.push(msg)\n continue\n }\n const prev = out.length > 0 ? out[out.length - 1] : null\n const validIds = prev && prev.role === 'assistant'\n ? collectIds<ToolCallBlock>(prev.content, 'tool_call', b => b.id)\n : new Set<string>()\n const cleaned = msg.content.filter(b => b.type !== 'tool_result' || validIds.has(b.callId))\n if (cleaned.length === msg.content.length) {\n out.push(msg)\n continue\n }\n changed = true\n if (cleaned.length > 0)\n out.push({ ...msg, content: cleaned })\n }\n\n return changed ? out : messages\n}\n\nfunction collectIds<B extends SessionContentBlock>(\n content: SessionContentBlock[],\n type: B['type'],\n getId: (block: B) => string,\n): Set<string> {\n const ids = new Set<string>()\n for (const block of content) {\n if (block.type === type)\n ids.add(getId(block as B))\n }\n return ids\n}\n\nfunction intersectIds<B extends SessionContentBlock>(\n content: SessionContentBlock[],\n type: B['type'],\n getId: (block: B) => string,\n candidates: Set<string>,\n): Set<string> {\n const matched = new Set<string>()\n for (const block of content) {\n if (block.type !== type)\n continue\n const id = getId(block as B)\n if (candidates.has(id))\n matched.add(id)\n }\n return matched\n}\n\nexport function autoDetectAndConvert(msg: { role: string, content: unknown }): SessionMessage {\n const c: unknown = msg.content\n\n // OpenAI-compat tagged messages\n if (c && typeof c === 'object' && !Array.isArray(c)) {\n const tag = (c as { _tag?: unknown })._tag\n if (typeof tag === 'string' && tag.startsWith('__zidane_'))\n return fromOpenAI(msg)\n }\n\n // Array: inspect block types\n if (Array.isArray(c)) {\n for (const block of c) {\n if (!block || typeof block !== 'object')\n continue\n const b = block as Record<string, unknown>\n if (b.type === 'tool_use' || (b.type === 'tool_result' && 'tool_use_id' in b)) {\n return fromAnthropic(msg)\n }\n if (b.type === 'image_url') {\n return fromOpenAI(msg)\n }\n }\n // Default array → Anthropic\n return fromAnthropic(msg)\n }\n\n // String → either format is the same\n if (typeof c === 'string') {\n return fromAnthropic(msg)\n }\n\n // Default\n return fromAnthropic(msg)\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { a as multiEdit, i as readFile, n as createSpawnTool, o as listFiles, r as shell, t as writeFile, u as edit } from "./tools-BoHVy2UM.js";
1
+ import { a as multiEdit, i as readFile, n as createSpawnTool, o as listFiles, r as shell, t as writeFile, u as edit } from "./tools-BG2wMa3X.js";
2
2
  //#region src/presets/basic.ts
3
3
  /**
4
4
  * Core tools available in every basic preset (without spawn).
@@ -87,4 +87,4 @@ function composePresets(...presets) {
87
87
  //#endregion
88
88
  export { basic_default as i, definePreset as n, basicTools as r, composePresets as t };
89
89
 
90
- //# sourceMappingURL=presets-CYNTGGXg.js.map
90
+ //# sourceMappingURL=presets-Ce79MK4J.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"presets-CYNTGGXg.js","names":[],"sources":["../src/presets/basic.ts","../src/presets/index.ts"],"sourcesContent":["import { definePreset } from '.'\nimport { edit, listFiles, multiEdit, readFile, shell, writeFile } from '../tools'\nimport { createSpawnTool } from '../tools/spawn'\n\n/**\n * Core tools available in every basic preset (without spawn).\n *\n * `edit` and `multi_edit` ship in the basic set because surgical edits are the\n * default modality for production agents — `write_file` is for full overwrites.\n * `glob` and `grep` are exported but opt-in: not every agent needs codebase\n * search, and shipping them by default would force `tool:gate` work onto\n * consumers that prefer the model to use `shell` + classic Unix tools.\n */\nexport const basicTools = { shell, readFile, writeFile, listFiles, edit, multiEdit }\n\nexport default definePreset({\n name: 'basic',\n system: 'You are a helpful assistant with access to shell, file reading, file writing, surgical and multi-edit tools, directory listing, and sub-agent spawning. Prefer `edit` / `multi_edit` for in-place changes and `write_file` for full file overwrites. Use them to accomplish tasks in the project directory.',\n // `persist: true` shares the parent's session with every child agent — child\n // turns land in `session.turns` tagged with their own `runId`, and the run\n // itself is recorded in `session.runs` with `parentRunId` + `depth`. That's\n // what lets a reloaded TUI session reconstruct the full subagent tree (see\n // `eventsFromTurns` in `tui/store.ts`). Hosts that want children in-memory\n // only can construct their own preset with `createSpawnTool()`.\n tools: { ...basicTools, spawn: createSpawnTool({ persist: true }) },\n})\n","import type { AgentHooks, AgentOptions } from '../agent'\n\nexport type { AgentHookMap } from '../agent'\n\n/**\n * A preset is a reusable slice of `AgentOptions` — spread it into `createAgent()`\n * to configure tools, a default system prompt, aliases, behavior defaults, and\n * agent-lifetime hooks.\n *\n * `provider`, `execution`, `session`, and internal fields are excluded so presets\n * remain shareable and composable.\n *\n * ```ts\n * import { basic } from 'zidane/presets'\n * createAgent({ ...basic, provider })\n * ```\n *\n * ### Composing multiple presets\n *\n * Bare `...spread` is shallow — `{ ...a, ...b }` overwrites every key `b`\n * defines, including `hooks`. Use {@link composePresets} when you want\n * field-aware merging (per-event hook concat, tools shallow-merge, etc.):\n *\n * ```ts\n * createAgent({ ...composePresets(basic, telemetry, mine), provider })\n * ```\n */\nexport type Preset = Omit<Partial<AgentOptions>, 'provider' | 'execution' | 'session' | 'mcpConnector'>\n\n/**\n * Identity helper for type inference when defining a preset.\n */\nexport function definePreset(config: Preset): Preset {\n return config\n}\n\n/**\n * Field-aware composition of presets. Right-most preset wins for scalar fields;\n * objects shallow-merge; arrays and hook handler lists concatenate. Designed so\n * stacking presets does the obvious thing without the spread-collision footgun:\n *\n * - `name`, `system`, `eager`, `skills` → last-defined wins\n * - `tools`, `toolAliases`, `behavior` → shallow-merge (later keys override)\n * - `mcpServers` → concat with last-wins on `name` collision\n * - `hooks` → per-event concat; every handler fires\n *\n * `hooks` always emerges as `event → handler[]` so downstream registration\n * (in `createAgent`) sees a uniform shape. Order of handlers within an event\n * follows preset order: earlier presets register first.\n *\n * `mcpServers` is deduped by `name` because shipping two servers with the same\n * name would trip the connector at runtime — a later preset overriding an\n * earlier preset's `github` server is the practical intent.\n */\nexport function composePresets(...presets: Preset[]): Preset {\n const out: Preset = {}\n const hooksByEvent: { [K in keyof AgentHooks]?: AgentHooks[K][] } = {}\n // Keep mcpServers in source-order on first sight, but allow later\n // declarations to override earlier ones with the same `name`. A `Map`\n // keyed by name gives O(1) override + stable iteration.\n const mcpByName = new Map<string, NonNullable<Preset['mcpServers']>[number]>()\n\n for (const p of presets) {\n if (p.name !== undefined)\n out.name = p.name\n if (p.system !== undefined)\n out.system = p.system\n if (p.eager !== undefined)\n out.eager = p.eager\n if (p.skills !== undefined)\n out.skills = p.skills\n if (p.tools)\n out.tools = { ...out.tools, ...p.tools }\n if (p.toolAliases)\n out.toolAliases = { ...out.toolAliases, ...p.toolAliases }\n if (p.behavior)\n out.behavior = { ...out.behavior, ...p.behavior }\n if (p.mcpServers) {\n for (const server of p.mcpServers)\n mcpByName.set(server.name, server)\n }\n if (p.hooks) {\n for (const [event, handler] of Object.entries(p.hooks)) {\n if (handler === undefined)\n continue\n const list = Array.isArray(handler) ? handler : [handler]\n const key = event as keyof AgentHooks\n // Safe cast: we read the loose `AgentHookMap` shape (handler-or-array)\n // and re-emit only as arrays. Each `list` element matches the event's\n // handler signature by construction (the input was typed `AgentHookMap`).\n const bucket = (hooksByEvent[key] ??= []) as unknown[]\n bucket.push(...(list as unknown[]))\n }\n }\n }\n\n if (mcpByName.size > 0)\n out.mcpServers = [...mcpByName.values()]\n\n if (Object.keys(hooksByEvent).length > 0)\n out.hooks = hooksByEvent\n\n return out\n}\n\nexport { default as basic, basicTools } from './basic'\n"],"mappings":";;;;;;;;;;;AAaA,MAAa,aAAa;CAAE;CAAO;CAAU;CAAW;CAAW;CAAM;CAAW;AAEpF,IAAA,gBAAe,aAAa;CAC1B,MAAM;CACN,QAAQ;CAOR,OAAO;EAAE,GAAG;EAAY,OAAO,gBAAgB,EAAE,SAAS,MAAM,CAAC;EAAE;CACpE,CAAC;;;;;;ACOF,SAAgB,aAAa,QAAwB;CACnD,OAAO;;;;;;;;;;;;;;;;;;;;AAqBT,SAAgB,eAAe,GAAG,SAA2B;CAC3D,MAAM,MAAc,EAAE;CACtB,MAAM,eAA8D,EAAE;CAItE,MAAM,4BAAY,IAAI,KAAwD;CAE9E,KAAK,MAAM,KAAK,SAAS;EACvB,IAAI,EAAE,SAAS,KAAA,GACb,IAAI,OAAO,EAAE;EACf,IAAI,EAAE,WAAW,KAAA,GACf,IAAI,SAAS,EAAE;EACjB,IAAI,EAAE,UAAU,KAAA,GACd,IAAI,QAAQ,EAAE;EAChB,IAAI,EAAE,WAAW,KAAA,GACf,IAAI,SAAS,EAAE;EACjB,IAAI,EAAE,OACJ,IAAI,QAAQ;GAAE,GAAG,IAAI;GAAO,GAAG,EAAE;GAAO;EAC1C,IAAI,EAAE,aACJ,IAAI,cAAc;GAAE,GAAG,IAAI;GAAa,GAAG,EAAE;GAAa;EAC5D,IAAI,EAAE,UACJ,IAAI,WAAW;GAAE,GAAG,IAAI;GAAU,GAAG,EAAE;GAAU;EACnD,IAAI,EAAE,YACJ,KAAK,MAAM,UAAU,EAAE,YACrB,UAAU,IAAI,OAAO,MAAM,OAAO;EAEtC,IAAI,EAAE,OACJ,KAAK,MAAM,CAAC,OAAO,YAAY,OAAO,QAAQ,EAAE,MAAM,EAAE;GACtD,IAAI,YAAY,KAAA,GACd;GACF,MAAM,OAAO,MAAM,QAAQ,QAAQ,GAAG,UAAU,CAAC,QAAQ;GACzD,MAAM,MAAM;GAKZ,CADgB,aAAa,SAAS,EAAE,EACjC,KAAK,GAAI,KAAmB;;;CAKzC,IAAI,UAAU,OAAO,GACnB,IAAI,aAAa,CAAC,GAAG,UAAU,QAAQ,CAAC;CAE1C,IAAI,OAAO,KAAK,aAAa,CAAC,SAAS,GACrC,IAAI,QAAQ;CAEd,OAAO"}
1
+ {"version":3,"file":"presets-Ce79MK4J.js","names":[],"sources":["../src/presets/basic.ts","../src/presets/index.ts"],"sourcesContent":["import { definePreset } from '.'\nimport { edit, listFiles, multiEdit, readFile, shell, writeFile } from '../tools'\nimport { createSpawnTool } from '../tools/spawn'\n\n/**\n * Core tools available in every basic preset (without spawn).\n *\n * `edit` and `multi_edit` ship in the basic set because surgical edits are the\n * default modality for production agents — `write_file` is for full overwrites.\n * `glob` and `grep` are exported but opt-in: not every agent needs codebase\n * search, and shipping them by default would force `tool:gate` work onto\n * consumers that prefer the model to use `shell` + classic Unix tools.\n */\nexport const basicTools = { shell, readFile, writeFile, listFiles, edit, multiEdit }\n\nexport default definePreset({\n name: 'basic',\n system: 'You are a helpful assistant with access to shell, file reading, file writing, surgical and multi-edit tools, directory listing, and sub-agent spawning. Prefer `edit` / `multi_edit` for in-place changes and `write_file` for full file overwrites. Use them to accomplish tasks in the project directory.',\n // `persist: true` shares the parent's session with every child agent — child\n // turns land in `session.turns` tagged with their own `runId`, and the run\n // itself is recorded in `session.runs` with `parentRunId` + `depth`. That's\n // what lets a reloaded TUI session reconstruct the full subagent tree (see\n // `eventsFromTurns` in `tui/store.ts`). Hosts that want children in-memory\n // only can construct their own preset with `createSpawnTool()`.\n tools: { ...basicTools, spawn: createSpawnTool({ persist: true }) },\n})\n","import type { AgentHooks, AgentOptions } from '../agent'\n\nexport type { AgentHookMap } from '../agent'\n\n/**\n * A preset is a reusable slice of `AgentOptions` — spread it into `createAgent()`\n * to configure tools, a default system prompt, aliases, behavior defaults, and\n * agent-lifetime hooks.\n *\n * `provider`, `execution`, `session`, and internal fields are excluded so presets\n * remain shareable and composable.\n *\n * ```ts\n * import { basic } from 'zidane/presets'\n * createAgent({ ...basic, provider })\n * ```\n *\n * ### Composing multiple presets\n *\n * Bare `...spread` is shallow — `{ ...a, ...b }` overwrites every key `b`\n * defines, including `hooks`. Use {@link composePresets} when you want\n * field-aware merging (per-event hook concat, tools shallow-merge, etc.):\n *\n * ```ts\n * createAgent({ ...composePresets(basic, telemetry, mine), provider })\n * ```\n */\nexport type Preset = Omit<Partial<AgentOptions>, 'provider' | 'execution' | 'session' | 'mcpConnector'>\n\n/**\n * Identity helper for type inference when defining a preset.\n */\nexport function definePreset(config: Preset): Preset {\n return config\n}\n\n/**\n * Field-aware composition of presets. Right-most preset wins for scalar fields;\n * objects shallow-merge; arrays and hook handler lists concatenate. Designed so\n * stacking presets does the obvious thing without the spread-collision footgun:\n *\n * - `name`, `system`, `eager`, `skills` → last-defined wins\n * - `tools`, `toolAliases`, `behavior` → shallow-merge (later keys override)\n * - `mcpServers` → concat with last-wins on `name` collision\n * - `hooks` → per-event concat; every handler fires\n *\n * `hooks` always emerges as `event → handler[]` so downstream registration\n * (in `createAgent`) sees a uniform shape. Order of handlers within an event\n * follows preset order: earlier presets register first.\n *\n * `mcpServers` is deduped by `name` because shipping two servers with the same\n * name would trip the connector at runtime — a later preset overriding an\n * earlier preset's `github` server is the practical intent.\n */\nexport function composePresets(...presets: Preset[]): Preset {\n const out: Preset = {}\n const hooksByEvent: { [K in keyof AgentHooks]?: AgentHooks[K][] } = {}\n // Keep mcpServers in source-order on first sight, but allow later\n // declarations to override earlier ones with the same `name`. A `Map`\n // keyed by name gives O(1) override + stable iteration.\n const mcpByName = new Map<string, NonNullable<Preset['mcpServers']>[number]>()\n\n for (const p of presets) {\n if (p.name !== undefined)\n out.name = p.name\n if (p.system !== undefined)\n out.system = p.system\n if (p.eager !== undefined)\n out.eager = p.eager\n if (p.skills !== undefined)\n out.skills = p.skills\n if (p.tools)\n out.tools = { ...out.tools, ...p.tools }\n if (p.toolAliases)\n out.toolAliases = { ...out.toolAliases, ...p.toolAliases }\n if (p.behavior)\n out.behavior = { ...out.behavior, ...p.behavior }\n if (p.mcpServers) {\n for (const server of p.mcpServers)\n mcpByName.set(server.name, server)\n }\n if (p.hooks) {\n for (const [event, handler] of Object.entries(p.hooks)) {\n if (handler === undefined)\n continue\n const list = Array.isArray(handler) ? handler : [handler]\n const key = event as keyof AgentHooks\n // Safe cast: we read the loose `AgentHookMap` shape (handler-or-array)\n // and re-emit only as arrays. Each `list` element matches the event's\n // handler signature by construction (the input was typed `AgentHookMap`).\n const bucket = (hooksByEvent[key] ??= []) as unknown[]\n bucket.push(...(list as unknown[]))\n }\n }\n }\n\n if (mcpByName.size > 0)\n out.mcpServers = [...mcpByName.values()]\n\n if (Object.keys(hooksByEvent).length > 0)\n out.hooks = hooksByEvent\n\n return out\n}\n\nexport { default as basic, basicTools } from './basic'\n"],"mappings":";;;;;;;;;;;AAaA,MAAa,aAAa;CAAE;CAAO;CAAU;CAAW;CAAW;CAAM;CAAW;AAEpF,IAAA,gBAAe,aAAa;CAC1B,MAAM;CACN,QAAQ;CAOR,OAAO;EAAE,GAAG;EAAY,OAAO,gBAAgB,EAAE,SAAS,MAAM,CAAC;EAAE;CACpE,CAAC;;;;;;ACOF,SAAgB,aAAa,QAAwB;CACnD,OAAO;;;;;;;;;;;;;;;;;;;;AAqBT,SAAgB,eAAe,GAAG,SAA2B;CAC3D,MAAM,MAAc,EAAE;CACtB,MAAM,eAA8D,EAAE;CAItE,MAAM,4BAAY,IAAI,KAAwD;CAE9E,KAAK,MAAM,KAAK,SAAS;EACvB,IAAI,EAAE,SAAS,KAAA,GACb,IAAI,OAAO,EAAE;EACf,IAAI,EAAE,WAAW,KAAA,GACf,IAAI,SAAS,EAAE;EACjB,IAAI,EAAE,UAAU,KAAA,GACd,IAAI,QAAQ,EAAE;EAChB,IAAI,EAAE,WAAW,KAAA,GACf,IAAI,SAAS,EAAE;EACjB,IAAI,EAAE,OACJ,IAAI,QAAQ;GAAE,GAAG,IAAI;GAAO,GAAG,EAAE;GAAO;EAC1C,IAAI,EAAE,aACJ,IAAI,cAAc;GAAE,GAAG,IAAI;GAAa,GAAG,EAAE;GAAa;EAC5D,IAAI,EAAE,UACJ,IAAI,WAAW;GAAE,GAAG,IAAI;GAAU,GAAG,EAAE;GAAU;EACnD,IAAI,EAAE,YACJ,KAAK,MAAM,UAAU,EAAE,YACrB,UAAU,IAAI,OAAO,MAAM,OAAO;EAEtC,IAAI,EAAE,OACJ,KAAK,MAAM,CAAC,OAAO,YAAY,OAAO,QAAQ,EAAE,MAAM,EAAE;GACtD,IAAI,YAAY,KAAA,GACd;GACF,MAAM,OAAO,MAAM,QAAQ,QAAQ,GAAG,UAAU,CAAC,QAAQ;GACzD,MAAM,MAAM;GAKZ,CADgB,aAAa,SAAS,EAAE,EACjC,KAAK,GAAI,KAAmB;;;CAKzC,IAAI,UAAU,OAAO,GACnB,IAAI,aAAa,CAAC,GAAG,UAAU,QAAQ,CAAC;CAE1C,IAAI,OAAO,KAAK,aAAa,CAAC,SAAS,GACrC,IAAI,QAAQ;CAEd,OAAO"}
package/dist/presets.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { n as AgentHookMap } from "./agent-D0pXl4CO.js";
2
- import { a as basicTools, i as _default, n as composePresets, r as definePreset, t as Preset } from "./index-n4STKh9s.js";
1
+ import { n as AgentHookMap } from "./agent-skiQGYs2.js";
2
+ import { a as basicTools, i as _default, n as composePresets, r as definePreset, t as Preset } from "./index-CjPh6CRE.js";
3
3
  export { AgentHookMap, Preset, _default as basic, basicTools, composePresets, definePreset };
package/dist/presets.js CHANGED
@@ -1,2 +1,2 @@
1
- import { i as basic_default, n as definePreset, r as basicTools, t as composePresets } from "./presets-CYNTGGXg.js";
1
+ import { i as basic_default, n as definePreset, r as basicTools, t as composePresets } from "./presets-Ce79MK4J.js";
2
2
  export { basic_default as basic, basicTools, composePresets, definePreset };
@@ -1,9 +1,9 @@
1
1
  import { o as matchesContextExceeded } from "./errors-D1lhd6mX.js";
2
- import { a as toAnthropic, c as assistantMessage, d as openaiCompat, f as toolResultsMessage, n as fromAnthropic, p as userMessage } from "./messages-DiAiNhxA.js";
2
+ import { a as toAnthropic, c as assistantMessage, d as openaiCompat, f as toolResultsMessage, m as fillEstimatedCost, n as fromAnthropic, p as userMessage } from "./messages-CIkO_aCH.js";
3
3
  import { resolve } from "node:path";
4
+ import { getModel } from "@mariozechner/pi-ai";
4
5
  import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
5
6
  import { getOAuthApiKey } from "@mariozechner/pi-ai/oauth";
6
- import { getModel } from "@mariozechner/pi-ai";
7
7
  import { streamOpenAICodexResponses } from "@mariozechner/pi-ai/openai-codex-responses";
8
8
  //#region src/providers/oauth.ts
9
9
  /**
@@ -78,11 +78,30 @@ function readOAuthCredentials() {
78
78
  * the same filesystem, so readers either see the old file or the new one —
79
79
  * never a half-written one. This matters when a host has multiple processes
80
80
  * pointed at the same creds file.
81
+ *
82
+ * Merges the incoming OAuth entries on top of the raw file contents so that
83
+ * entries this layer doesn't manage (e.g. `kind: 'apikey'` from the TUI
84
+ * wizard) survive an OAuth refresh cycle. Without this merge,
85
+ * `readOAuthCredentials` filters those entries out, and a naive overwrite
86
+ * would delete them.
81
87
  */
82
88
  function writeOAuthCredentials(credentials) {
83
89
  const path = credentialsFilePath();
90
+ let existing = {};
91
+ try {
92
+ if (existsSync(path)) {
93
+ const raw = readFileSync(path, "utf-8");
94
+ const parsed = JSON.parse(raw);
95
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) existing = parsed;
96
+ }
97
+ } catch {}
98
+ const merged = {
99
+ ...existing,
100
+ ...credentials
101
+ };
102
+ for (const [key, value] of Object.entries(merged)) if (value === void 0) delete merged[key];
84
103
  const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
85
- writeFileSync(tmp, JSON.stringify(credentials, null, 2), { mode: CREDENTIALS_FILE_MODE });
104
+ writeFileSync(tmp, JSON.stringify(merged, null, 2), { mode: CREDENTIALS_FILE_MODE });
86
105
  renameSync(tmp, path);
87
106
  }
88
107
  function credentialsFromParams(params, extraKeys = []) {
@@ -616,14 +635,14 @@ function anthropic(anthropicParams) {
616
635
  text,
617
636
  toolCalls,
618
637
  done: !isPause && (response.stop_reason === "end_turn" || toolCalls.length === 0),
619
- usage: {
638
+ usage: fillEstimatedCost({
620
639
  input: response.usage.input_tokens,
621
640
  output: response.usage.output_tokens,
622
641
  cacheCreation: response.usage.cache_creation_input_tokens ?? void 0,
623
642
  cacheRead: response.usage.cache_read_input_tokens ?? void 0,
624
643
  ...finishReason ? { finishReason } : {},
625
644
  modelId: response.model ?? options.model
626
- }
645
+ }, "anthropic")
627
646
  };
628
647
  }
629
648
  };
@@ -814,7 +833,7 @@ function extractText(message) {
814
833
  return message.content.filter((block) => block.type === "text").map((block) => block.text).join("");
815
834
  }
816
835
  function toTurnUsage(usage, finishReason, modelId) {
817
- return {
836
+ return fillEstimatedCost({
818
837
  input: usage.input,
819
838
  output: usage.output,
820
839
  cacheRead: usage.cacheRead || void 0,
@@ -822,7 +841,7 @@ function toTurnUsage(usage, finishReason, modelId) {
822
841
  cost: usage.cost.total || void 0,
823
842
  ...finishReason ? { finishReason } : {},
824
843
  modelId
825
- };
844
+ }, "openai");
826
845
  }
827
846
  /**
828
847
  * Classify an OpenAI Codex error. pi-ai surfaces errors either as thrown `Error`s
@@ -987,4 +1006,4 @@ function openrouter(params) {
987
1006
  //#endregion
988
1007
  export { anthropic as i, openai as n, cerebras as r, openrouter as t };
989
1008
 
990
- //# sourceMappingURL=providers-6bqfXUd1.js.map
1009
+ //# sourceMappingURL=providers-CvriFHFU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers-CvriFHFU.js","names":["BASE_URL","getApiKey"],"sources":["../src/providers/oauth.ts","../src/providers/anthropic.ts","../src/providers/cerebras.ts","../src/providers/openai.ts","../src/providers/openrouter.ts"],"sourcesContent":["import type { OAuthCredentials } from '@mariozechner/pi-ai/oauth'\nimport type { StreamCallbacks } from '.'\nimport type { OAuthRefreshHookContext } from '../types'\nimport { existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { getOAuthApiKey } from '@mariozechner/pi-ai/oauth'\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\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.\n if (typeof v.access === 'string')\n result[key] = v as unknown as OAuthCredentials\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 const tmp = `${path}.${process.pid}.${Date.now()}.tmp`\n writeFileSync(tmp, JSON.stringify(merged, null, 2), { mode: CREDENTIALS_FILE_MODE })\n renameSync(tmp, path)\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 const reason = err instanceof Error ? err.message : String(err)\n throw new Error(options.refreshError(reason))\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<T extends string>(\n key: string,\n fn: () => Promise<T>,\n): Promise<T> {\n const existing = refreshLocks.get(key) as Promise<T> | undefined\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 as unknown as Promise<string>)\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 { matchesContextExceeded } from '../errors'\nimport { fromAnthropic, toAnthropic } from '../session/messages'\nimport { fillEstimatedCost } from './cost'\nimport { readOAuthCredentials, resolveOAuthApiKey } from './oauth'\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 {\n apiKey?: string\n access?: string\n refresh?: string\n expires?: number\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 * 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 — last text block.\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 */\nexport function applyAnthropicCacheBreakpoints(params: Anthropic.MessageCreateParamsStreaming): void {\n if (typeof params.system === 'string') {\n if (params.system.length > 0) {\n params.system = [{ type: 'text', text: params.system, cache_control: EPHEMERAL }]\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.Tool[]\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 * Classify an Anthropic SDK / HTTP error for typed-error wrapping.\n *\n * - `prompt is too long` (400 invalid_request_error) → `context_exceeded`.\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 if (!err || typeof err !== 'object')\n return null\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 if (anyErr.name === 'AbortError')\n return { kind: 'aborted' }\n\n if (!looksLikeAnthropicApiError(err))\n return null\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 const status = anyErr.status\n const retryable = typeof status === 'number'\n ? status === 429 || (status >= 500 && status !== 501)\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-7'\n let runtimeCredentials = (\n typeof anthropicParams?.access === 'string'\n && typeof anthropicParams.refresh === 'string'\n && typeof anthropicParams.expires === 'number'\n )\n ? {\n access: anthropicParams.access,\n refresh: anthropicParams.refresh,\n expires: anthropicParams.expires,\n }\n : undefined\n\n return {\n name: 'anthropic',\n meta: {\n defaultModel,\n isOAuth,\n capabilities: {\n vision: true,\n imageInToolResult: true,\n },\n },\n\n formatTools(tools: ToolSpec[]): Anthropic.Tool[] {\n return tools.map(t => ({\n name: t.name,\n description: t.description,\n input_schema: t.inputSchema as Anthropic.Tool['input_schema'],\n }))\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 })),\n }\n },\n\n promptMessage: anthropicPromptMessage,\n\n classifyError: classifyAnthropicError,\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 const client = createClient(\n SDK,\n apiKey,\n apiKey.includes('sk-ant-oat'),\n anthropicParams?.baseURL,\n anthropicParams?.extraBetas,\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 const system = isOAuth\n ? `You are Claude Code, Anthropic's official CLI for Claude.`\n : options.system\n const messages: SessionMessage[] = isOAuth && options.system\n ? [\n { role: 'user', content: [{ type: 'text' as const, text: options.system }] },\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 const params: Anthropic.MessageCreateParamsStreaming = {\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.Tool[],\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 // SDK v0.90 does not type `context_management`; cast through the param\n // bag so we don't pin a specific schema version. Skipped when the caller\n // didn't pass a config — leaving the field off the wire keeps requests\n // valid on accounts that don't have the beta enabled.\n if (anthropicParams?.contextManagement) {\n ;(params as unknown as Record<string, unknown>).context_management = anthropicParams.contextManagement\n }\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 // 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)\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 const plan = planAnthropicThinking(thinking, options.thinkingBudget)\n if (plan) {\n if (plan.kind === 'enabled') {\n params.thinking = { type: 'enabled', budget_tokens: plan.budgetTokens }\n params.max_tokens = plan.maxTokensBump + params.max_tokens\n }\n else {\n params.thinking = { type: 'adaptive' }\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 // 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 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'),\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","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 '@mariozechner/pi-ai'\nimport type { Provider, StreamCallbacks, StreamOptions, ToolSpec, TurnResult } from '.'\nimport type { ClassifiedError } from '../errors'\nimport type { SessionContentBlock, SessionMessage, TurnFinishReason } from '../types'\nimport { getModel } from '@mariozechner/pi-ai'\nimport { streamOpenAICodexResponses } from '@mariozechner/pi-ai/openai-codex-responses'\nimport { matchesContextExceeded } from '../errors'\nimport { fillEstimatedCost } from './cost'\nimport { resolveOAuthApiKey } from './oauth'\nimport {\n assistantMessage,\n toolResultsMessage,\n userMessage,\n} from './openai-compat'\n\nconst PROVIDER_ID = 'openai-codex'\nconst DEFAULT_MODEL = 'gpt-5.4'\n\ntype CodexModel = PiModel<'openai-codex-responses'>\n\nexport interface OpenAIParams {\n /** OpenAI Codex OAuth access token. Falls back to OPENAI_CODEX_API_KEY and .credentials.json. */\n apiKey?: string\n /** Alias for apiKey, matching the OAuth credential field. */\n access?: string\n refresh?: string\n expires?: number\n accountId?: string\n defaultModel?: string\n transport?: 'sse' | 'websocket' | 'auto'\n}\n\nfunction resolveModel(modelId: string): CodexModel {\n const model = getModel(PROVIDER_ID, modelId as never) as CodexModel | undefined\n if (model)\n return model\n\n const fallback = getModel(PROVIDER_ID, DEFAULT_MODEL as never) as CodexModel | undefined\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 return tools.map(t => ({\n name: t.name,\n description: t.description,\n parameters: t.inputSchema as PiTool['parameters'],\n }))\n}\n\nfunction toPiMessages(messages: SessionMessage[], modelId: string): PiMessage[] {\n const out: PiMessage[] = []\n\n for (const msg of messages) {\n const toolResults = msg.content.filter((b): b is Extract<SessionContentBlock, { type: 'tool_result' }> => b.type === 'tool_result')\n if (toolResults.length > 0) {\n for (const result of toolResults) {\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 out.push({\n role: 'toolResult',\n toolCallId: result.callId,\n toolName: '',\n content,\n isError: result.isError ?? false,\n timestamp: Date.now(),\n })\n }\n continue\n }\n\n const textBlocks = msg.content.filter((b): b is Extract<SessionContentBlock, { type: 'text' }> => b.type === 'text')\n const imageBlocks = msg.content.filter((b): b is Extract<SessionContentBlock, { type: 'image' }> => b.type === 'image')\n\n if (msg.role === 'user') {\n if (imageBlocks.length === 0 && textBlocks.length === 1) {\n out.push({ role: 'user', content: textBlocks[0].text, timestamp: Date.now() })\n continue\n }\n\n out.push({\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 continue\n }\n\n const content: PiAssistantMessage['content'] = []\n for (const block of msg.content) {\n if (block.type === 'text') {\n content.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 content.push({ type: 'thinking', thinking: block.text, thinkingSignature: block.signature })\n }\n else if (block.type === 'tool_call') {\n content.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 out.push({\n role: 'assistant',\n content,\n api: 'openai-codex-responses',\n provider: PROVIDER_ID,\n model: modelId,\n usage: emptyUsage(),\n stopReason: 'stop',\n timestamp: Date.now(),\n })\n }\n\n 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 is Extract<PiAssistantMessage['content'][number], { type: 'toolCall' }> => 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 * 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 */\nexport function classifyOpenAIError(err: unknown): ClassifiedError | null {\n if (!err || typeof err !== 'object')\n return null\n\n const anyErr = err as { name?: string, message?: string, code?: string, type?: string }\n\n if (anyErr.name === 'AbortError')\n return { kind: 'aborted' }\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 // pi-ai wraps API errors in generic `Error` — treat as provider_error when we have a message.\n if (message.length > 0) {\n return {\n kind: 'provider_error',\n providerCode: code,\n message,\n }\n }\n\n return null\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 let runtimeCredentials = (\n typeof params?.access === 'string'\n && typeof params.refresh === 'string'\n && typeof params.expires === 'number'\n )\n ? {\n access: params.access,\n refresh: params.refresh,\n expires: params.expires,\n ...(params.accountId ? { accountId: params.accountId } : {}),\n }\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 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 const context: PiContext = {\n systemPrompt: 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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"}
@@ -1,2 +1,2 @@
1
- import { $ as openrouter, G as ProviderCapabilities, J as ToolCall, K as StreamCallbacks, Q as OpenRouterParams, W as Provider, X as ToolSpec, Y as ToolResult, Z as TurnResult, at as openaiCompat, ct as CerebrasParams, dt as anthropic, et as OpenAICompatAuthHeader, it as mapOAIFinishReason, lt as cerebras, nt as OpenAICompatParams, ot as OpenAIParams, q as StreamOptions, rt as classifyOpenAICompatError, st as openai, tt as OpenAICompatHttpError, ut as AnthropicParams } from "./agent-D0pXl4CO.js";
1
+ import { $ as openrouter, G as ProviderCapabilities, J as ToolCall, K as StreamCallbacks, Q as OpenRouterParams, W as Provider, X as ToolSpec, Y as ToolResult, Z as TurnResult, at as openaiCompat, ct as CerebrasParams, dt as anthropic, et as OpenAICompatAuthHeader, it as mapOAIFinishReason, lt as cerebras, nt as OpenAICompatParams, ot as OpenAIParams, q as StreamOptions, rt as classifyOpenAICompatError, st as openai, tt as OpenAICompatHttpError, ut as AnthropicParams } from "./agent-skiQGYs2.js";
2
2
  export { AnthropicParams, CerebrasParams, OpenAICompatAuthHeader, OpenAICompatHttpError, OpenAICompatParams, OpenAIParams, OpenRouterParams, Provider, ProviderCapabilities, StreamCallbacks, StreamOptions, ToolCall, ToolResult, ToolSpec, TurnResult, anthropic, cerebras, classifyOpenAICompatError, mapOAIFinishReason, openai, openaiCompat, openrouter };
package/dist/providers.js CHANGED
@@ -1,3 +1,3 @@
1
- import { d as openaiCompat, l as classifyOpenAICompatError, s as OpenAICompatHttpError, u as mapOAIFinishReason } from "./messages-DiAiNhxA.js";
2
- import { i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-6bqfXUd1.js";
1
+ import { d as openaiCompat, l as classifyOpenAICompatError, s as OpenAICompatHttpError, u as mapOAIFinishReason } from "./messages-CIkO_aCH.js";
2
+ import { i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-CvriFHFU.js";
3
3
  export { OpenAICompatHttpError, anthropic, cerebras, classifyOpenAICompatError, mapOAIFinishReason, openai, openaiCompat, openrouter };