zidane 4.0.2 → 4.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +196 -614
- package/dist/agent-BoV5Twdl.d.ts +2347 -0
- package/dist/agent-BoV5Twdl.d.ts.map +1 -0
- package/dist/contexts-3Arvn7yR.js +321 -0
- package/dist/contexts-3Arvn7yR.js.map +1 -0
- package/dist/contexts.d.ts +2 -25
- package/dist/contexts.js +2 -10
- package/dist/errors-D1lhd6mX.js +118 -0
- package/dist/errors-D1lhd6mX.js.map +1 -0
- package/dist/index-28otmfLX.d.ts +400 -0
- package/dist/index-28otmfLX.d.ts.map +1 -0
- package/dist/index-BfSdALzk.d.ts +113 -0
- package/dist/index-BfSdALzk.d.ts.map +1 -0
- package/dist/index-DPsd0qwm.d.ts +254 -0
- package/dist/index-DPsd0qwm.d.ts.map +1 -0
- package/dist/index.d.ts +5 -95
- package/dist/index.js +141 -271
- package/dist/index.js.map +1 -0
- package/dist/interpolate-CukJwP2G.js +887 -0
- package/dist/interpolate-CukJwP2G.js.map +1 -0
- package/dist/mcp-8wClKY-3.js +771 -0
- package/dist/mcp-8wClKY-3.js.map +1 -0
- package/dist/mcp.d.ts +2 -4
- package/dist/mcp.js +2 -13
- package/dist/messages-z5Pq20p7.js +1020 -0
- package/dist/messages-z5Pq20p7.js.map +1 -0
- package/dist/presets-Cs7_CsMk.js +39 -0
- package/dist/presets-Cs7_CsMk.js.map +1 -0
- package/dist/presets.d.ts +2 -43
- package/dist/presets.js +2 -17
- package/dist/providers-CX-R-Oy-.js +969 -0
- package/dist/providers-CX-R-Oy-.js.map +1 -0
- package/dist/providers.d.ts +2 -4
- package/dist/providers.js +3 -23
- package/dist/session/sqlite.d.ts +7 -12
- package/dist/session/sqlite.d.ts.map +1 -0
- package/dist/session/sqlite.js +67 -79
- package/dist/session/sqlite.js.map +1 -0
- package/dist/session-Cn68UASv.js +440 -0
- package/dist/session-Cn68UASv.js.map +1 -0
- package/dist/session.d.ts +2 -4
- package/dist/session.js +3 -27
- package/dist/skills.d.ts +3 -322
- package/dist/skills.js +24 -47
- package/dist/skills.js.map +1 -0
- package/dist/stats-DoKUtF5T.js +58 -0
- package/dist/stats-DoKUtF5T.js.map +1 -0
- package/dist/tools-DpeWKzP1.js +3941 -0
- package/dist/tools-DpeWKzP1.js.map +1 -0
- package/dist/tools.d.ts +3 -95
- package/dist/tools.js +2 -40
- package/dist/tui.d.ts +533 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +2004 -0
- package/dist/tui.js.map +1 -0
- package/dist/types-Bx_F8jet.js +39 -0
- package/dist/types-Bx_F8jet.js.map +1 -0
- package/dist/types.d.ts +4 -55
- package/dist/types.js +4 -28
- package/package.json +38 -4
- package/dist/agent-BAHrGtqu.d.ts +0 -2425
- package/dist/chunk-4ILGBQ23.js +0 -803
- package/dist/chunk-4LPBN547.js +0 -3540
- package/dist/chunk-64LLNY7F.js +0 -28
- package/dist/chunk-6STZTA4N.js +0 -830
- package/dist/chunk-7GQ7P6DM.js +0 -566
- package/dist/chunk-IC7FT4OD.js +0 -37
- package/dist/chunk-JCOB6IYO.js +0 -22
- package/dist/chunk-JH6IAAFA.js +0 -28
- package/dist/chunk-LNN5UTS2.js +0 -97
- package/dist/chunk-PMCQOMV4.js +0 -490
- package/dist/chunk-UD25QF3H.js +0 -304
- package/dist/chunk-W57VY6DJ.js +0 -834
- package/dist/sandbox-D7v6Wy62.d.ts +0 -28
- package/dist/skills-use-DwZrNmcw.d.ts +0 -80
- package/dist/types-Bai5rKpa.d.ts +0 -89
- package/dist/validation-Pm--dQEU.d.ts +0 -185
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers-CX-R-Oy-.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 */\nfunction credentialsFilePath(): string {\n return 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.json` 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 */\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 return parsed as Record<string, OAuthCredentials | undefined>\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 */\nexport function writeOAuthCredentials(credentials: Record<string, OAuthCredentials | undefined>) {\n const path = credentialsFilePath()\n const tmp = `${path}.${process.pid}.${Date.now()}.tmp`\n writeFileSync(tmp, JSON.stringify(credentials, 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 { 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-6'\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: {\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 },\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 { 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 {\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 }\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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"}
|
package/dist/providers.d.ts
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import './types-Bai5rKpa.js';
|
|
4
|
-
import '@modelcontextprotocol/sdk/client/index.js';
|
|
1
|
+
import { $ as OpenAICompatHttpError, G as StreamOptions, H as Provider, J as ToolSpec, K as ToolCall, Q as OpenAICompatAuthHeader, U as ProviderCapabilities, W as StreamCallbacks, X as OpenRouterParams, Y as TurnResult, Z as openrouter, at as openai, ct as AnthropicParams, et as OpenAICompatParams, it as OpenAIParams, lt as anthropic, nt as mapOAIFinishReason, ot as CerebrasParams, q as ToolResult, rt as openaiCompat, st as cerebras, tt as classifyOpenAICompatError } from "./agent-BoV5Twdl.js";
|
|
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,23 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
openai,
|
|
5
|
-
openrouter
|
|
6
|
-
} from "./chunk-W57VY6DJ.js";
|
|
7
|
-
import {
|
|
8
|
-
OpenAICompatHttpError,
|
|
9
|
-
classifyOpenAICompatError,
|
|
10
|
-
mapOAIFinishReason,
|
|
11
|
-
openaiCompat
|
|
12
|
-
} from "./chunk-4ILGBQ23.js";
|
|
13
|
-
import "./chunk-LNN5UTS2.js";
|
|
14
|
-
export {
|
|
15
|
-
OpenAICompatHttpError,
|
|
16
|
-
anthropic,
|
|
17
|
-
cerebras,
|
|
18
|
-
classifyOpenAICompatError,
|
|
19
|
-
mapOAIFinishReason,
|
|
20
|
-
openai,
|
|
21
|
-
openaiCompat,
|
|
22
|
-
openrouter
|
|
23
|
-
};
|
|
1
|
+
import { c as classifyOpenAICompatError, l as mapOAIFinishReason, o as OpenAICompatHttpError, u as openaiCompat } from "./messages-z5Pq20p7.js";
|
|
2
|
+
import { i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-CX-R-Oy-.js";
|
|
3
|
+
export { OpenAICompatHttpError, anthropic, cerebras, classifyOpenAICompatError, mapOAIFinishReason, openai, openaiCompat, openrouter };
|
package/dist/session/sqlite.d.ts
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import 'hookable';
|
|
3
|
-
import '../types-Bai5rKpa.js';
|
|
4
|
-
import '@modelcontextprotocol/sdk/client/index.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* SQLite session store using Bun's built-in bun:sqlite.
|
|
8
|
-
*/
|
|
1
|
+
import { O as SessionStore } from "../agent-BoV5Twdl.js";
|
|
9
2
|
|
|
3
|
+
//#region src/session/sqlite.d.ts
|
|
10
4
|
interface SqliteStoreOptions {
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
/** Path to the SQLite database file */
|
|
6
|
+
path: string;
|
|
13
7
|
}
|
|
14
8
|
declare function createSqliteStore(options: SqliteStoreOptions): SessionStore;
|
|
15
|
-
|
|
16
|
-
export {
|
|
9
|
+
//#endregion
|
|
10
|
+
export { SqliteStoreOptions, createSqliteStore };
|
|
11
|
+
//# sourceMappingURL=sqlite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.d.ts","names":[],"sources":["../../src/session/sqlite.ts"],"mappings":";;;UAQiB,kBAAA;;EAEf,IAAA;AAAA;AAAA,iBAGc,iBAAA,CAAkB,OAAA,EAAS,kBAAA,GAAqB,YAAA"}
|
package/dist/session/sqlite.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// src/session/sqlite.ts
|
|
2
1
|
import { Database } from "bun:sqlite";
|
|
2
|
+
//#region src/session/sqlite.ts
|
|
3
3
|
function createSqliteStore(options) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
const db = new Database(options.path);
|
|
5
|
+
db.run("PRAGMA journal_mode = WAL");
|
|
6
|
+
db.run(`
|
|
7
7
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
8
8
|
id TEXT PRIMARY KEY,
|
|
9
9
|
agent_id TEXT,
|
|
@@ -12,9 +12,9 @@ function createSqliteStore(options) {
|
|
|
12
12
|
updated_at INTEGER NOT NULL
|
|
13
13
|
)
|
|
14
14
|
`);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_sessions_agent_id ON sessions(agent_id)`);
|
|
16
|
+
const stmtLoad = db.prepare("SELECT data FROM sessions WHERE id = ?");
|
|
17
|
+
const stmtUpsert = db.prepare(`
|
|
18
18
|
INSERT INTO sessions (id, agent_id, data, created_at, updated_at)
|
|
19
19
|
VALUES (?, ?, ?, ?, ?)
|
|
20
20
|
ON CONFLICT(id) DO UPDATE SET
|
|
@@ -22,76 +22,64 @@ function createSqliteStore(options) {
|
|
|
22
22
|
data = excluded.data,
|
|
23
23
|
updated_at = excluded.updated_at
|
|
24
24
|
`);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
await store.save(data);
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
async updateStatus(sessionId, status) {
|
|
85
|
-
const data = await store.load(sessionId);
|
|
86
|
-
if (data) {
|
|
87
|
-
data.status = status;
|
|
88
|
-
data.updatedAt = Date.now();
|
|
89
|
-
await store.save(data);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
return store;
|
|
25
|
+
const stmtDelete = db.prepare("DELETE FROM sessions WHERE id = ?");
|
|
26
|
+
const stmtList = db.prepare("SELECT id FROM sessions ORDER BY updated_at DESC");
|
|
27
|
+
const stmtListLimited = db.prepare("SELECT id FROM sessions ORDER BY updated_at DESC LIMIT ?");
|
|
28
|
+
const stmtListByAgent = db.prepare("SELECT id FROM sessions WHERE agent_id = ? ORDER BY updated_at DESC");
|
|
29
|
+
const stmtListByAgentLimited = db.prepare("SELECT id FROM sessions WHERE agent_id = ? ORDER BY updated_at DESC LIMIT ?");
|
|
30
|
+
const store = {
|
|
31
|
+
async load(sessionId) {
|
|
32
|
+
const row = stmtLoad.get(sessionId);
|
|
33
|
+
if (!row) return null;
|
|
34
|
+
return JSON.parse(row.data);
|
|
35
|
+
},
|
|
36
|
+
async save(session) {
|
|
37
|
+
stmtUpsert.run(session.id, session.agentId ?? null, JSON.stringify(session), session.createdAt, session.updatedAt);
|
|
38
|
+
},
|
|
39
|
+
async delete(sessionId) {
|
|
40
|
+
stmtDelete.run(sessionId);
|
|
41
|
+
},
|
|
42
|
+
async list(filter) {
|
|
43
|
+
const limit = typeof filter?.limit === "number" && filter.limit > 0 ? filter.limit : void 0;
|
|
44
|
+
let rows;
|
|
45
|
+
if (filter?.agentId) rows = limit ? stmtListByAgentLimited.all(filter.agentId, limit) : stmtListByAgent.all(filter.agentId);
|
|
46
|
+
else rows = limit ? stmtListLimited.all(limit) : stmtList.all();
|
|
47
|
+
return rows.map((r) => r.id);
|
|
48
|
+
},
|
|
49
|
+
async appendTurns(sessionId, turns) {
|
|
50
|
+
const data = await store.load(sessionId);
|
|
51
|
+
if (data) {
|
|
52
|
+
data.turns.push(...turns);
|
|
53
|
+
data.updatedAt = Date.now();
|
|
54
|
+
await store.save(data);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
async getTurns(sessionId, from = 0, limit) {
|
|
58
|
+
const data = await store.load(sessionId);
|
|
59
|
+
if (!data) return [];
|
|
60
|
+
return data.turns.slice(from, limit !== void 0 ? from + limit : void 0);
|
|
61
|
+
},
|
|
62
|
+
async updateRun(sessionId, run) {
|
|
63
|
+
const data = await store.load(sessionId);
|
|
64
|
+
if (data) {
|
|
65
|
+
const idx = data.runs.findIndex((r) => r.id === run.id);
|
|
66
|
+
if (idx >= 0) data.runs[idx] = run;
|
|
67
|
+
data.updatedAt = Date.now();
|
|
68
|
+
await store.save(data);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
async updateStatus(sessionId, status) {
|
|
72
|
+
const data = await store.load(sessionId);
|
|
73
|
+
if (data) {
|
|
74
|
+
data.status = status;
|
|
75
|
+
data.updatedAt = Date.now();
|
|
76
|
+
await store.save(data);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
return store;
|
|
94
81
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
82
|
+
//#endregion
|
|
83
|
+
export { createSqliteStore };
|
|
84
|
+
|
|
85
|
+
//# sourceMappingURL=sqlite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.js","names":[],"sources":["../../src/session/sqlite.ts"],"sourcesContent":["/**\n * SQLite session store using Bun's built-in bun:sqlite.\n */\n\nimport type { SessionData, SessionRun, SessionStore } from '.'\nimport type { SessionTurn } from '../types'\nimport { Database } from 'bun:sqlite'\n\nexport interface SqliteStoreOptions {\n /** Path to the SQLite database file */\n path: string\n}\n\nexport function createSqliteStore(options: SqliteStoreOptions): SessionStore {\n const db = new Database(options.path)\n\n // Enable WAL mode for better concurrent read performance\n db.run('PRAGMA journal_mode = WAL')\n\n // Create table if it doesn't exist\n db.run(`\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n agent_id TEXT,\n data TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n )\n `)\n db.run(`CREATE INDEX IF NOT EXISTS idx_sessions_agent_id ON sessions(agent_id)`)\n\n const stmtLoad = db.prepare('SELECT data FROM sessions WHERE id = ?')\n const stmtUpsert = db.prepare(`\n INSERT INTO sessions (id, agent_id, data, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET\n agent_id = excluded.agent_id,\n data = excluded.data,\n updated_at = excluded.updated_at\n `)\n const stmtDelete = db.prepare('DELETE FROM sessions WHERE id = ?')\n const stmtList = db.prepare('SELECT id FROM sessions ORDER BY updated_at DESC')\n const stmtListLimited = db.prepare('SELECT id FROM sessions ORDER BY updated_at DESC LIMIT ?')\n const stmtListByAgent = db.prepare('SELECT id FROM sessions WHERE agent_id = ? ORDER BY updated_at DESC')\n const stmtListByAgentLimited = db.prepare('SELECT id FROM sessions WHERE agent_id = ? ORDER BY updated_at DESC LIMIT ?')\n\n const store: SessionStore = {\n async load(sessionId: string) {\n const row = stmtLoad.get(sessionId) as { data: string } | null\n if (!row)\n return null\n return JSON.parse(row.data) as SessionData\n },\n\n async save(session: SessionData) {\n stmtUpsert.run(\n session.id,\n session.agentId ?? null,\n JSON.stringify(session),\n session.createdAt,\n session.updatedAt,\n )\n },\n\n async delete(sessionId: string) {\n stmtDelete.run(sessionId)\n },\n\n async list(filter) {\n // Push LIMIT into the SQL so we don't materialize every row into JS\n // just to slice the first N — meaningful on stores with many sessions.\n const limit = typeof filter?.limit === 'number' && filter.limit > 0 ? filter.limit : undefined\n let rows: { id: string }[]\n\n if (filter?.agentId) {\n rows = (limit\n ? stmtListByAgentLimited.all(filter.agentId, limit)\n : stmtListByAgent.all(filter.agentId)) as { id: string }[]\n }\n else {\n rows = (limit ? stmtListLimited.all(limit) : stmtList.all()) as { id: string }[]\n }\n\n return rows.map(r => r.id)\n },\n\n async appendTurns(sessionId: string, turns: SessionTurn[]) {\n const data = await store.load(sessionId)\n if (data) {\n data.turns.push(...turns)\n data.updatedAt = Date.now()\n await store.save(data)\n }\n },\n\n async getTurns(sessionId: string, from = 0, limit?: number) {\n const data = await store.load(sessionId)\n if (!data)\n return []\n return data.turns.slice(from, limit !== undefined ? from + limit : undefined)\n },\n\n async updateRun(sessionId: string, run: SessionRun) {\n const data = await store.load(sessionId)\n if (data) {\n const idx = data.runs.findIndex(r => r.id === run.id)\n if (idx >= 0) {\n data.runs[idx] = run\n }\n data.updatedAt = Date.now()\n await store.save(data)\n }\n },\n\n async updateStatus(sessionId: string, status: SessionData['status']) {\n const data = await store.load(sessionId)\n if (data) {\n data.status = status\n data.updatedAt = Date.now()\n await store.save(data)\n }\n },\n }\n\n return store\n}\n"],"mappings":";;AAaA,SAAgB,kBAAkB,SAA2C;CAC3E,MAAM,KAAK,IAAI,SAAS,QAAQ,KAAK;CAGrC,GAAG,IAAI,4BAA4B;CAGnC,GAAG,IAAI;;;;;;;;IAQL;CACF,GAAG,IAAI,yEAAyE;CAEhF,MAAM,WAAW,GAAG,QAAQ,yCAAyC;CACrE,MAAM,aAAa,GAAG,QAAQ;;;;;;;IAO5B;CACF,MAAM,aAAa,GAAG,QAAQ,oCAAoC;CAClE,MAAM,WAAW,GAAG,QAAQ,mDAAmD;CAC/E,MAAM,kBAAkB,GAAG,QAAQ,2DAA2D;CAC9F,MAAM,kBAAkB,GAAG,QAAQ,sEAAsE;CACzG,MAAM,yBAAyB,GAAG,QAAQ,8EAA8E;CAExH,MAAM,QAAsB;EAC1B,MAAM,KAAK,WAAmB;GAC5B,MAAM,MAAM,SAAS,IAAI,UAAU;GACnC,IAAI,CAAC,KACH,OAAO;GACT,OAAO,KAAK,MAAM,IAAI,KAAK;;EAG7B,MAAM,KAAK,SAAsB;GAC/B,WAAW,IACT,QAAQ,IACR,QAAQ,WAAW,MACnB,KAAK,UAAU,QAAQ,EACvB,QAAQ,WACR,QAAQ,UACT;;EAGH,MAAM,OAAO,WAAmB;GAC9B,WAAW,IAAI,UAAU;;EAG3B,MAAM,KAAK,QAAQ;GAGjB,MAAM,QAAQ,OAAO,QAAQ,UAAU,YAAY,OAAO,QAAQ,IAAI,OAAO,QAAQ,KAAA;GACrF,IAAI;GAEJ,IAAI,QAAQ,SACV,OAAQ,QACJ,uBAAuB,IAAI,OAAO,SAAS,MAAM,GACjD,gBAAgB,IAAI,OAAO,QAAQ;QAGvC,OAAQ,QAAQ,gBAAgB,IAAI,MAAM,GAAG,SAAS,KAAK;GAG7D,OAAO,KAAK,KAAI,MAAK,EAAE,GAAG;;EAG5B,MAAM,YAAY,WAAmB,OAAsB;GACzD,MAAM,OAAO,MAAM,MAAM,KAAK,UAAU;GACxC,IAAI,MAAM;IACR,KAAK,MAAM,KAAK,GAAG,MAAM;IACzB,KAAK,YAAY,KAAK,KAAK;IAC3B,MAAM,MAAM,KAAK,KAAK;;;EAI1B,MAAM,SAAS,WAAmB,OAAO,GAAG,OAAgB;GAC1D,MAAM,OAAO,MAAM,MAAM,KAAK,UAAU;GACxC,IAAI,CAAC,MACH,OAAO,EAAE;GACX,OAAO,KAAK,MAAM,MAAM,MAAM,UAAU,KAAA,IAAY,OAAO,QAAQ,KAAA,EAAU;;EAG/E,MAAM,UAAU,WAAmB,KAAiB;GAClD,MAAM,OAAO,MAAM,MAAM,KAAK,UAAU;GACxC,IAAI,MAAM;IACR,MAAM,MAAM,KAAK,KAAK,WAAU,MAAK,EAAE,OAAO,IAAI,GAAG;IACrD,IAAI,OAAO,GACT,KAAK,KAAK,OAAO;IAEnB,KAAK,YAAY,KAAK,KAAK;IAC3B,MAAM,MAAM,KAAK,KAAK;;;EAI1B,MAAM,aAAa,WAAmB,QAA+B;GACnE,MAAM,OAAO,MAAM,MAAM,KAAK,UAAU;GACxC,IAAI,MAAM;IACR,KAAK,SAAS;IACd,KAAK,YAAY,KAAK,KAAK;IAC3B,MAAM,MAAM,KAAK,KAAK;;;EAG3B;CAED,OAAO"}
|