@letrquan/book 0.2.0
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/CHANGELOG.md +2504 -0
- package/LICENSE +123 -0
- package/README.md +1383 -0
- package/dist/app-MOXXWEOY.js +18945 -0
- package/dist/app-MOXXWEOY.js.map +1 -0
- package/dist/chunk-24AXE6SP.js +12 -0
- package/dist/chunk-24AXE6SP.js.map +1 -0
- package/dist/chunk-3U5IBM24.js +213 -0
- package/dist/chunk-3U5IBM24.js.map +1 -0
- package/dist/chunk-574C6MQR.js +743 -0
- package/dist/chunk-574C6MQR.js.map +1 -0
- package/dist/chunk-5GDZ22YP.js +449 -0
- package/dist/chunk-5GDZ22YP.js.map +1 -0
- package/dist/chunk-5KLVH3PY.js +167 -0
- package/dist/chunk-5KLVH3PY.js.map +1 -0
- package/dist/chunk-5RDRAO4B.js +92 -0
- package/dist/chunk-5RDRAO4B.js.map +1 -0
- package/dist/chunk-7N4J557C.js +10 -0
- package/dist/chunk-7N4J557C.js.map +1 -0
- package/dist/chunk-A7JLBK2Y.js +3506 -0
- package/dist/chunk-A7JLBK2Y.js.map +1 -0
- package/dist/chunk-ANSJPYGI.js +84 -0
- package/dist/chunk-ANSJPYGI.js.map +1 -0
- package/dist/chunk-BTZZUCLI.js +264 -0
- package/dist/chunk-BTZZUCLI.js.map +1 -0
- package/dist/chunk-C7D4NJ2D.js +217 -0
- package/dist/chunk-C7D4NJ2D.js.map +1 -0
- package/dist/chunk-CAGOB2N4.js +208 -0
- package/dist/chunk-CAGOB2N4.js.map +1 -0
- package/dist/chunk-DGMQEI6Y.js +98 -0
- package/dist/chunk-DGMQEI6Y.js.map +1 -0
- package/dist/chunk-E75IPST5.js +289 -0
- package/dist/chunk-E75IPST5.js.map +1 -0
- package/dist/chunk-EYGD6X2T.js +180 -0
- package/dist/chunk-EYGD6X2T.js.map +1 -0
- package/dist/chunk-GTVB4HEM.js +765 -0
- package/dist/chunk-GTVB4HEM.js.map +1 -0
- package/dist/chunk-J7MIZ5CA.js +1907 -0
- package/dist/chunk-J7MIZ5CA.js.map +1 -0
- package/dist/chunk-KWHQ2XXL.js +626 -0
- package/dist/chunk-KWHQ2XXL.js.map +1 -0
- package/dist/chunk-L6LK2QIQ.js +657 -0
- package/dist/chunk-L6LK2QIQ.js.map +1 -0
- package/dist/chunk-MAQXCUR4.js +1007 -0
- package/dist/chunk-MAQXCUR4.js.map +1 -0
- package/dist/chunk-S4XL7HOM.js +402 -0
- package/dist/chunk-S4XL7HOM.js.map +1 -0
- package/dist/chunk-URLQAXTR.js +60 -0
- package/dist/chunk-URLQAXTR.js.map +1 -0
- package/dist/chunk-V4BOYR52.js +3504 -0
- package/dist/chunk-V4BOYR52.js.map +1 -0
- package/dist/chunk-VZQXX3WW.js +210 -0
- package/dist/chunk-VZQXX3WW.js.map +1 -0
- package/dist/chunk-WKBO5R4O.js +34 -0
- package/dist/chunk-WKBO5R4O.js.map +1 -0
- package/dist/chunk-XIFFTATU.js +15753 -0
- package/dist/chunk-XIFFTATU.js.map +1 -0
- package/dist/command-approvals-6Y57VCWZ.js +28 -0
- package/dist/command-approvals-6Y57VCWZ.js.map +1 -0
- package/dist/context-ZC5IFEAX.js +25 -0
- package/dist/context-ZC5IFEAX.js.map +1 -0
- package/dist/hook-approvals-CTUFKEJT.js +22 -0
- package/dist/hook-approvals-CTUFKEJT.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2582 -0
- package/dist/index.js.map +1 -0
- package/dist/interactive-assets-CCAAWVKH.js +31 -0
- package/dist/interactive-assets-CCAAWVKH.js.map +1 -0
- package/dist/job-runner.d.ts +2 -0
- package/dist/job-runner.js +235 -0
- package/dist/job-runner.js.map +1 -0
- package/dist/loader-4IDS2RIE.js +15 -0
- package/dist/loader-4IDS2RIE.js.map +1 -0
- package/dist/mcp-approvals-WNPH65BK.js +18 -0
- package/dist/mcp-approvals-WNPH65BK.js.map +1 -0
- package/dist/mcp-config-YIJIES2C.js +16 -0
- package/dist/mcp-config-YIJIES2C.js.map +1 -0
- package/dist/model-window-store-YFVNXCIP.js +27 -0
- package/dist/model-window-store-YFVNXCIP.js.map +1 -0
- package/dist/openai-compatible-RHZUBHV6.js +10 -0
- package/dist/openai-compatible-RHZUBHV6.js.map +1 -0
- package/dist/permission-approvals-76PVREFD.js +14 -0
- package/dist/permission-approvals-76PVREFD.js.map +1 -0
- package/dist/permissions-CHCKTFQQ.js +28 -0
- package/dist/permissions-CHCKTFQQ.js.map +1 -0
- package/dist/sandbox-CNVAQDA7.js +23 -0
- package/dist/sandbox-CNVAQDA7.js.map +1 -0
- package/dist/scrollback-LUKLIBVI.js +136 -0
- package/dist/scrollback-LUKLIBVI.js.map +1 -0
- package/dist/sdk.d.ts +4574 -0
- package/dist/sdk.js +665 -0
- package/dist/sdk.js.map +1 -0
- package/dist/settings-loader-M2QP5TX2.js +21 -0
- package/dist/settings-loader-M2QP5TX2.js.map +1 -0
- package/dist/settings-removed-JWWPT4WA.js +19 -0
- package/dist/settings-removed-JWWPT4WA.js.map +1 -0
- package/dist/shell-selection-V6QAYXPX.js +17 -0
- package/dist/shell-selection-V6QAYXPX.js.map +1 -0
- package/package.json +143 -0
- package/patches/ink+6.8.0.patch +13 -0
- package/scripts/apply-ink-patch.mjs +29 -0
- package/scripts/ink-patch.mjs +59 -0
- package/scripts/verify-ink-patch.mjs +11 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/debug-log.ts","../src/provider/reliability.ts","../src/provider/openai-compatible.ts"],"sourcesContent":["/**\r\n * Lightweight debug logger controlled by environment variables.\r\n *\r\n * Writes timestamped messages to a log file when stderr is an interactive TTY,\r\n * because Ink renders to the same terminal and raw stderr writes corrupt the UI.\r\n * In non-TTY contexts (redirected stderr, CI), logs continue to use stderr.\r\n * Most functions are no-ops when the relevant env var is not set to '1'.\r\n *\r\n * Gated by separate flags so output volume stays controllable:\r\n * BOOK_DEBUG=1 — provider + agent + TUI lifecycle events\r\n * BOOK_DEBUG_UI=1 — input handling, modal toggles, permission prompts,\r\n * component mount/unmount, layout state changes\r\n * BOOK_DEBUG_RENDER=1 — per-render details (noisy; can flood during streaming)\r\n * BOOK_DEBUG_FLOW=1 — enter/exit timing around expensive flows\r\n * BOOK_DEBUG_FILE=path — write logs to a specific file\r\n * BOOK_DEBUG_STDERR=1 — force stderr even when attached to a TTY\r\n *\r\n * `BOOK_DEBUG=1` covers the union of \"core + UI\" (lifecycle). UI hooks read\r\n * `isUiDebugEnabled()`, which returns true if either BOOK_DEBUG=1 or\r\n * BOOK_DEBUG_UI=1 so the default mode surfaces UI events too.\r\n *\r\n * Usage:\r\n * import { createDebugLogger } from '../debug-log.js';\r\n * const log = createDebugLogger('provider');\r\n * log.debug('Sending request', { model: 'gpt-4' });\r\n */\r\n\r\nimport {\r\n appendFileSync,\r\n existsSync,\r\n mkdirSync,\r\n readdirSync,\r\n renameSync,\r\n statSync,\r\n unlinkSync,\r\n} from 'fs';\r\nimport { dirname, join } from 'path';\r\n\r\n// Core flag — provider, agent loop, and TUI lifecycle.\r\nconst DEBUG_ENABLED = process.env.BOOK_DEBUG === '1';\r\n// UI flag — input, modals, permissions, mount/unmount, layout changes.\r\n// Falls back to core flag so default debug mode surfaces UI events too.\r\nconst UI_DEBUG_ENABLED = process.env.BOOK_DEBUG_UI === '1' || DEBUG_ENABLED;\r\n// Noisy per-render flag — opt-in only.\r\nconst RENDER_DEBUG_ENABLED = process.env.BOOK_DEBUG_RENDER === '1';\r\n// Flow/tracing flag — enter/exit pairs with timing — opt-in only.\r\nconst FLOW_DEBUG_ENABLED = process.env.BOOK_DEBUG_FLOW === '1';\r\n\r\nlet debugLogPath: string | undefined;\r\nconst debugLogSizes = new Map<string, number>();\r\nconst DEFAULT_DEBUG_LOG_MAX_BYTES = 5 * 1024 * 1024;\r\nconst MIN_DEBUG_LOG_MAX_BYTES = 4;\r\nconst DEFAULT_DEBUG_LOG_BACKUPS = 3;\r\nexport const DEFAULT_LOCAL_DATA_RETENTION_DAYS = 30;\r\n\r\nexport function positiveInteger(value: string | undefined, fallback: number): number {\r\n const parsed = Number(value);\r\n return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback;\r\n}\r\n\r\nfunction debugLogMaxBytes(): number {\r\n // Four bytes is the largest UTF-8 encoding for a single Unicode code point.\r\n return Math.max(\r\n MIN_DEBUG_LOG_MAX_BYTES,\r\n positiveInteger(process.env.BOOK_DEBUG_MAX_BYTES, DEFAULT_DEBUG_LOG_MAX_BYTES),\r\n );\r\n}\r\n\r\nfunction rotateDebugLog(target: string, incomingBytes: number): void {\r\n if (!existsSync(target)) {\r\n debugLogSizes.set(target, 0);\r\n return;\r\n }\r\n const maxBytes = debugLogMaxBytes();\r\n const currentBytes = debugLogSizes.get(target) ?? statSync(target).size;\r\n debugLogSizes.set(target, currentBytes);\r\n if (currentBytes + incomingBytes <= maxBytes) return;\r\n\r\n const backups = positiveInteger(process.env.BOOK_DEBUG_BACKUPS, DEFAULT_DEBUG_LOG_BACKUPS);\r\n const oldest = `${target}.${backups}`;\r\n if (existsSync(oldest)) unlinkSync(oldest);\r\n for (let index = backups - 1; index >= 1; index--) {\r\n const source = `${target}.${index}`;\r\n if (existsSync(source)) renameSync(source, `${target}.${index + 1}`);\r\n }\r\n renameSync(target, `${target}.1`);\r\n debugLogSizes.set(target, 0);\r\n}\r\n\r\nfunction defaultDebugLogPath(): string {\r\n return join(process.env.BOOK_WORKSPACE || process.cwd(), '.book', 'debug.log');\r\n}\r\n\r\nexport function getDebugLogPath(): string | undefined {\r\n if (process.env.BOOK_DEBUG_STDERR === '1') return undefined;\r\n if (process.env.BOOK_DEBUG_FILE) return process.env.BOOK_DEBUG_FILE;\r\n if (process.stderr.isTTY) return defaultDebugLogPath();\r\n return undefined;\r\n}\r\n\r\n/** Remove expired rotated logs while always preserving the active log file. */\r\nexport function cleanupDebugLogs(\r\n days = DEFAULT_LOCAL_DATA_RETENTION_DAYS,\r\n target = getDebugLogPath(),\r\n now = Date.now(),\r\n): number {\r\n if (!target) return 0;\r\n const cutoff = now - Math.max(1, days) * 86_400_000;\r\n const directory = dirname(target);\r\n const prefix = `${target.split(/[\\\\/]/).pop()}.`;\r\n let removed = 0;\r\n try {\r\n for (const entry of readdirSync(directory, { withFileTypes: true })) {\r\n if (!entry.isFile() || !entry.name.startsWith(prefix)) continue;\r\n const path = join(directory, entry.name);\r\n if (statSync(path).mtimeMs >= cutoff) continue;\r\n unlinkSync(path);\r\n debugLogSizes.delete(path);\r\n removed++;\r\n }\r\n } catch {\r\n // Retention cleanup is best effort and must never block startup.\r\n }\r\n return removed;\r\n}\r\n\r\nfunction writeDebugLine(line: string): void {\r\n const target = debugLogPath ?? (debugLogPath = getDebugLogPath());\r\n if (!target) {\r\n process.stderr.write(line);\r\n return;\r\n }\r\n\r\n try {\r\n mkdirSync(dirname(target), { recursive: true });\r\n const lineBytes = Buffer.byteLength(line);\r\n rotateDebugLog(target, lineBytes);\r\n appendFileSync(target, line, 'utf8');\r\n debugLogSizes.set(target, (debugLogSizes.get(target) ?? 0) + lineBytes);\r\n } catch {\r\n process.stderr.write(line);\r\n }\r\n}\r\n\r\nfunction writeSizeBoundedDebugLine(line: string, maxBytes: number): void {\r\n if (Buffer.byteLength(line) <= maxBytes) {\r\n writeDebugLine(line);\r\n return;\r\n }\r\n\r\n // Split oversized render events on UTF-8 character boundaries so one burst\r\n // cannot bypass the configured active-log cap.\r\n let chunk = '';\r\n let chunkBytes = 0;\r\n for (const character of line) {\r\n const characterBytes = Buffer.byteLength(character);\r\n if (chunk && chunkBytes + characterBytes > maxBytes) {\r\n writeDebugLine(chunk);\r\n chunk = '';\r\n chunkBytes = 0;\r\n }\r\n chunk += character;\r\n chunkBytes += characterBytes;\r\n }\r\n if (chunk) writeDebugLine(chunk);\r\n}\r\n\r\nlet pendingRenderDebug: string[] = [];\r\nlet renderDebugFlush: ReturnType<typeof setImmediate> | null = null;\r\n\r\nfunction writeRenderDebugLine(line: string): void {\r\n pendingRenderDebug.push(line);\r\n if (renderDebugFlush !== null) return;\r\n renderDebugFlush = setImmediate(() => {\r\n renderDebugFlush = null;\r\n const batch = pendingRenderDebug;\r\n pendingRenderDebug = [];\r\n const maxBytes = debugLogMaxBytes();\r\n let chunk = '';\r\n let chunkBytes = 0;\r\n\r\n for (const pendingLine of batch) {\r\n const lineBytes = Buffer.byteLength(pendingLine);\r\n if (chunk && chunkBytes + lineBytes > maxBytes) {\r\n writeDebugLine(chunk);\r\n chunk = '';\r\n chunkBytes = 0;\r\n }\r\n if (lineBytes > maxBytes) {\r\n writeSizeBoundedDebugLine(pendingLine, maxBytes);\r\n continue;\r\n }\r\n chunk += pendingLine;\r\n chunkBytes += lineBytes;\r\n }\r\n if (chunk) writeDebugLine(chunk);\r\n });\r\n}\r\n\r\n// Per-namespace monotonic event counter, used when a logger is created with\r\n// `createDebugLoggerWithCounter`. Useful for tracing event ordering across\r\n// concurrent sources (streaming flushes vs. user input).\r\nconst namespaceCounters = new Map<string, number>();\r\n\r\nfunction nextEventId(namespace: string): number {\r\n const n = (namespaceCounters.get(namespace) ?? 0) + 1;\r\n namespaceCounters.set(namespace, n);\r\n return n;\r\n}\r\n\r\n/** True if core debug (provider/agent/TUI lifecycle) is on. */\r\nexport function isDebugEnabled(): boolean {\r\n return DEBUG_ENABLED;\r\n}\r\n\r\n/** True if UI debug is on (BOOK_DEBUG=1 already enables this). */\r\nexport function isUiDebugEnabled(): boolean {\r\n return UI_DEBUG_ENABLED;\r\n}\r\n\r\n/** True if per-render debug is on (opt-in via BOOK_DEBUG_RENDER=1). */\r\nexport function isRenderDebugEnabled(): boolean {\r\n return RENDER_DEBUG_ENABLED;\r\n}\r\n\r\n/** True if flow tracing is on (opt-in via BOOK_DEBUG_FLOW=1). */\r\nexport function isFlowDebugEnabled(): boolean {\r\n return FLOW_DEBUG_ENABLED;\r\n}\r\n\r\nfunction timestamp(): string {\r\n const now = new Date();\r\n const h = String(now.getHours()).padStart(2, '0');\r\n const m = String(now.getMinutes()).padStart(2, '0');\r\n const s = String(now.getSeconds()).padStart(2, '0');\r\n const ms = String(now.getMilliseconds()).padStart(3, '0');\r\n return `${h}:${m}:${s}.${ms}`;\r\n}\r\n\r\n/** Truncate a string for safe preview in logs. */\r\nfunction truncate(value: string, max = 80): string {\r\n const single = value.replace(/\\s+/g, ' ').trim();\r\n if (single.length <= max) return single;\r\n return `${single.slice(0, max)}…`;\r\n}\r\n\r\nfunction formatValue(a: unknown): string {\r\n if (typeof a === 'string') return a;\r\n if (a instanceof Error) return a.message;\r\n try {\r\n return JSON.stringify(a);\r\n } catch {\r\n return String(a);\r\n }\r\n}\r\n\r\nfunction formatMessage(...args: unknown[]): string {\r\n return args.map(formatValue).join(' ');\r\n}\r\n\r\n/** Format a metadata object, truncating any long string values. */\r\nfunction formatMeta(meta: Record<string, unknown>): string {\r\n const parts: string[] = [];\r\n for (const [key, value] of Object.entries(meta)) {\r\n let repr: string;\r\n if (typeof value === 'string') {\r\n repr = truncate(value, 120);\r\n } else if (value === null) {\r\n repr = 'null';\r\n } else if (value === undefined) {\r\n repr = 'undefined';\r\n } else {\r\n try {\r\n repr = JSON.stringify(value);\r\n } catch {\r\n repr = String(value);\r\n }\r\n }\r\n parts.push(`${key}=${repr}`);\r\n }\r\n return parts.join(' ');\r\n}\r\n\r\nexport interface DebugLogger {\r\n debug: (...args: unknown[]) => void;\r\n info: (...args: unknown[]) => void;\r\n warn: (...args: unknown[]) => void;\r\n /** Structured log with key=value metadata (long strings are truncated). */\r\n event: (event: string, meta?: Record<string, unknown>) => void;\r\n}\r\n\r\nfunction noop(): void {}\r\n\r\nconst NOOP_LOGGER: DebugLogger = {\r\n debug: noop,\r\n info: noop,\r\n warn: noop,\r\n event: noop,\r\n};\r\n\r\nfunction makePrefix(namespace: string, level: string): string {\r\n return `[${timestamp()}] [${namespace}] [${level}]`;\r\n}\r\n\r\n/** Build a writing logger for an enabled namespace. */\r\nfunction buildLogger(\r\n namespace: string,\r\n write: (line: string) => void = writeDebugLine,\r\n): DebugLogger {\r\n return {\r\n debug: (...args: unknown[]) => {\r\n write(`${makePrefix(namespace, 'DEBUG')} ${formatMessage(...args)}\\n`);\r\n },\r\n info: (...args: unknown[]) => {\r\n write(`${makePrefix(namespace, 'INFO')} ${formatMessage(...args)}\\n`);\r\n },\r\n warn: (...args: unknown[]) => {\r\n write(`${makePrefix(namespace, 'WARN')} ${formatMessage(...args)}\\n`);\r\n },\r\n event: (event, meta) => {\r\n const suffix = meta && Object.keys(meta).length > 0 ? ` ${formatMeta(meta)}` : '';\r\n write(`${makePrefix(namespace, 'DEBUG')} ${event}${suffix}\\n`);\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Create a debug logger gated by `BOOK_DEBUG=1`. Returns a no-op logger when\r\n * debug is off, so callers can call freely without env checks at call sites.\r\n */\r\nexport function createDebugLogger(namespace: string): DebugLogger {\r\n if (!DEBUG_ENABLED) return NOOP_LOGGER;\r\n return buildLogger(namespace);\r\n}\r\n\r\n/**\r\n * Like {@link createDebugLogger} but emits a monotonic event id per namespace\r\n * in every message, e.g. `[tui:input] [DEBUG#42] key=Escape`. Helpful when\r\n * tracing event ordering across concurrent sources.\r\n *\r\n * Activation matches {@link createDebugLogger}: gated by `BOOK_DEBUG=1`.\r\n */\r\nexport function createDebugLoggerWithCounter(namespace: string): DebugLogger {\r\n if (!DEBUG_ENABLED) return NOOP_LOGGER;\r\n const wrap =\r\n (level: 'debug' | 'info' | 'warn') =>\r\n (...args: unknown[]) => {\r\n const id = nextEventId(namespace);\r\n writeDebugLine(\r\n `[${timestamp()}] [${namespace}] [${level.toUpperCase()}#${id}] ${formatMessage(...args)}\\n`,\r\n );\r\n };\r\n return {\r\n debug: wrap('debug'),\r\n info: wrap('info'),\r\n warn: wrap('warn'),\r\n event: (event, meta) => {\r\n const id = nextEventId(namespace);\r\n const suffix = meta && Object.keys(meta).length > 0 ? ` ${formatMeta(meta)}` : '';\r\n writeDebugLine(`[${timestamp()}] [${namespace}] [DEBUG#${id}] ${event}${suffix}\\n`);\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Create a debug logger gated by `BOOK_DEBUG_UI=1` (also active when\r\n * `BOOK_DEBUG=1`). No-op otherwise. Used for input, modal, permission, and\r\n * mount/unmount events.\r\n */\r\nexport function createUiDebugLogger(namespace: string): DebugLogger {\r\n if (!UI_DEBUG_ENABLED) return NOOP_LOGGER;\r\n return buildLogger(namespace);\r\n}\r\n\r\n/**\r\n * Create a debug logger gated by `BOOK_DEBUG_RENDER=1` only. No-op otherwise.\r\n * Used for noisy per-render logs. Render logs must be opt-in to keep stderr\r\n * readable during streaming.\r\n */\r\nexport function createRenderDebugLogger(namespace: string): DebugLogger {\r\n if (!RENDER_DEBUG_ENABLED) return NOOP_LOGGER;\r\n return buildLogger(namespace, writeRenderDebugLine);\r\n}\r\n\r\n/**\r\n * Create a debug logger gated by `BOOK_DEBUG_FLOW=1` only. No-op otherwise.\r\n * Used for enter/exit trace pairs around expensive flows.\r\n */\r\nexport function createFlowDebugLogger(namespace: string): DebugLogger {\r\n if (!FLOW_DEBUG_ENABLED) return NOOP_LOGGER;\r\n return buildLogger(namespace);\r\n}\r\n\r\n/** Throttle a callback to at most one invocation per `intervalMs`. */\r\nexport function throttle<A extends unknown[]>(\r\n fn: (...args: A) => void,\r\n intervalMs: number,\r\n): (...args: A) => void {\r\n let last = 0;\r\n return (...args: A) => {\r\n const now = Date.now();\r\n if (now - last < intervalMs) return;\r\n last = now;\r\n fn(...args);\r\n };\r\n}\r\n","import type { RetryConfig } from '../types/runtime.js';\r\n\r\ninterface RetryLogger {\r\n warn(message: string, data?: Record<string, unknown>): void;\r\n}\r\n\r\nimport { systemClock, type Clock, type MonotonicMs } from '../clock.js';\r\n\r\nexport type ProviderErrorCode =\r\n | 'network'\r\n | 'timeout'\r\n | 'context_overflow'\r\n | 'rate_limited'\r\n | 'overloaded'\r\n | 'server_error'\r\n | 'auth'\r\n | 'bad_request'\r\n | 'not_found'\r\n | 'quota'\r\n | 'unknown';\r\n\r\nexport function classifyHttpStatus(status: number): {\r\n code: ProviderErrorCode;\r\n retryable: boolean;\r\n} {\r\n if (status === 413) return { code: 'context_overflow', retryable: false };\r\n if (status === 429) return { code: 'rate_limited', retryable: true };\r\n if (status === 529) return { code: 'overloaded', retryable: true };\r\n if (status >= 500 && status < 600) return { code: 'server_error', retryable: true };\r\n if (status === 408) return { code: 'timeout', retryable: true };\r\n if (status === 401 || status === 403) return { code: 'auth', retryable: false };\r\n if (status === 402) return { code: 'quota', retryable: false };\r\n if (status === 400) return { code: 'bad_request', retryable: false };\r\n if (status === 404) return { code: 'not_found', retryable: false };\r\n return { code: 'unknown', retryable: false };\r\n}\r\n\r\nexport function classifyApiError(status: number, body: string): ProviderErrorCode {\r\n const code = classifyHttpStatus(status).code;\r\n return code === 'bad_request' && isContextOverflowError(body) ? 'context_overflow' : code;\r\n}\r\n\r\nexport function classifyProviderError(error: unknown): ProviderErrorCode {\r\n if (error instanceof DOMException && error.name === 'TimeoutError') return 'timeout';\r\n const message = (error instanceof Error ? error.message : String(error)).toLowerCase();\r\n if (message.includes('timed out') || message.includes('timeout')) return 'timeout';\r\n if (isContextOverflowError(message)) return 'context_overflow';\r\n return 'network';\r\n}\r\n\r\nexport function formatApiError(status: number, body: string): string {\r\n const code = classifyApiError(status, body);\r\n const detail = safeErrorDetail(body);\r\n const base = `API Error: ${status}`;\r\n switch (code) {\r\n case 'context_overflow':\r\n return `${base} ${detail || 'Input exceeds the model context window.'} Reduce the conversation or tool output and try again.`;\r\n case 'rate_limited':\r\n return `${base} ${detail}. This may be a temporary capacity issue. Try again in a moment.`;\r\n case 'overloaded':\r\n return `${base} Repeated 529 Overloaded errors. The API is at capacity — this is usually temporary. Try again in a moment.`;\r\n case 'server_error':\r\n return `${base} ${detail}. This is a server-side issue, usually temporary — try again in a moment.`;\r\n case 'timeout':\r\n return 'Request timed out. Check your network connection and try again.';\r\n case 'auth':\r\n return `${base} ${detail}. Check BOOK_API_KEY, or provider.<id>.apiKey in settings.`;\r\n case 'quota':\r\n return `${base} ${detail}. Check your usage/credits.`;\r\n default:\r\n return `${base} ${detail}`;\r\n }\r\n}\r\n\r\n/** Detect provider/router responses that mean the input, rather than transport, is too large. */\r\nexport function isContextOverflowError(error: unknown): boolean {\r\n const normalized = (error instanceof Error ? error.message : String(error)).toLowerCase();\r\n return (\r\n /\\b(?:api error:\\s*)?413\\b/.test(normalized) ||\r\n normalized.includes('request entity too large') ||\r\n normalized.includes('payload too large') ||\r\n normalized.includes('request too large') ||\r\n normalized.includes('context_length_exceeded') ||\r\n normalized.includes('maximum context length') ||\r\n normalized.includes('context window') ||\r\n normalized.includes('prompt too long') ||\r\n /prompt\\s+is\\s+too\\s+long/.test(normalized) ||\r\n /input\\s+(?:is\\s+)?too\\s+long/.test(normalized) ||\r\n normalized.includes('too many tokens') ||\r\n /input\\s+(?:token\\s+count\\s+)?exceeds?.*(?:context|limit|maximum)/.test(normalized) ||\r\n /input\\s+exceeds?.*(?:context\\s+window|context\\s+length|token\\s+limit)/.test(normalized) ||\r\n /maximum\\s+context|context\\s+(?:length|window|size).*(?:exceed|overflow|too\\s+(?:long|large)|maximum)/.test(\r\n normalized,\r\n ) ||\r\n /too\\s+many\\s+(?:input\\s+)?tokens|request\\s+too\\s+large.*token/.test(normalized)\r\n );\r\n}\r\n\r\nexport async function fetchWithRetry(\r\n url: string,\r\n init: RequestInit,\r\n retry: RetryConfig,\r\n signal?: AbortSignal,\r\n onRetry?: (attempt: number, max: number, delayMs: number) => void,\r\n logger?: RetryLogger,\r\n // The retry budget is a duration, so it reads the monotonic clock. On the\r\n // wall clock an NTP step or a resumed VM could hand a week-long run either\r\n // failure mode: a backwards correction makes the budget never expire and the\r\n // call retries forever, a forwards one exhausts it on the first attempt.\r\n clock: Clock = systemClock,\r\n): Promise<Response> {\r\n const startMs = clock.monotonicNowMs();\r\n const maxAttempts = retry.watchdog ? Number.MAX_SAFE_INTEGER : retry.maxAttempts;\r\n let lastError: string | null = null;\r\n\r\n for (let attempt = 0; attempt <= maxAttempts; attempt++) {\r\n if (attempt > 0 && signal?.aborted) throw abortError(signal);\r\n const fetchSignal = requestSignal(signal, retry.requestTimeoutMs);\r\n let response: Response;\r\n try {\r\n response = await fetch(url, { ...init, signal: fetchSignal });\r\n } catch (error) {\r\n if (signal?.aborted) throw error;\r\n lastError = error instanceof Error ? error.message : String(error);\r\n if (attempt >= maxAttempts || budgetExhausted(clock, startMs, retry.totalBudgetMs)) break;\r\n const delay = boundedDelay(clock, backoffMs(attempt, retry), startMs, retry.totalBudgetMs);\r\n logger?.warn('retry network error', {\r\n attempt: attempt + 1,\r\n delayMs: delay,\r\n error: lastError,\r\n });\r\n onRetry?.(attempt + 1, maxAttempts > 100 ? -1 : maxAttempts, delay);\r\n await sleep(delay, signal);\r\n continue;\r\n }\r\n\r\n const classification = classifyHttpStatus(response.status);\r\n if (!classification.retryable) return response;\r\n lastError = `API error ${response.status}`;\r\n const watchdogRetry = retry.watchdog && (response.status === 429 || response.status === 529);\r\n const effectiveMax = watchdogRetry ? Number.MAX_SAFE_INTEGER : maxAttempts;\r\n if (attempt >= effectiveMax || budgetExhausted(clock, startMs, retry.totalBudgetMs))\r\n return response;\r\n\r\n const delay = boundedDelay(\r\n clock,\r\n backoffMs(attempt, retry, response.headers.get('retry-after')),\r\n startMs,\r\n retry.totalBudgetMs,\r\n );\r\n logger?.warn('retry http status', {\r\n attempt: attempt + 1,\r\n status: response.status,\r\n delayMs: delay,\r\n });\r\n onRetry?.(attempt + 1, watchdogRetry ? -1 : maxAttempts, delay);\r\n try {\r\n await sleep(delay, signal);\r\n } catch {\r\n return response;\r\n }\r\n try {\r\n await response.body?.cancel();\r\n } catch {\r\n // A custom fetch implementation may expose an already-locked body.\r\n }\r\n }\r\n\r\n throw new Error(lastError ?? 'request failed after retries');\r\n}\r\n\r\nexport async function readStreamChunk(\r\n reader: ReadableStreamDefaultReader<Uint8Array>,\r\n signal: AbortSignal | undefined,\r\n stallTimeoutMs: number,\r\n): Promise<\r\n | { tag: 'read'; done: boolean; value: Uint8Array | undefined }\r\n | { tag: 'stall' }\r\n | { tag: 'abort' }\r\n> {\r\n if (signal?.aborted) return { tag: 'abort' };\r\n let timeout: ReturnType<typeof setTimeout> | undefined;\r\n let onAbort: (() => void) | undefined;\r\n try {\r\n return await Promise.race([\r\n reader.read().then((result) => ({\r\n tag: 'read' as const,\r\n done: result.done,\r\n value: result.value,\r\n })),\r\n ...(stallTimeoutMs > 0\r\n ? [\r\n new Promise<{ tag: 'stall' }>((resolve) => {\r\n timeout = setTimeout(() => resolve({ tag: 'stall' }), stallTimeoutMs);\r\n }),\r\n ]\r\n : []),\r\n ...(signal\r\n ? [\r\n new Promise<{ tag: 'abort' }>((resolve) => {\r\n onAbort = () => resolve({ tag: 'abort' });\r\n signal.addEventListener('abort', onAbort, { once: true });\r\n }),\r\n ]\r\n : []),\r\n ]);\r\n } finally {\r\n if (timeout) clearTimeout(timeout);\r\n if (signal && onAbort) signal.removeEventListener('abort', onAbort);\r\n }\r\n}\r\n\r\nfunction requestSignal(\r\n signal: AbortSignal | undefined,\r\n timeoutMs: number,\r\n): AbortSignal | undefined {\r\n if (timeoutMs <= 0) return signal;\r\n const timeout = AbortSignal.timeout(timeoutMs);\r\n return signal ? AbortSignal.any([signal, timeout]) : timeout;\r\n}\r\n\r\nfunction abortError(signal: AbortSignal): Error {\r\n return signal.reason instanceof Error ? signal.reason : new Error('Aborted');\r\n}\r\n\r\nfunction safeErrorDetail(body: string): string {\r\n try {\r\n const parsed = JSON.parse(body) as { error?: { message?: unknown } };\r\n if (typeof parsed.error?.message === 'string') return parsed.error.message.slice(0, 2000);\r\n } catch {\r\n // Non-JSON response bodies are still useful when kept bounded.\r\n }\r\n return body.slice(0, 200);\r\n}\r\n\r\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n if (signal?.aborted) {\r\n reject(abortError(signal));\r\n return;\r\n }\r\n const timer = setTimeout(() => {\r\n signal?.removeEventListener('abort', onAbort);\r\n resolve();\r\n }, ms);\r\n const onAbort = () => {\r\n clearTimeout(timer);\r\n reject(signal ? abortError(signal) : new Error('Aborted'));\r\n };\r\n signal?.addEventListener('abort', onAbort, { once: true });\r\n });\r\n}\r\n\r\nfunction backoffMs(attempt: number, retry: RetryConfig, retryAfter?: string | null): number {\r\n const retryAfterMs = parseRetryAfter(retryAfter);\r\n if (retryAfterMs !== undefined) return Math.min(retryAfterMs, retry.maxDelayMs);\r\n const exponential = Math.min(retry.baseDelayMs * 2 ** attempt, retry.maxDelayMs);\r\n return Math.round(exponential * (0.5 + Math.random()));\r\n}\r\n\r\nfunction parseRetryAfter(value?: string | null): number | undefined {\r\n if (!value) return undefined;\r\n const seconds = Number(value);\r\n if (Number.isFinite(seconds) && seconds > 0) return seconds * 1000;\r\n const timestamp = Date.parse(value);\r\n if (!Number.isFinite(timestamp)) return undefined;\r\n // Wall clock on purpose, and the one place in this file that should be: the\r\n // server sent an HTTP date, which is a point on the wall clock by definition.\r\n // Subtracting a monotonic reading from it would be meaningless.\r\n return Math.max(0, timestamp - Date.now());\r\n}\r\n\r\nfunction budgetExhausted(clock: Clock, startMs: MonotonicMs, budgetMs: number): boolean {\r\n return budgetMs > 0 && clock.monotonicNowMs() - startMs >= budgetMs;\r\n}\r\n\r\nfunction boundedDelay(\r\n clock: Clock,\r\n delayMs: number,\r\n startMs: MonotonicMs,\r\n budgetMs: number,\r\n): number {\r\n if (budgetMs <= 0) return delayMs;\r\n return Math.min(delayMs, Math.max(0, budgetMs - (clock.monotonicNowMs() - startMs)));\r\n}\r\n","import type { AgentConfig } from '../types/runtime.js';\r\nimport type {\r\n ProviderMessage,\r\n ProviderStreamEvent,\r\n SystemPromptZones,\r\n} from '../types/providers.js';\r\nimport type { ToolDefinition } from '../types/tools.js';\r\nimport type { Usage } from '../types/messages.js';\r\nimport { createDebugLogger } from '../debug-log.js';\r\nimport {\r\n classifyApiError,\r\n classifyProviderError,\r\n fetchWithRetry,\r\n formatApiError,\r\n readStreamChunk,\r\n} from './reliability.js';\r\n\r\nconst log = createDebugLogger('provider');\r\n\r\nfunction parseToolArguments(raw: string): Record<string, unknown> {\r\n if (!raw.trim()) return {};\r\n try {\r\n const parsed = JSON.parse(raw);\r\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};\r\n } catch {\r\n return { __raw: raw };\r\n }\r\n}\r\n\r\nfunction parseReasoningDelta(delta: Record<string, unknown>): string | undefined {\r\n for (const key of ['reasoning_content', 'reasoning', 'thinking', 'analysis']) {\r\n const value = delta[key];\r\n if (typeof value === 'string' && value) return value;\r\n }\r\n const details = delta.reasoning_details;\r\n if (!Array.isArray(details)) return undefined;\r\n const text = details\r\n .map((detail) => {\r\n if (typeof detail === 'string') return detail;\r\n if (!detail || typeof detail !== 'object') return '';\r\n const item = detail as Record<string, unknown>;\r\n for (const key of ['text', 'reasoning', 'content']) {\r\n if (typeof item[key] === 'string') return item[key] as string;\r\n }\r\n return '';\r\n })\r\n .filter(Boolean)\r\n .join('');\r\n return text || undefined;\r\n}\r\n\r\nfunction isSystemPromptZones(content: ProviderMessage['content']): content is SystemPromptZones {\r\n return (\r\n !!content &&\r\n typeof content === 'object' &&\r\n 'cachedPrefix' in content &&\r\n 'dynamicSuffix' in content\r\n );\r\n}\r\n\r\nfunction flattenMessages(messages: ProviderMessage[]): Array<{\r\n role: string;\r\n content:\r\n | string\r\n | null\r\n | Array<{ type: 'text'; text: string } | { type: 'image_url'; image_url: { url: string } }>;\r\n tool_calls?: ProviderMessage['tool_calls'];\r\n tool_call_id?: string;\r\n}> {\r\n return messages.map(({ providerMetadata: _providerMetadata, reasoningContent, ...msg }) => ({\r\n ...msg,\r\n content: isSystemPromptZones(msg.content)\r\n ? [msg.content.cachedPrefix, msg.content.dynamicSuffix].filter(Boolean).join('\\n\\n')\r\n : Array.isArray(msg.content)\r\n ? msg.content.map((part) =>\r\n part.type === 'text'\r\n ? part\r\n : {\r\n type: 'image_url' as const,\r\n image_url: { url: `data:${part.mediaType};base64,${part.data}` },\r\n },\r\n )\r\n : reasoningContent\r\n ? ['<reasoning_context>', reasoningContent, '</reasoning_context>', msg.content ?? '']\r\n .filter(Boolean)\r\n .join('\\n')\r\n : msg.content,\r\n }));\r\n}\r\n\r\nexport function convertTools(tools: ToolDefinition[]): Array<{\r\n type: 'function';\r\n function: { name: string; description: string; parameters: Record<string, unknown> };\r\n}> {\r\n return tools.map((tool) => ({\r\n type: 'function',\r\n function: {\r\n name: tool.name,\r\n description: tool.description,\r\n parameters: tool.inputSchema ?? tool.parameters,\r\n },\r\n }));\r\n}\r\n\r\nexport async function* chatCompletionStream(\r\n config: AgentConfig,\r\n messages: ProviderMessage[],\r\n tools: ToolDefinition[],\r\n options?: {\r\n signal?: AbortSignal;\r\n onRetry?: (attempt: number, max: number, delayMs: number) => void;\r\n onStreamStall?: (countdownMs: number) => void;\r\n onStreamResume?: () => void;\r\n maxOutputTokens?: number;\r\n },\r\n): AsyncGenerator<ProviderStreamEvent> {\r\n const retry = config.retry;\r\n const signal = options?.signal;\r\n const url = `${config.baseUrl}/chat/completions`;\r\n\r\n const body: Record<string, unknown> = {\r\n model: config.model,\r\n messages: flattenMessages(messages),\r\n stream: true,\r\n // Request token usage in the final SSE chunk so we can track cost.\r\n stream_options: { include_usage: true },\r\n };\r\n if (options?.maxOutputTokens || config.maxTokensExplicit || config.modelInfo?.maxOutputTokens) {\r\n body.max_tokens = options?.maxOutputTokens ?? config.maxTokens;\r\n }\r\n if (config.effortExplicit && config.effort) body.reasoning_effort = config.effort;\r\n\r\n // Whether this request expects the model to reason before answering: either we\r\n // asked it to, or the model's catalog entry declares an effort range. An entry\r\n // of `false` means the model does not reason at all; an absent entry is unknown,\r\n // and stays on the chat regime rather than guessing.\r\n const reasoningEnabled =\r\n body.reasoning_effort !== undefined || typeof config.modelInfo?.effort === 'object';\r\n\r\n if (tools.length > 0) {\r\n body.tools = convertTools(tools);\r\n }\r\n\r\n log.debug('chatCompletionStream request', {\r\n model: config.model,\r\n messageCount: messages.length,\r\n toolCount: tools.length,\r\n maxTokens: config.maxTokens,\r\n });\r\n\r\n let response: Response;\r\n try {\r\n response = await fetchWithRetry(\r\n url,\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n Authorization: `Bearer ${config.apiKey}`,\r\n },\r\n body: JSON.stringify(body),\r\n },\r\n retry,\r\n signal,\r\n options?.onRetry,\r\n log,\r\n );\r\n } catch (e) {\r\n if (signal?.aborted) return;\r\n log.warn('fetchWithRetry failed', e instanceof Error ? e.message : String(e));\r\n yield {\r\n type: 'error',\r\n error: e instanceof Error ? e.message : String(e),\r\n errorCode: classifyProviderError(e),\r\n };\r\n return;\r\n }\r\n\r\n if (signal?.aborted) {\r\n await response.body?.cancel();\r\n return;\r\n }\r\n\r\n log.debug('response received', { status: response.status, ok: response.ok });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text();\r\n yield {\r\n type: 'error',\r\n error: formatApiError(response.status, errorText),\r\n errorCode: classifyApiError(response.status, errorText),\r\n };\r\n return;\r\n }\r\n\r\n const reader = response.body?.getReader();\r\n if (!reader) {\r\n yield { type: 'error', error: 'No response body', errorCode: 'protocol_error' };\r\n return;\r\n }\r\n\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n const toolCallParts: Array<{ index: number; id: string; name: string; arguments: string }> = [];\r\n let currentUsage: Usage | null = null;\r\n let responseModel: string | undefined;\r\n let responseId: string | undefined;\r\n const finishReasons = new Set<string>();\r\n\r\n const emitToolCalls = function* (): Generator<ProviderStreamEvent> {\r\n for (const part of [...toolCallParts].sort((a, b) => a.index - b.index)) {\r\n if (!part.id && !part.name) continue;\r\n yield {\r\n type: 'tool_call',\r\n toolCall: {\r\n id: part.id || `tool-${part.index}`,\r\n name: part.name,\r\n arguments: parseToolArguments(part.arguments),\r\n },\r\n };\r\n }\r\n };\r\n\r\n const emitDone = function* (\r\n terminal: '[DONE]' | 'finish_reason',\r\n ): Generator<ProviderStreamEvent> {\r\n yield* emitToolCalls();\r\n log.info('stream done', {\r\n terminal,\r\n promptTokens: currentUsage?.promptTokens ?? 0,\r\n completionTokens: currentUsage?.completionTokens ?? 0,\r\n totalTokens: currentUsage?.totalTokens ?? 0,\r\n });\r\n yield {\r\n type: 'done',\r\n usage: currentUsage ?? undefined,\r\n ...(responseModel ? { responseModel } : {}),\r\n ...(responseId ? { responseId } : {}),\r\n ...(finishReasons.size > 0 ? { finishReasons: [...finishReasons] } : {}),\r\n };\r\n };\r\n\r\n const processSseLine = function* (line: string): Generator<ProviderStreamEvent, boolean> {\r\n const trimmed = line.trim();\r\n if (!trimmed || !trimmed.startsWith('data:')) return false;\r\n\r\n const data = trimmed.slice(5).replace(/^ /, '');\r\n if (data === '[DONE]') {\r\n yield* emitDone('[DONE]');\r\n return true;\r\n }\r\n\r\n try {\r\n const parsed = JSON.parse(data);\r\n if (typeof parsed.model === 'string') responseModel = parsed.model;\r\n if (typeof parsed.id === 'string') responseId = parsed.id;\r\n // OpenAI sends usage on the final chunk when stream_options.include_usage is set.\r\n if (parsed.usage) {\r\n currentUsage = {\r\n promptTokens: parsed.usage.prompt_tokens ?? 0,\r\n completionTokens: parsed.usage.completion_tokens ?? 0,\r\n totalTokens: parsed.usage.total_tokens ?? 0,\r\n };\r\n }\r\n const choice = parsed.choices?.[0];\r\n if (!choice) return false;\r\n const finishReason: unknown = choice.finish_reason;\r\n if (typeof finishReason === 'string' && finishReason) finishReasons.add(finishReason);\r\n\r\n const delta = choice.delta as\r\n | (Record<string, unknown> & {\r\n content?: string;\r\n tool_calls?: Array<{\r\n index?: number;\r\n id?: string;\r\n function?: { name?: string; arguments?: string };\r\n }>;\r\n })\r\n | undefined;\r\n if (!delta) return false;\r\n\r\n const reasoning = parseReasoningDelta(delta);\r\n if (reasoning) {\r\n log.debug('stream reasoning', { len: reasoning.length });\r\n yield { type: 'reasoning', reasoning };\r\n }\r\n\r\n if (delta.content) {\r\n log.debug('stream text', { len: delta.content.length });\r\n yield { type: 'text', content: delta.content };\r\n }\r\n\r\n if (delta.tool_calls) {\r\n log.debug('stream tool_call delta', { count: delta.tool_calls.length });\r\n for (const tc of delta.tool_calls) {\r\n const explicitIndex = Number.isInteger(tc.index) ? tc.index : undefined;\r\n let index = explicitIndex;\r\n\r\n if (index === undefined && tc.id) {\r\n index = toolCallParts.find((part) => part.id === tc.id)?.index;\r\n }\r\n if (index === undefined) {\r\n index = toolCallParts.length;\r\n }\r\n\r\n let part = toolCallParts.find((p) => p.index === index);\r\n if (!part) {\r\n part = { index, id: '', name: '', arguments: '' };\r\n toolCallParts.push(part);\r\n }\r\n\r\n if (tc.id) part.id = tc.id;\r\n if (tc.function?.name) part.name = tc.function.name;\r\n if (tc.function?.arguments) part.arguments += tc.function.arguments;\r\n }\r\n }\r\n } catch {\r\n // Skip unparseable lines.\r\n }\r\n\r\n return false;\r\n };\r\n\r\n // Stream stall detection: if no data arrives for streamStallTimeoutMs,\r\n // call the onStreamStall callback and yield a visible error instead of\r\n // leaving the TUI stuck in a pending read forever.\r\n //\r\n // A reasoning model goes quiet on purpose, and many OpenAI-compatible endpoints\r\n // buffer the whole thinking block before emitting anything. The chat-tuned 20s\r\n // ceiling cancels a healthy request mid-thought and reports it as a stalled\r\n // stream, which is the single most common way a high-effort run \"just stops\".\r\n const stallTimeoutMs =\r\n reasoningEnabled && retry.thinkingStallTimeoutMs\r\n ? Math.max(retry.streamStallTimeoutMs, retry.thinkingStallTimeoutMs)\r\n : retry.streamStallTimeoutMs;\r\n\r\n try {\r\n while (true) {\r\n const result = await readStreamChunk(reader, signal, stallTimeoutMs);\r\n\r\n if (result.tag === 'abort') {\r\n try {\r\n await reader.cancel();\r\n } catch {\r\n // ignore cancellation failures\r\n }\r\n return;\r\n }\r\n\r\n if (result.tag === 'stall') {\r\n log.warn('stream stalled', { timeoutMs: stallTimeoutMs });\r\n options?.onStreamStall?.(stallTimeoutMs);\r\n try {\r\n await reader.cancel();\r\n } catch {\r\n // ignore cancellation failures\r\n }\r\n yield {\r\n type: 'error',\r\n error: 'Stream stalled: no data received for ' + stallTimeoutMs + 'ms',\r\n errorCode: 'stream_stall',\r\n };\r\n return;\r\n }\r\n\r\n if (result.done) break;\r\n\r\n const value = result.value;\r\n if (!value) continue;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n const lines = buffer.split('\\n');\r\n buffer = lines.pop() || '';\r\n\r\n for (const line of lines) {\r\n if (yield* processSseLine(line)) return;\r\n }\r\n }\r\n\r\n buffer += decoder.decode();\r\n for (const line of buffer.split('\\n')) {\r\n if (yield* processSseLine(line)) return;\r\n }\r\n\r\n // Some OpenAI-compatible gateways omit [DONE] and close after a finish_reason chunk.\r\n if (finishReasons.size > 0) {\r\n yield* emitDone('finish_reason');\r\n return;\r\n }\r\n } catch (e) {\r\n if (signal?.aborted) return;\r\n // Unexpected stream error — surface it instead of silently completing,\r\n // otherwise the TUI can show an empty completed assistant message.\r\n yield {\r\n type: 'error',\r\n error: e instanceof Error ? e.message : String(e),\r\n errorCode: classifyProviderError(e),\r\n };\r\n return;\r\n } finally {\r\n try {\r\n reader.releaseLock();\r\n } catch {\r\n // ignore: the reader may already have been cancelled/released\r\n }\r\n }\r\n\r\n yield {\r\n type: 'error',\r\n error: 'Provider stream ended before its terminal event.',\r\n errorCode: 'transport_interrupted',\r\n };\r\n}\r\n"],"mappings":"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","names":["delay","timestamp","part"]}
|