zidane 6.4.0 → 6.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-DzUgjzNa.js → acp-Ba4OzG71.js} +6 -6
  3. package/dist/{acp-DzUgjzNa.js.map → acp-Ba4OzG71.js.map} +1 -1
  4. package/dist/acp-cli.js +6 -6
  5. package/dist/acp.d.ts +1 -1
  6. package/dist/acp.js +1 -1
  7. package/dist/{agent-COHX5SpM.js → agent-BMJKrD84.js} +26 -12
  8. package/dist/{agent-COHX5SpM.js.map → agent-BMJKrD84.js.map} +1 -1
  9. package/dist/agent.d.ts +1 -1
  10. package/dist/agent.js +1 -1
  11. package/dist/{anthropic-Bw39RApb.js → anthropic-BJhMEi7x.js} +15 -10
  12. package/dist/anthropic-BJhMEi7x.js.map +1 -0
  13. package/dist/{auth-XS60l6Q5.js → auth-C2Hmb0tt.js} +106 -13
  14. package/dist/auth-C2Hmb0tt.js.map +1 -0
  15. package/dist/chat/pure.d.ts +3 -3
  16. package/dist/chat.d.ts +16 -7
  17. package/dist/chat.d.ts.map +1 -1
  18. package/dist/chat.js +5 -5
  19. package/dist/{context-transport-Nb9CVjLJ.js → context-transport-CwJZxs56.js} +3 -3
  20. package/dist/{context-transport-Nb9CVjLJ.js.map → context-transport-CwJZxs56.js.map} +1 -1
  21. package/dist/contexts/daytona.d.ts +1 -1
  22. package/dist/contexts/e2b.d.ts +1 -1
  23. package/dist/{errors-DJUxZg9b.js → errors-BwBxu3zD.js} +27 -2
  24. package/dist/errors-BwBxu3zD.js.map +1 -0
  25. package/dist/errors.d.ts +1 -1
  26. package/dist/errors.js +1 -1
  27. package/dist/eval.d.ts +1 -1
  28. package/dist/eval.js +1 -1
  29. package/dist/extensions.d.ts +1 -1
  30. package/dist/extensions.js +1 -1
  31. package/dist/{fetch-url-_5WKWpbQ.js → fetch-url-B7aSg6Bp.js} +2 -2
  32. package/dist/{fetch-url-_5WKWpbQ.js.map → fetch-url-B7aSg6Bp.js.map} +1 -1
  33. package/dist/headless.d.ts +1 -1
  34. package/dist/headless.js +3 -3
  35. package/dist/{index-1Dr4Yqw1.d.ts → index-Gy9wi80M.d.ts} +189 -8
  36. package/dist/index-Gy9wi80M.d.ts.map +1 -0
  37. package/dist/index.d.ts +3 -3
  38. package/dist/index.js +14 -14
  39. package/dist/{inline-autocomplete-DC2cxprN.js → inline-autocomplete-D0MPvBaS.js} +103 -17
  40. package/dist/inline-autocomplete-D0MPvBaS.js.map +1 -0
  41. package/dist/{login-CPU73khP.js → login-llWTV13a.js} +3 -3
  42. package/dist/{login-CPU73khP.js.map → login-llWTV13a.js.map} +1 -1
  43. package/dist/{mcp-BNg6hUeX.js → mcp-IaEpSauj.js} +4 -4
  44. package/dist/{mcp-BNg6hUeX.js.map → mcp-IaEpSauj.js.map} +1 -1
  45. package/dist/mcp.d.ts +1 -1
  46. package/dist/mcp.js +1 -1
  47. package/dist/{messages-DIxD2UCr.js → messages-D1EryrDs.js} +2 -2
  48. package/dist/{messages-DIxD2UCr.js.map → messages-D1EryrDs.js.map} +1 -1
  49. package/dist/{oauth-CuFPhsHY.js → oauth-bkEOybqm.js} +2 -2
  50. package/dist/{oauth-CuFPhsHY.js.map → oauth-bkEOybqm.js.map} +1 -1
  51. package/dist/{openai-compat-BTbSyQbm.js → openai-compat-0MJq4-g9.js} +192 -19
  52. package/dist/openai-compat-0MJq4-g9.js.map +1 -0
  53. package/dist/output/stream-json.d.ts +1 -1
  54. package/dist/output/terminal.d.ts +1 -1
  55. package/dist/presets.d.ts +1 -1
  56. package/dist/presets.js +1 -1
  57. package/dist/providers/anthropic.d.ts +1 -1
  58. package/dist/providers/anthropic.js +1 -1
  59. package/dist/providers/arcee.d.ts +1 -1
  60. package/dist/providers/arcee.js +1 -1
  61. package/dist/providers/baseten.d.ts +1 -1
  62. package/dist/providers/baseten.js +1 -1
  63. package/dist/providers/cerebras.d.ts +1 -1
  64. package/dist/providers/cerebras.js +1 -1
  65. package/dist/providers/local.d.ts +1 -1
  66. package/dist/providers/local.js +1 -1
  67. package/dist/providers/openai-compat.d.ts +1 -1
  68. package/dist/providers/openai-compat.js +1 -1
  69. package/dist/providers/openai.d.ts +1 -1
  70. package/dist/providers/openai.js +15 -14
  71. package/dist/providers/openai.js.map +1 -1
  72. package/dist/providers/openrouter.d.ts +1 -1
  73. package/dist/providers/openrouter.js +1 -1
  74. package/dist/providers/xai.d.ts +1 -1
  75. package/dist/providers/xai.js +1 -1
  76. package/dist/{providers-BsH1MnhC.js → providers-BSrJx0Tn.js} +4 -4
  77. package/dist/{providers-BsH1MnhC.js.map → providers-BSrJx0Tn.js.map} +1 -1
  78. package/dist/providers.d.ts +2 -2
  79. package/dist/providers.js +6 -6
  80. package/dist/{resolve-BPTA1RpX.js → resolve-CZJxds85.js} +2 -2
  81. package/dist/{resolve-BPTA1RpX.js.map → resolve-CZJxds85.js.map} +1 -1
  82. package/dist/restate.d.ts +1 -1
  83. package/dist/session/sqlite.d.ts +1 -1
  84. package/dist/session/sqlite.js +1 -1
  85. package/dist/{session-DY2LWai4.js → session-B40flcj7.js} +2 -2
  86. package/dist/{session-DY2LWai4.js.map → session-B40flcj7.js.map} +1 -1
  87. package/dist/session.d.ts +1 -1
  88. package/dist/session.js +2 -2
  89. package/dist/{skills-C7eIjWYm.js → skills-Dd6XCi4s.js} +3 -3
  90. package/dist/{skills-C7eIjWYm.js.map → skills-Dd6XCi4s.js.map} +1 -1
  91. package/dist/skills.d.ts +1 -1
  92. package/dist/skills.js +2 -2
  93. package/dist/{stdio-DfWu1rNB.js → stdio-D-02FOVT.js} +2 -2
  94. package/dist/{stdio-DfWu1rNB.js.map → stdio-D-02FOVT.js.map} +1 -1
  95. package/dist/{stdio-loader-mfN5JYns.js → stdio-loader-Byqw5KjJ.js} +2 -2
  96. package/dist/{stdio-loader-mfN5JYns.js.map → stdio-loader-Byqw5KjJ.js.map} +1 -1
  97. package/dist/{timeout-8vSIRjzl.d.ts → timeout-DEaqslLO.d.ts} +25 -2
  98. package/dist/timeout-DEaqslLO.d.ts.map +1 -0
  99. package/dist/{tool-formatters-BaHq343O.d.ts → tool-formatters-CU0memLh.d.ts} +2 -2
  100. package/dist/{tool-formatters-BaHq343O.d.ts.map → tool-formatters-CU0memLh.d.ts.map} +1 -1
  101. package/dist/tools/fetch-url.d.ts +1 -1
  102. package/dist/tools/fetch-url.js +1 -1
  103. package/dist/tools/web-search.d.ts +1 -1
  104. package/dist/tools/web-search.js +2 -2
  105. package/dist/tools.d.ts +1 -1
  106. package/dist/tools.js +1 -1
  107. package/dist/{transcript-anchors-BquAWoGN.d.ts → transcript-anchors-4IdT10xC.d.ts} +2 -2
  108. package/dist/{transcript-anchors-BquAWoGN.d.ts.map → transcript-anchors-4IdT10xC.d.ts.map} +1 -1
  109. package/dist/{transcript-anchors-CWzlwIOr.js → transcript-anchors-CJ4gJn1T.js} +7 -7
  110. package/dist/{transcript-anchors-CWzlwIOr.js.map → transcript-anchors-CJ4gJn1T.js.map} +1 -1
  111. package/dist/tui.d.ts +24 -3
  112. package/dist/tui.d.ts.map +1 -1
  113. package/dist/tui.js +51 -18
  114. package/dist/tui.js.map +1 -1
  115. package/dist/{turn-operations-OQlIx13T.d.ts → turn-operations-B08dE8kH.d.ts} +3 -3
  116. package/dist/{turn-operations-OQlIx13T.d.ts.map → turn-operations-B08dE8kH.d.ts.map} +1 -1
  117. package/dist/types-BIarq1qE.js.map +1 -1
  118. package/dist/types.d.ts +2 -2
  119. package/dist/types.js +1 -1
  120. package/dist/{xai-DnZfHvTz.js → xai-CpPbCGWO.js} +3 -3
  121. package/dist/{xai-DnZfHvTz.js.map → xai-CpPbCGWO.js.map} +1 -1
  122. package/docs/ARCHITECTURE.md +2 -0
  123. package/docs/CHAT.md +1 -1
  124. package/docs/TUI.md +1 -1
  125. package/package.json +8 -8
  126. package/dist/anthropic-Bw39RApb.js.map +0 -1
  127. package/dist/auth-XS60l6Q5.js.map +0 -1
  128. package/dist/errors-DJUxZg9b.js.map +0 -1
  129. package/dist/index-1Dr4Yqw1.d.ts.map +0 -1
  130. package/dist/inline-autocomplete-DC2cxprN.js.map +0 -1
  131. package/dist/openai-compat-BTbSyQbm.js.map +0 -1
  132. package/dist/timeout-8vSIRjzl.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"context-transport-Nb9CVjLJ.js","names":[],"sources":["../src/mcp/context-transport.ts"],"sourcesContent":["/**\n * An MCP `Transport` that speaks stdio JSON-RPC to a server running INSIDE\n * an `ExecutionContext`, rather than as a child of the host process.\n *\n * Why this exists\n * ---------------\n * An MCP server is an ordinary program. When it calls `fs.readFileSync` or\n * `fs.writeFile`, those hit whatever filesystem it was spawned on. The\n * default `StdioClientTransport` spawns on the HOST, so with a sandboxed\n * execution context (Daytona / E2B / Docker) the agent's own tools and its\n * MCP servers end up looking at two different filesystems: a path the model\n * discovered via `list_files` does not exist for the MCP server, and an MCP\n * write lands somewhere `read_file` cannot see.\n *\n * Routing the server through `ExecutionContext.execStream` puts both on the\n * same filesystem. Note what this does NOT buy: isolation. Remote-transport\n * MCP servers are unreachable by this mechanism by construction, so\n * \"everything the agent touches runs in the execution context\" can never be\n * a true invariant. This is about coherence, not containment.\n *\n * Framing\n * -------\n * Delegated to the SDK's own `ReadBuffer` / `serializeMessage`, the exact\n * pair `StdioClientTransport` uses. That matters beyond code reuse:\n * `ReadBuffer` concatenates raw bytes and only decodes at newline\n * boundaries, so a multibyte codepoint split across two chunks survives.\n * Decoding each chunk independently would corrupt it irrecoverably — which\n * is precisely why `StreamHandle` carries bytes rather than strings.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../agent'\nimport type { ExecutionContext, ExecutionHandle } from '../contexts/types'\nimport { Buffer } from 'node:buffer'\nimport { createStderrLineEmitter } from './index'\n\n/**\n * Structural subset of the MCP SDK's `Transport` that we implement. Declared\n * locally rather than imported as a type so this module keeps the optional\n * peer-dependency contract (see the note atop `./index.ts`) — the SDK is only\n * ever touched through a runtime `await import(...)`.\n */\nexport interface ContextStdioTransportLike {\n /**\n * Brand marking this transport's process as living OUTSIDE the host.\n * `stdioPidOf` keys off it to refuse handing any pid from here to\n * `killStdioChild`, which signals host pids: a sandbox pid like `77`\n * names a real, unrelated host process. Termination for this transport\n * goes through `StreamHandle.kill()`, which signals inside the context.\n */\n readonly __contextScoped: true\n start: () => Promise<void>\n send: (message: unknown) => Promise<void>\n close: () => Promise<void>\n onclose?: () => void\n onerror?: (error: Error) => void\n onmessage?: (message: unknown) => void\n}\n\nexport interface ContextStdioTransportOptions {\n /** Server name, used for `mcp:warn` attribution. */\n name: string\n context: ExecutionContext\n handle: ExecutionHandle\n /** Full command line, run through the context's shell. */\n command: string\n cwd?: string\n env?: Record<string, string>\n hooks?: Hookable<AgentHooks>\n}\n\n/**\n * Build the transport. Throws if the context can't stream — deliberately\n * loudly, because the alternative (quietly spawning on the host) would\n * reintroduce the split-filesystem bug this transport exists to fix, and\n * would do it invisibly.\n */\nexport async function createContextStdioTransport(\n options: ContextStdioTransportOptions,\n): Promise<ContextStdioTransportLike> {\n const { name, context, handle, command, cwd, env, hooks } = options\n\n if (!context.execStream) {\n throw new Error(\n `MCP server \"${name}\" is configured with \\`scope: 'context'\\`, but the `\n + `'${context.type}' execution context does not support live streams `\n + `(\\`execStream\\`). Use \\`scope: 'host'\\` for this server, or switch to a `\n + `context that advertises \\`capabilities.stream\\`.`,\n )\n }\n\n const { ReadBuffer, serializeMessage } = await import('@modelcontextprotocol/sdk/shared/stdio.js')\n\n const readBuffer = new ReadBuffer()\n let stream: Awaited<ReturnType<NonNullable<ExecutionContext['execStream']>>> | null = null\n let closed = false\n\n const transport: ContextStdioTransportLike = {\n __contextScoped: true,\n\n async start() {\n if (stream)\n throw new Error(`MCP context transport for \"${name}\" already started`)\n\n // cwd is defaulted HERE, not left to the context: process and docker\n // fall back to `handle.cwd` on their own, but the sandbox providers\n // forward `cwd` only when set, so their SDK default would win (E2B's\n // `/home/user`, Daytona's PTY login dir). A `scope: 'context'` server\n // without an explicit `cwd` — e.g. server-filesystem rooted at '.' —\n // would then serve the workspace on two contexts and the home\n // directory on the others: the exact silent path divergence this\n // transport exists to close. Redundant-but-harmless on contexts that\n // already default to `handle.cwd`.\n stream = await context.execStream!(handle, command, {\n cwd: cwd ?? handle.cwd,\n ...(env !== undefined ? { env } : {}),\n })\n\n const active = stream\n\n // stdout → framed JSON-RPC. Runs detached from `start()`; awaiting it\n // would never resolve, since the server lives as long as the session.\n void (async () => {\n try {\n for await (const chunk of active.stdout) {\n readBuffer.append(Buffer.from(chunk))\n for (;;) {\n // A malformed frame must not kill the pump: report it and keep\n // reading. Servers that interleave stray output with protocol\n // frames (a PTY-backed context that lost the `stty raw` race,\n // a server logging to stdout) would otherwise wedge the\n // connection permanently on the first bad line.\n let message: unknown\n try {\n message = readBuffer.readMessage()\n }\n catch (err) {\n transport.onerror?.(err instanceof Error ? err : new Error(String(err)))\n continue\n }\n if (message === null)\n break\n transport.onmessage?.(message)\n }\n }\n }\n catch (err) {\n if (!closed)\n transport.onerror?.(err instanceof Error ? err : new Error(String(err)))\n }\n })()\n\n // stderr → `mcp:warn`, when the context provides it separately. A\n // PTY-backed context cannot split it from the terminal stream, so it\n // redirects to a file and may surface it here out-of-band (Daytona\n // polls) or not at all — absence is expected, not an error.\n if (active.stderr) {\n const emitter = createStderrLineEmitter(name, hooks)\n // Streaming decoder for the same reason `ReadBuffer` exists on the\n // stdout side: a per-chunk decode corrupts any multibyte codepoint\n // split across a chunk boundary. Diagnostic-only here, but free to\n // get right.\n const decoder = new TextDecoder('utf-8')\n void (async () => {\n try {\n for await (const chunk of active.stderr!)\n emitter.push(decoder.decode(chunk, { stream: true }))\n }\n catch {\n // Diagnostic channel — a failure here must not surface as a\n // protocol error.\n }\n finally {\n emitter.push(decoder.decode())\n emitter.flush()\n }\n })()\n }\n\n // The child dying is the connection ending. Surface it once.\n void active.exited.then(() => {\n if (closed)\n return\n closed = true\n transport.onclose?.()\n })\n },\n\n async send(message: unknown) {\n if (!stream)\n throw new Error(`MCP context transport for \"${name}\" not started`)\n await stream.write(new TextEncoder().encode(serializeMessage(message as never)))\n },\n\n async close() {\n if (closed) {\n // Still ensure the child is gone: `closed` may have been set by the\n // exit watcher, but an explicit close after a half-dead stream\n // should not leave a process running in the sandbox.\n await stream?.kill()\n return\n }\n closed = true\n readBuffer.clear()\n await stream?.kill()\n transport.onclose?.()\n },\n }\n\n return transport\n}\n"],"mappings":";;;;;;;;;AA6EA,eAAsB,4BACpB,SACoC;CACpC,MAAM,EAAE,MAAM,SAAS,QAAQ,SAAS,KAAK,KAAK,UAAU;CAE5D,IAAI,CAAC,QAAQ,YACX,MAAM,IAAI,MACR,eAAe,KAAK,sDACd,QAAQ,KAAK,2KAGrB;CAGF,MAAM,EAAE,YAAY,qBAAqB,MAAM,OAAO,sBAA4C,CAAA,MAAA,MAAA,EAAA,CAAA;CAElG,MAAM,aAAa,IAAI,WAAW;CAClC,IAAI,SAAkF;CACtF,IAAI,SAAS;CAEb,MAAM,YAAuC;EAC3C,iBAAiB;EAEjB,MAAM,QAAQ;GACZ,IAAI,QACF,MAAM,IAAI,MAAM,8BAA8B,KAAK,kBAAkB;GAWvE,SAAS,MAAM,QAAQ,WAAY,QAAQ,SAAS;IAClD,KAAK,OAAO,OAAO;IACnB,GAAI,QAAQ,KAAA,IAAY,EAAE,IAAI,IAAI,CAAC;GACrC,CAAC;GAED,MAAM,SAAS;GAIf,CAAM,YAAY;IAChB,IAAI;KACF,WAAW,MAAM,SAAS,OAAO,QAAQ;MACvC,WAAW,OAAO,OAAO,KAAK,KAAK,CAAC;MACpC,SAAS;OAMP,IAAI;OACJ,IAAI;QACF,UAAU,WAAW,YAAY;OACnC,SACO,KAAK;QACV,UAAU,UAAU,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;QACvE;OACF;OACA,IAAI,YAAY,MACd;OACF,UAAU,YAAY,OAAO;MAC/B;KACF;IACF,SACO,KAAK;KACV,IAAI,CAAC,QACH,UAAU,UAAU,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;IAC3E;GACF,EAAA,CAAG;GAMH,IAAI,OAAO,QAAQ;IACjB,MAAM,UAAU,wBAAwB,MAAM,KAAK;IAKnD,MAAM,UAAU,IAAI,YAAY,OAAO;IACvC,CAAM,YAAY;KAChB,IAAI;MACF,WAAW,MAAM,SAAS,OAAO,QAC/B,QAAQ,KAAK,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,CAAC;KACxD,QACM,CAGN,UACQ;MACN,QAAQ,KAAK,QAAQ,OAAO,CAAC;MAC7B,QAAQ,MAAM;KAChB;IACF,EAAA,CAAG;GACL;GAGA,OAAY,OAAO,WAAW;IAC5B,IAAI,QACF;IACF,SAAS;IACT,UAAU,UAAU;GACtB,CAAC;EACH;EAEA,MAAM,KAAK,SAAkB;GAC3B,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,8BAA8B,KAAK,cAAc;GACnE,MAAM,OAAO,MAAM,IAAI,YAAY,CAAC,CAAC,OAAO,iBAAiB,OAAgB,CAAC,CAAC;EACjF;EAEA,MAAM,QAAQ;GACZ,IAAI,QAAQ;IAIV,MAAM,QAAQ,KAAK;IACnB;GACF;GACA,SAAS;GACT,WAAW,MAAM;GACjB,MAAM,QAAQ,KAAK;GACnB,UAAU,UAAU;EACtB;CACF;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"context-transport-CwJZxs56.js","names":[],"sources":["../src/mcp/context-transport.ts"],"sourcesContent":["/**\n * An MCP `Transport` that speaks stdio JSON-RPC to a server running INSIDE\n * an `ExecutionContext`, rather than as a child of the host process.\n *\n * Why this exists\n * ---------------\n * An MCP server is an ordinary program. When it calls `fs.readFileSync` or\n * `fs.writeFile`, those hit whatever filesystem it was spawned on. The\n * default `StdioClientTransport` spawns on the HOST, so with a sandboxed\n * execution context (Daytona / E2B / Docker) the agent's own tools and its\n * MCP servers end up looking at two different filesystems: a path the model\n * discovered via `list_files` does not exist for the MCP server, and an MCP\n * write lands somewhere `read_file` cannot see.\n *\n * Routing the server through `ExecutionContext.execStream` puts both on the\n * same filesystem. Note what this does NOT buy: isolation. Remote-transport\n * MCP servers are unreachable by this mechanism by construction, so\n * \"everything the agent touches runs in the execution context\" can never be\n * a true invariant. This is about coherence, not containment.\n *\n * Framing\n * -------\n * Delegated to the SDK's own `ReadBuffer` / `serializeMessage`, the exact\n * pair `StdioClientTransport` uses. That matters beyond code reuse:\n * `ReadBuffer` concatenates raw bytes and only decodes at newline\n * boundaries, so a multibyte codepoint split across two chunks survives.\n * Decoding each chunk independently would corrupt it irrecoverably — which\n * is precisely why `StreamHandle` carries bytes rather than strings.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../agent'\nimport type { ExecutionContext, ExecutionHandle } from '../contexts/types'\nimport { Buffer } from 'node:buffer'\nimport { createStderrLineEmitter } from './index'\n\n/**\n * Structural subset of the MCP SDK's `Transport` that we implement. Declared\n * locally rather than imported as a type so this module keeps the optional\n * peer-dependency contract (see the note atop `./index.ts`) — the SDK is only\n * ever touched through a runtime `await import(...)`.\n */\nexport interface ContextStdioTransportLike {\n /**\n * Brand marking this transport's process as living OUTSIDE the host.\n * `stdioPidOf` keys off it to refuse handing any pid from here to\n * `killStdioChild`, which signals host pids: a sandbox pid like `77`\n * names a real, unrelated host process. Termination for this transport\n * goes through `StreamHandle.kill()`, which signals inside the context.\n */\n readonly __contextScoped: true\n start: () => Promise<void>\n send: (message: unknown) => Promise<void>\n close: () => Promise<void>\n onclose?: () => void\n onerror?: (error: Error) => void\n onmessage?: (message: unknown) => void\n}\n\nexport interface ContextStdioTransportOptions {\n /** Server name, used for `mcp:warn` attribution. */\n name: string\n context: ExecutionContext\n handle: ExecutionHandle\n /** Full command line, run through the context's shell. */\n command: string\n cwd?: string\n env?: Record<string, string>\n hooks?: Hookable<AgentHooks>\n}\n\n/**\n * Build the transport. Throws if the context can't stream — deliberately\n * loudly, because the alternative (quietly spawning on the host) would\n * reintroduce the split-filesystem bug this transport exists to fix, and\n * would do it invisibly.\n */\nexport async function createContextStdioTransport(\n options: ContextStdioTransportOptions,\n): Promise<ContextStdioTransportLike> {\n const { name, context, handle, command, cwd, env, hooks } = options\n\n if (!context.execStream) {\n throw new Error(\n `MCP server \"${name}\" is configured with \\`scope: 'context'\\`, but the `\n + `'${context.type}' execution context does not support live streams `\n + `(\\`execStream\\`). Use \\`scope: 'host'\\` for this server, or switch to a `\n + `context that advertises \\`capabilities.stream\\`.`,\n )\n }\n\n const { ReadBuffer, serializeMessage } = await import('@modelcontextprotocol/sdk/shared/stdio.js')\n\n const readBuffer = new ReadBuffer()\n let stream: Awaited<ReturnType<NonNullable<ExecutionContext['execStream']>>> | null = null\n let closed = false\n\n const transport: ContextStdioTransportLike = {\n __contextScoped: true,\n\n async start() {\n if (stream)\n throw new Error(`MCP context transport for \"${name}\" already started`)\n\n // cwd is defaulted HERE, not left to the context: process and docker\n // fall back to `handle.cwd` on their own, but the sandbox providers\n // forward `cwd` only when set, so their SDK default would win (E2B's\n // `/home/user`, Daytona's PTY login dir). A `scope: 'context'` server\n // without an explicit `cwd` — e.g. server-filesystem rooted at '.' —\n // would then serve the workspace on two contexts and the home\n // directory on the others: the exact silent path divergence this\n // transport exists to close. Redundant-but-harmless on contexts that\n // already default to `handle.cwd`.\n stream = await context.execStream!(handle, command, {\n cwd: cwd ?? handle.cwd,\n ...(env !== undefined ? { env } : {}),\n })\n\n const active = stream\n\n // stdout → framed JSON-RPC. Runs detached from `start()`; awaiting it\n // would never resolve, since the server lives as long as the session.\n void (async () => {\n try {\n for await (const chunk of active.stdout) {\n readBuffer.append(Buffer.from(chunk))\n for (;;) {\n // A malformed frame must not kill the pump: report it and keep\n // reading. Servers that interleave stray output with protocol\n // frames (a PTY-backed context that lost the `stty raw` race,\n // a server logging to stdout) would otherwise wedge the\n // connection permanently on the first bad line.\n let message: unknown\n try {\n message = readBuffer.readMessage()\n }\n catch (err) {\n transport.onerror?.(err instanceof Error ? err : new Error(String(err)))\n continue\n }\n if (message === null)\n break\n transport.onmessage?.(message)\n }\n }\n }\n catch (err) {\n if (!closed)\n transport.onerror?.(err instanceof Error ? err : new Error(String(err)))\n }\n })()\n\n // stderr → `mcp:warn`, when the context provides it separately. A\n // PTY-backed context cannot split it from the terminal stream, so it\n // redirects to a file and may surface it here out-of-band (Daytona\n // polls) or not at all — absence is expected, not an error.\n if (active.stderr) {\n const emitter = createStderrLineEmitter(name, hooks)\n // Streaming decoder for the same reason `ReadBuffer` exists on the\n // stdout side: a per-chunk decode corrupts any multibyte codepoint\n // split across a chunk boundary. Diagnostic-only here, but free to\n // get right.\n const decoder = new TextDecoder('utf-8')\n void (async () => {\n try {\n for await (const chunk of active.stderr!)\n emitter.push(decoder.decode(chunk, { stream: true }))\n }\n catch {\n // Diagnostic channel — a failure here must not surface as a\n // protocol error.\n }\n finally {\n emitter.push(decoder.decode())\n emitter.flush()\n }\n })()\n }\n\n // The child dying is the connection ending. Surface it once.\n void active.exited.then(() => {\n if (closed)\n return\n closed = true\n transport.onclose?.()\n })\n },\n\n async send(message: unknown) {\n if (!stream)\n throw new Error(`MCP context transport for \"${name}\" not started`)\n await stream.write(new TextEncoder().encode(serializeMessage(message as never)))\n },\n\n async close() {\n if (closed) {\n // Still ensure the child is gone: `closed` may have been set by the\n // exit watcher, but an explicit close after a half-dead stream\n // should not leave a process running in the sandbox.\n await stream?.kill()\n return\n }\n closed = true\n readBuffer.clear()\n await stream?.kill()\n transport.onclose?.()\n },\n }\n\n return transport\n}\n"],"mappings":";;;;;;;;;AA6EA,eAAsB,4BACpB,SACoC;CACpC,MAAM,EAAE,MAAM,SAAS,QAAQ,SAAS,KAAK,KAAK,UAAU;CAE5D,IAAI,CAAC,QAAQ,YACX,MAAM,IAAI,MACR,eAAe,KAAK,sDACd,QAAQ,KAAK,2KAGrB;CAGF,MAAM,EAAE,YAAY,qBAAqB,MAAM,OAAO,sBAA4C,CAAA,MAAA,MAAA,EAAA,CAAA;CAElG,MAAM,aAAa,IAAI,WAAW;CAClC,IAAI,SAAkF;CACtF,IAAI,SAAS;CAEb,MAAM,YAAuC;EAC3C,iBAAiB;EAEjB,MAAM,QAAQ;GACZ,IAAI,QACF,MAAM,IAAI,MAAM,8BAA8B,KAAK,kBAAkB;GAWvE,SAAS,MAAM,QAAQ,WAAY,QAAQ,SAAS;IAClD,KAAK,OAAO,OAAO;IACnB,GAAI,QAAQ,KAAA,IAAY,EAAE,IAAI,IAAI,CAAC;GACrC,CAAC;GAED,MAAM,SAAS;GAIf,CAAM,YAAY;IAChB,IAAI;KACF,WAAW,MAAM,SAAS,OAAO,QAAQ;MACvC,WAAW,OAAO,OAAO,KAAK,KAAK,CAAC;MACpC,SAAS;OAMP,IAAI;OACJ,IAAI;QACF,UAAU,WAAW,YAAY;OACnC,SACO,KAAK;QACV,UAAU,UAAU,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;QACvE;OACF;OACA,IAAI,YAAY,MACd;OACF,UAAU,YAAY,OAAO;MAC/B;KACF;IACF,SACO,KAAK;KACV,IAAI,CAAC,QACH,UAAU,UAAU,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;IAC3E;GACF,EAAA,CAAG;GAMH,IAAI,OAAO,QAAQ;IACjB,MAAM,UAAU,wBAAwB,MAAM,KAAK;IAKnD,MAAM,UAAU,IAAI,YAAY,OAAO;IACvC,CAAM,YAAY;KAChB,IAAI;MACF,WAAW,MAAM,SAAS,OAAO,QAC/B,QAAQ,KAAK,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,CAAC;KACxD,QACM,CAGN,UACQ;MACN,QAAQ,KAAK,QAAQ,OAAO,CAAC;MAC7B,QAAQ,MAAM;KAChB;IACF,EAAA,CAAG;GACL;GAGA,OAAY,OAAO,WAAW;IAC5B,IAAI,QACF;IACF,SAAS;IACT,UAAU,UAAU;GACtB,CAAC;EACH;EAEA,MAAM,KAAK,SAAkB;GAC3B,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,8BAA8B,KAAK,cAAc;GACnE,MAAM,OAAO,MAAM,IAAI,YAAY,CAAC,CAAC,OAAO,iBAAiB,OAAgB,CAAC,CAAC;EACjF;EAEA,MAAM,QAAQ;GACZ,IAAI,QAAQ;IAIV,MAAM,QAAQ,KAAK;IACnB;GACF;GACA,SAAS;GACT,WAAW,MAAM;GACjB,MAAM,QAAQ,KAAK;GACnB,UAAU,UAAU;EACtB;CACF;CAEA,OAAO;AACT"}
@@ -1,6 +1,6 @@
1
+ import { hu as Logger } from "../index-Gy9wi80M.js";
1
2
  import { s as ExecResult } from "../types-M2DauK2D.js";
2
3
  import { t as SandboxProvider } from "../sandbox-DLY6uah7.js";
3
- import { hu as Logger } from "../index-1Dr4Yqw1.js";
4
4
  import { Buffer } from "node:buffer";
5
5
 
6
6
  //#region src/contexts/daytona.d.ts
@@ -1,5 +1,5 @@
1
+ import { hu as Logger } from "../index-Gy9wi80M.js";
1
2
  import { t as SandboxProvider } from "../sandbox-DLY6uah7.js";
2
- import { hu as Logger } from "../index-1Dr4Yqw1.js";
3
3
 
4
4
  //#region src/contexts/e2b.d.ts
5
5
  /**
@@ -84,6 +84,31 @@ var AgentBudgetExceededError = class extends Error {
84
84
  }
85
85
  };
86
86
  /**
87
+ * Thrown by the loop when consecutive `resumeOnMaxTokens` resumes keep
88
+ * producing output-cap (`finishReason: 'length'`) turns with **no visible
89
+ * text and no tool calls** — the degenerate reasoning spin: on providers
90
+ * that don't accept prior reasoning back, each resume restarts reasoning
91
+ * from scratch on a synthetic "Please continue.", burns the full output
92
+ * budget, and makes zero progress. Unlike a text-producing truncation
93
+ * (which keeps the generous internal resume bound and, on exhaustion,
94
+ * still ends the run cleanly), this loop can never assemble an answer,
95
+ * so it fails fast with a real error instead of silently "completing".
96
+ *
97
+ * The run is finalized as `'error'` and the error re-throws so a caller's
98
+ * `try`/`catch` can branch on `err instanceof AgentLengthResumeExhaustedError`
99
+ * without string-sniffing.
100
+ */
101
+ var AgentLengthResumeExhaustedError = class extends Error {
102
+ code = "length_resume_exhausted";
103
+ /** Consecutive output-cap turns that produced no visible text and no tool calls. */
104
+ consecutiveEmptyTurns;
105
+ constructor(options) {
106
+ super(`Agent run stalled: ${options.consecutiveEmptyTurns} consecutive max_tokens-truncated turns produced no visible output and no tool calls`);
107
+ this.name = "AgentLengthResumeExhaustedError";
108
+ this.consecutiveEmptyTurns = options.consecutiveEmptyTurns;
109
+ }
110
+ };
111
+ /**
87
112
  * Thrown by the pre-send pairing repair when {@link AgentBehavior.strictToolPairing}
88
113
  * is `true` and {@link ensureToolResultPairing} would otherwise patch over
89
114
  * corruption. Strict mode opts into fail-fast for training-data collectors and
@@ -272,6 +297,6 @@ function toTypedError(classification, provider, cause) {
272
297
  });
273
298
  }
274
299
  //#endregion
275
- export { AgentToolNotAllowedError as a, classifyErrorPrelude as c, isRetryableHttpStatus as d, matchesContextExceeded as f, AgentProviderError as i, errorMessage as l, toTypedError as m, AgentBudgetExceededError as n, AgentToolPairingError as o, matchesToolPairingError as p, AgentContextExceededError as r, CONTEXT_EXCEEDED_MESSAGE_PATTERNS as s, AgentAbortedError as t, isAbortLikeError as u };
300
+ export { AgentProviderError as a, CONTEXT_EXCEEDED_MESSAGE_PATTERNS as c, isAbortLikeError as d, isRetryableHttpStatus as f, toTypedError as h, AgentLengthResumeExhaustedError as i, classifyErrorPrelude as l, matchesToolPairingError as m, AgentBudgetExceededError as n, AgentToolNotAllowedError as o, matchesContextExceeded as p, AgentContextExceededError as r, AgentToolPairingError as s, AgentAbortedError as t, errorMessage as u };
276
301
 
277
- //# sourceMappingURL=errors-DJUxZg9b.js.map
302
+ //# sourceMappingURL=errors-BwBxu3zD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors-BwBxu3zD.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Typed error classes for agent runs.\n *\n * Providers classify native errors into one of these so downstream consumers\n * can react without string-sniffing messages.\n *\n * Provider authors: implement `Provider.classifyError` to map native errors\n * (SDK exceptions, HTTP responses) to a `ClassifiedError`. The loop wraps\n * unclassified errors in `AgentProviderError` automatically.\n */\n\n/** Kind of classified provider error */\nexport type ClassifiedErrorKind = 'context_exceeded' | 'provider_error' | 'aborted' | 'tool_pairing_corruption'\n\n/** Structured classification returned by `Provider.classifyError` */\nexport interface ClassifiedError {\n kind: ClassifiedErrorKind\n /** Upstream error code as surfaced by the provider (e.g. `context_length_exceeded`). Optional. */\n providerCode?: string\n /** Optional human-readable message override. Falls back to the underlying error's message. */\n message?: string\n /**\n * Hint that the error is transient and a retry with backoff is reasonable\n * (e.g. 429, 5xx, truncated stream). Omitted when the provider can't decide;\n * callers should default to \"do not retry\" when absent to avoid hammering\n * terminal failures (auth, invalid request).\n */\n retryable?: boolean\n}\n\ninterface TypedErrorOptions {\n /** Provider name, always set (e.g. `anthropic`, `openrouter`) */\n provider: string\n /** Optional upstream error code */\n providerCode?: string\n /** Original error from the provider SDK/HTTP layer */\n cause?: unknown\n /** See {@link ClassifiedError.retryable}. */\n retryable?: boolean\n}\n\n/**\n * Thrown when the model or provider signals that the context window was exceeded.\n * Downstream consumers should catch this, prune history, and retry.\n */\nexport class AgentContextExceededError extends Error {\n readonly code = 'context_exceeded' as const\n readonly provider: string\n readonly providerCode?: string\n\n constructor(message: string, options: TypedErrorOptions) {\n super(message, options.cause !== undefined ? { cause: options.cause } : undefined)\n this.name = 'AgentContextExceededError'\n this.provider = options.provider\n this.providerCode = options.providerCode\n }\n}\n\n/**\n * Thrown when the provider returns a non-context error (auth, rate limit, server error, etc.).\n * Catch-all for unclassified provider failures.\n */\nexport class AgentProviderError extends Error {\n readonly code = 'provider_error' as const\n readonly provider: string\n readonly providerCode?: string\n /**\n * Whether a retry with backoff is likely to succeed. See\n * {@link ClassifiedError.retryable}. Absent when the provider did not\n * classify the error — callers should treat absent as \"don't retry\".\n */\n readonly retryable?: boolean\n\n constructor(message: string, options: TypedErrorOptions) {\n super(message, options.cause !== undefined ? { cause: options.cause } : undefined)\n this.name = 'AgentProviderError'\n this.provider = options.provider\n this.providerCode = options.providerCode\n this.retryable = options.retryable\n }\n}\n\n/**\n * Thrown when a run is aborted by the consumer via `agent.abort()` or an external `AbortSignal`.\n */\nexport class AgentAbortedError extends Error {\n readonly code = 'aborted' as const\n\n constructor(message = 'Agent run aborted', options?: { cause?: unknown }) {\n super(message, options?.cause !== undefined ? { cause: options.cause } : undefined)\n this.name = 'AgentAbortedError'\n }\n}\n\n/**\n * Thrown by the loop when a run's cumulative cost, token consumption, or\n * wall-clock elapsed time crosses a ceiling configured on\n * {@link AgentBehavior.maxCostUsd} / {@link AgentBehavior.maxTotalTokens} /\n * {@link AgentBehavior.maxWallMs}. Acts as a programmable circuit\n * breaker for unattended runs — without this, the only built-in safety net\n * is {@link AgentBehavior.maxTurns}, which doesn't bound a single very\n * expensive turn (large context, deep reasoning).\n *\n * The breach is checked **after** each turn completes (post-`turn:after`),\n * so the run may exceed the budget by one turn's worth of usage before\n * tripping. Callers wanting a tighter pre-turn estimate should layer their\n * own check on top of the `usage` hook.\n *\n * The harness treats this the same way as {@link AgentAbortedError}: the\n * session run is finalized as `'aborted'`, persisted stats reflect what\n * was actually consumed, and the parent agent re-throws so a caller's\n * `try`/`catch` can branch on `err instanceof AgentBudgetExceededError`\n * without string-sniffing.\n */\nexport class AgentBudgetExceededError extends Error {\n readonly code = 'budget_exceeded' as const\n /** Which ceiling tripped. `'cost'` → `maxCostUsd`, `'tokens'` → `maxTotalTokens`, `'wallClock'` → `maxWallMs`. */\n readonly limit: 'cost' | 'tokens' | 'wallClock'\n /** The configured cap (USD for `cost`, total tokens for `tokens`, ms for `wallClock`). */\n readonly limitValue: number\n /** Actual consumed value at the moment the cap was crossed (same units as `limitValue`). */\n readonly actualValue: number\n\n constructor(options: {\n limit: 'cost' | 'tokens' | 'wallClock'\n limitValue: number\n actualValue: number\n cause?: unknown\n }) {\n const unit = options.limit === 'cost' ? 'USD' : options.limit === 'wallClock' ? 'ms' : 'tokens'\n super(\n `Agent run exceeded ${options.limit} budget: ${options.actualValue} ${unit} > ${options.limitValue} ${unit}`,\n options.cause !== undefined ? { cause: options.cause } : undefined,\n )\n this.name = 'AgentBudgetExceededError'\n this.limit = options.limit\n this.limitValue = options.limitValue\n this.actualValue = options.actualValue\n }\n}\n\n/**\n * Thrown by the loop when consecutive `resumeOnMaxTokens` resumes keep\n * producing output-cap (`finishReason: 'length'`) turns with **no visible\n * text and no tool calls** — the degenerate reasoning spin: on providers\n * that don't accept prior reasoning back, each resume restarts reasoning\n * from scratch on a synthetic \"Please continue.\", burns the full output\n * budget, and makes zero progress. Unlike a text-producing truncation\n * (which keeps the generous internal resume bound and, on exhaustion,\n * still ends the run cleanly), this loop can never assemble an answer,\n * so it fails fast with a real error instead of silently \"completing\".\n *\n * The run is finalized as `'error'` and the error re-throws so a caller's\n * `try`/`catch` can branch on `err instanceof AgentLengthResumeExhaustedError`\n * without string-sniffing.\n */\nexport class AgentLengthResumeExhaustedError extends Error {\n readonly code = 'length_resume_exhausted' as const\n /** Consecutive output-cap turns that produced no visible text and no tool calls. */\n readonly consecutiveEmptyTurns: number\n\n constructor(options: { consecutiveEmptyTurns: number }) {\n super(\n `Agent run stalled: ${options.consecutiveEmptyTurns} consecutive max_tokens-truncated turns produced no visible output and no tool calls`,\n )\n this.name = 'AgentLengthResumeExhaustedError'\n this.consecutiveEmptyTurns = options.consecutiveEmptyTurns\n }\n}\n\n/**\n * Thrown by the pre-send pairing repair when {@link AgentBehavior.strictToolPairing}\n * is `true` and {@link ensureToolResultPairing} would otherwise patch over\n * corruption. Strict mode opts into fail-fast for training-data collectors and\n * any consumer that prefers to bail out rather than ship a transcript carrying\n * a {@link SYNTHETIC_TOOL_RESULT_PLACEHOLDER}.\n *\n * The `repairs` field carries every repair the loop would have made — useful\n * for postmortems and for surfacing exactly which transcripts were rejected.\n *\n * Note: callers consuming the chat layer (TUI/SDK presets) typically leave\n * `strictToolPairing` off so user-facing sessions auto-heal instead of\n * crashing.\n */\nexport class AgentToolPairingError extends Error {\n readonly code = 'tool_pairing_corruption' as const\n /** Provider whose wire format the corruption would have hit. */\n readonly provider?: string\n /** Upstream error code when the corruption was detected from a 400 response. */\n readonly providerCode?: string\n /**\n * Repairs the harness would have performed had strict mode been off.\n * Preserves the full diagnostic so consumers can route to telemetry,\n * `/rewind` flows, or training-data quarantine without re-walking the\n * transcript.\n */\n readonly repairs: ReadonlyArray<{\n mode: string\n callId?: string\n messageIndex: number\n }>\n\n constructor(options: {\n message: string\n provider?: string\n providerCode?: string\n repairs: ReadonlyArray<{ mode: string, callId?: string, messageIndex: number }>\n cause?: unknown\n }) {\n super(options.message, options.cause !== undefined ? { cause: options.cause } : undefined)\n this.name = 'AgentToolPairingError'\n this.provider = options.provider\n this.providerCode = options.providerCode\n this.repairs = options.repairs\n }\n}\n\n/**\n * Thrown (well — constructed; attach via the `tool:gate` block signal) when the\n * union of `allowed-tools` across active skills does not permit a tool call.\n *\n * Produced by the allowed-tools middleware registered on `tool:gate` /\n * `mcp:tool:gate`. The gate's `block = true` + `reason` carry the same message\n * so consumers that don't look at this typed error still get a useful string.\n */\nexport class AgentToolNotAllowedError extends Error {\n readonly code = 'tool_not_allowed' as const\n /** Canonical tool name the agent tried to call. */\n readonly toolName: string\n /** Aliased / wire name the LLM saw. */\n readonly displayName: string\n /** Flattened union of `allowedTools` patterns across active skills. */\n readonly allowedUnion: readonly string[]\n /** Names of the skills currently active when the block fired. */\n readonly activeSkills: readonly string[]\n\n constructor(options: {\n toolName: string\n displayName: string\n allowedUnion: readonly string[]\n activeSkills: readonly string[]\n cause?: unknown\n }) {\n // Recovery hint points the model at the deactivate path. Without it the\n // model would invent folk theories like \"skill restrictions reset on\n // the next user message\" and silently waste turns probing other tools.\n // The hint mentions exactly one of the active skills (if any) so the\n // model has a concrete `skills_use({ mode: \"deactivate\", name: ... })`\n // call to make.\n const sample = options.activeSkills[0]\n const hint = sample !== undefined\n ? ` To use this tool, call \\`skills_use\\` with \\`mode: \"deactivate\"\\` and the active skill name (e.g. \"${sample}\") to lift its restriction — or ask the user to switch agent profile.`\n : ''\n const msg = (\n `Tool \"${options.displayName}\" is not in the allowed-tools union of the active `\n + `skill(s) [${options.activeSkills.join(', ')}]. Union: [${options.allowedUnion.join(' ')}].${hint}`\n )\n super(msg, options.cause !== undefined ? { cause: options.cause } : undefined)\n this.name = 'AgentToolNotAllowedError'\n this.toolName = options.toolName\n this.displayName = options.displayName\n this.allowedUnion = options.allowedUnion\n this.activeSkills = options.activeSkills\n }\n}\n\n/**\n * Regex patterns matching common \"context window exceeded\" messages across providers.\n *\n * Use {@link matchesContextExceeded} to test a free-form error message against them.\n * Provider authors can also compose these into their own `classifyError` fallbacks.\n */\nexport const CONTEXT_EXCEEDED_MESSAGE_PATTERNS: readonly RegExp[] = [\n /context[_\\s]length[_\\s]exceeded/i,\n /maximum context length/i,\n /prompt is too long/i,\n /context window/i,\n // Baseten Model APIs (GLM, Kimi, …): \"Input length 852084 exceeds the\n // maximum allowed input length of 202720 tokens.\" Specific enough to avoid\n // false positives on unrelated length errors.\n /maximum allowed input length/i,\n]\n\n/**\n * Regex patterns matching provider-side tool-call / tool-result adjacency\n * rejections. The local pre-send repair pass should prevent these, so a\n * provider still returning one is a typed `tool_pairing_corruption` signal.\n */\nexport const TOOL_PAIRING_ERROR_PATTERNS: readonly RegExp[] = [\n /tool_use[^a-z0-9]+ids?[^a-z0-9]+were[^a-z0-9]+found[^a-z0-9]+without[^a-z0-9]+tool_result/i,\n /tool_result[^a-z0-9]+must[^a-z0-9]+be[^a-z0-9]+preceded[^a-z0-9]+by[^a-z0-9]+a[^a-z0-9]+tool_call/i,\n /unexpected[^a-z0-9]+tool_result[^a-z0-9]+block/i,\n /tool_use[^a-z0-9]+block.*requires.*tool_result/i,\n /tool_calls?[^a-z0-9]+must[^a-z0-9]+be[^a-z0-9]+followed[^a-z0-9]+by[^a-z0-9]+tool/i,\n /tool_call_id[^a-z0-9]+(?:missing|mismatch|invalid)/i,\n /tool_call_id[^a-z0-9]+not[^a-z0-9]+found/i,\n]\n\n/**\n * Return true when `message` matches any of the known \"context window exceeded\"\n * phrasings. Safe for `''` / non-strings (returns false).\n */\nexport function matchesContextExceeded(message: unknown): boolean {\n if (typeof message !== 'string' || message.length === 0)\n return false\n return CONTEXT_EXCEEDED_MESSAGE_PATTERNS.some(re => re.test(message))\n}\n\n/**\n * Return true when `message` matches a known tool-call / tool-result pairing\n * rejection. Safe for `''` / non-strings (returns false).\n */\nexport function matchesToolPairingError(message: unknown): boolean {\n if (typeof message !== 'string' || message.length === 0)\n return false\n return TOOL_PAIRING_ERROR_PATTERNS.some(re => re.test(message))\n}\n\n/**\n * Shared entry guard for provider `classifyError` paths. Returns:\n * - `'not-object'` when `err` is null/undefined or not an object — the caller\n * should `return null` (nothing to classify).\n * - `'aborted'` when `err.name === 'AbortError'` — the caller should return\n * `{ kind: 'aborted' }`.\n * - `null` when `err` is a classifiable object that is not an abort.\n *\n * Collapses the byte-identical `if (!err || typeof err !== 'object') return null`\n * + `if (err.name === 'AbortError') return { kind: 'aborted' }` prelude every\n * provider repeated; per-provider classification past this point differs.\n */\nexport function classifyErrorPrelude(err: unknown): 'not-object' | 'aborted' | null {\n if (!err || typeof err !== 'object')\n return 'not-object'\n if ((err as { name?: unknown }).name === 'AbortError')\n return 'aborted'\n return null\n}\n\n/**\n * HTTP status retry rule shared by provider `classifyError` paths: `429` (rate\n * limit) and `5xx` except `501 Not Implemented` are safe to retry with backoff;\n * every other 4xx (bad request, auth, not found) is terminal.\n *\n * Note: `compact/compact.ts` deliberately uses a plain `>=500 && <600` test for\n * a different decision and is intentionally not routed through this.\n */\nexport function isRetryableHttpStatus(status: number): boolean {\n if (status === 429)\n return true\n if (status >= 500 && status !== 501)\n return true\n return false\n}\n\n/**\n * Extract a printable message from an unknown thrown value.\n *\n * Standardizes the `err instanceof Error ? err.message : String(err)` idiom\n * that every `catch (err)` block was reaching for.\n */\nexport function errorMessage(err: unknown): string {\n if (err instanceof Error)\n return err.message\n return String(err)\n}\n\n/**\n * Whether `err` is an abort-shaped error — a DOM/Node `AbortError` or a Node\n * `ABORT_ERR` code.\n *\n * Tools that wrap their body in a catch-all converting failures into a normal\n * tool-result string (e.g. `grep`) MUST special-case this and RE-THROW: an\n * abort is not a tool failure. The agent loop turns a propagated abort into\n * its canonical interrupt/cascade marker, whereas a swallowed one would mask\n * cancellation as a misleading `<tool> error:` string.\n */\nexport function isAbortLikeError(err: unknown): boolean {\n if (!err || typeof err !== 'object')\n return false\n const e = err as { name?: unknown, code?: unknown }\n return e.name === 'AbortError' || e.code === 'ABORT_ERR'\n}\n\n/**\n * Convert a `ClassifiedError` + underlying cause into the matching typed error instance.\n */\nexport function toTypedError(\n classification: ClassifiedError,\n provider: string,\n cause: unknown,\n): AgentContextExceededError | AgentProviderError | AgentAbortedError | AgentToolPairingError {\n const message = classification.message ?? errorMessage(cause)\n\n if (classification.kind === 'context_exceeded') {\n return new AgentContextExceededError(message, {\n provider,\n providerCode: classification.providerCode,\n cause,\n })\n }\n\n if (classification.kind === 'aborted') {\n return new AgentAbortedError(message, { cause })\n }\n\n if (classification.kind === 'tool_pairing_corruption') {\n return new AgentToolPairingError({\n message,\n provider,\n providerCode: classification.providerCode,\n // Server-side rejection: we don't have the structured repair list a\n // local-pre-send strict-mode throw would carry. Surface an empty\n // array so consumers branching on `repairs.length` see \"the harness\n // didn't get a chance to walk the transcript\".\n repairs: [],\n cause,\n })\n }\n\n return new AgentProviderError(message, {\n provider,\n providerCode: classification.providerCode,\n retryable: classification.retryable,\n cause,\n })\n}\n"],"mappings":"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"}
package/dist/errors.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as AgentProviderError, c as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, d as errorMessage, f as matchesContextExceeded, i as AgentContextExceededError, l as ClassifiedError, n as AgentAbortedError, o as AgentToolNotAllowedError, p as toTypedError, r as AgentBudgetExceededError, s as AgentToolPairingError, t as OperationTimeoutError, u as ClassifiedErrorKind } from "./timeout-8vSIRjzl.js";
1
+ import { c as AgentToolPairingError, d as ClassifiedErrorKind, f as errorMessage, i as AgentContextExceededError, l as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, m as toTypedError, n as AgentAbortedError, o as AgentProviderError, p as matchesContextExceeded, r as AgentBudgetExceededError, s as AgentToolNotAllowedError, t as OperationTimeoutError, u as ClassifiedError } from "./timeout-DEaqslLO.js";
2
2
  export { AgentAbortedError, AgentBudgetExceededError, AgentContextExceededError, AgentProviderError, AgentToolNotAllowedError, AgentToolPairingError, CONTEXT_EXCEEDED_MESSAGE_PATTERNS, type ClassifiedError, type ClassifiedErrorKind, OperationTimeoutError, errorMessage, matchesContextExceeded, toTypedError };
package/dist/errors.js CHANGED
@@ -1,3 +1,3 @@
1
- import { a as AgentToolNotAllowedError, f as matchesContextExceeded, i as AgentProviderError, l as errorMessage, m as toTypedError, n as AgentBudgetExceededError, o as AgentToolPairingError, r as AgentContextExceededError, s as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, t as AgentAbortedError } from "./errors-DJUxZg9b.js";
1
+ import { a as AgentProviderError, c as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, h as toTypedError, n as AgentBudgetExceededError, o as AgentToolNotAllowedError, p as matchesContextExceeded, r as AgentContextExceededError, s as AgentToolPairingError, t as AgentAbortedError, u as errorMessage } from "./errors-BwBxu3zD.js";
2
2
  import { t as OperationTimeoutError } from "./timeout-BDetbuN6.js";
3
3
  export { AgentAbortedError, AgentBudgetExceededError, AgentContextExceededError, AgentProviderError, AgentToolNotAllowedError, AgentToolPairingError, CONTEXT_EXCEEDED_MESSAGE_PATTERNS, OperationTimeoutError, errorMessage, matchesContextExceeded, toTypedError };
package/dist/eval.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { $t as EvalRunUsage, An as efficiencyMetricValues, Bn as functionalityMetric, Bt as EvalAgentStats, Cn as clearRegisteredEvals, Dn as createReusableExecutionContext, En as createEvalRunReporter, Fn as fileExistsOneOf, Ft as EvalAgent, Gn as runEvalCase, Gt as EvalDefinitionContext, Hn as normalizeMetric, Ht as EvalCaseOptions, In as finalizeEvalMetrics, It as EvalAgentMcpServers, Jt as EvalRunMetricAggregate, Kn as statusCompleted, Kt as EvalMetric, Ln as formatEvalCaseSummary, Lt as EvalAgentRunOptions, Mn as fileContains, Nn as fileContentQuality, Nt as CreateEvalAgentOptions, On as defineEval, Pn as fileExists, Pt as EFFICIENCY_METRICS, Qt as EvalRunSummaryCase, Rn as formatEvalRunSummary, Rt as EvalAgentRunResult, Sn as buildTrajectory, Tn as createEvalAgent, Un as registerEvalTests, Ut as EvalCaseResult, Vn as llmJudge, Vt as EvalArtifacts, Wn as relativeArtifactPath, Wt as EvalDefinition, Xt as EvalRunReporterOptions, Yt as EvalRunReporter, Zt as EvalRunSummary, _n as TrajectoryStep, an as EvalWorkspaceFile, bn as buildEvalRunSummary, cn as LlmJudgeOptions, dn as MetricSpec, en as EvalScore, fn as MetricSpecMap, gn as Trajectory, hn as ReusableExecutionContext, in as EvalVariantSummary, jn as emitEfficiencyMetrics, kn as defineMetrics, ln as MetricDirection, mn as RegisterEvalTestsOptions, nn as EvalScorerContext, on as EvalWorkspaceOptions, pn as MetricStats, qt as EvalMetricError, rn as EvalTestRunner, sn as EvalWorkspaceSnapshot, tn as EvalScorer, un as MetricEmitter, vn as TrajectoryStepKind, wn as computeEvalTagScores, xn as buildRegisteredEvals, yn as artifactPath, zn as formatTrajectoryLine, zt as EvalAgentRunStats } from "./index-1Dr4Yqw1.js";
1
+ import { $t as EvalRunUsage, An as efficiencyMetricValues, Bn as functionalityMetric, Bt as EvalAgentStats, Cn as clearRegisteredEvals, Dn as createReusableExecutionContext, En as createEvalRunReporter, Fn as fileExistsOneOf, Ft as EvalAgent, Gn as runEvalCase, Gt as EvalDefinitionContext, Hn as normalizeMetric, Ht as EvalCaseOptions, In as finalizeEvalMetrics, It as EvalAgentMcpServers, Jt as EvalRunMetricAggregate, Kn as statusCompleted, Kt as EvalMetric, Ln as formatEvalCaseSummary, Lt as EvalAgentRunOptions, Mn as fileContains, Nn as fileContentQuality, Nt as CreateEvalAgentOptions, On as defineEval, Pn as fileExists, Pt as EFFICIENCY_METRICS, Qt as EvalRunSummaryCase, Rn as formatEvalRunSummary, Rt as EvalAgentRunResult, Sn as buildTrajectory, Tn as createEvalAgent, Un as registerEvalTests, Ut as EvalCaseResult, Vn as llmJudge, Vt as EvalArtifacts, Wn as relativeArtifactPath, Wt as EvalDefinition, Xt as EvalRunReporterOptions, Yt as EvalRunReporter, Zt as EvalRunSummary, _n as TrajectoryStep, an as EvalWorkspaceFile, bn as buildEvalRunSummary, cn as LlmJudgeOptions, dn as MetricSpec, en as EvalScore, fn as MetricSpecMap, gn as Trajectory, hn as ReusableExecutionContext, in as EvalVariantSummary, jn as emitEfficiencyMetrics, kn as defineMetrics, ln as MetricDirection, mn as RegisterEvalTestsOptions, nn as EvalScorerContext, on as EvalWorkspaceOptions, pn as MetricStats, qt as EvalMetricError, rn as EvalTestRunner, sn as EvalWorkspaceSnapshot, tn as EvalScorer, un as MetricEmitter, vn as TrajectoryStepKind, wn as computeEvalTagScores, xn as buildRegisteredEvals, yn as artifactPath, zn as formatTrajectoryLine, zt as EvalAgentRunStats } from "./index-Gy9wi80M.js";
2
2
  export { CreateEvalAgentOptions, EFFICIENCY_METRICS, EvalAgent, EvalAgentMcpServers, EvalAgentRunOptions, EvalAgentRunResult, EvalAgentRunStats, EvalAgentStats, EvalArtifacts, EvalCaseOptions, EvalCaseResult, EvalDefinition, EvalDefinitionContext, EvalMetric, EvalMetricError, EvalRunMetricAggregate, EvalRunReporter, EvalRunReporterOptions, EvalRunSummary, EvalRunSummaryCase, EvalRunUsage, EvalScore, EvalScorer, EvalScorerContext, EvalTestRunner, EvalVariantSummary, EvalWorkspaceFile, EvalWorkspaceOptions, EvalWorkspaceSnapshot, LlmJudgeOptions, MetricDirection, MetricEmitter, MetricSpec, MetricSpecMap, MetricStats, RegisterEvalTestsOptions, ReusableExecutionContext, Trajectory, TrajectoryStep, TrajectoryStepKind, artifactPath, buildEvalRunSummary, buildRegisteredEvals, buildTrajectory, clearRegisteredEvals, computeEvalTagScores, createEvalAgent, createEvalRunReporter, createReusableExecutionContext, defineEval, defineMetrics, efficiencyMetricValues, emitEfficiencyMetrics, fileContains, fileContentQuality, fileExists, fileExistsOneOf, finalizeEvalMetrics, formatEvalCaseSummary, formatEvalRunSummary, formatTrajectoryLine, functionalityMetric, llmJudge, normalizeMetric, registerEvalTests, relativeArtifactPath, runEvalCase, statusCompleted };
package/dist/eval.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { r as createProcessContext } from "./contexts-DWVt7MvF.js";
2
2
  import { t as alwaysQuote } from "./shell-quote-BmnhZmdM.js";
3
- import { d as createMemoryStore, t as createSession } from "./session-DY2LWai4.js";
3
+ import { d as createMemoryStore, t as createSession } from "./session-B40flcj7.js";
4
4
  import { headlessEventToJsonl, runHeadless } from "./headless.js";
5
5
  import { join, relative, resolve } from "node:path";
6
6
  import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
@@ -1,2 +1,2 @@
1
- import { $a as ExtensionConfigSurface, $i as ExtensionCatalogPartition, $o as ExtensionToolResultTransform, Aa as inlineLoadedExtension, Ao as ExtensionModal, Ba as ExtensionConfigActionItem, Bo as ExtensionSessionStateSurface, Ca as removeInstalledExtension, Co as ExtensionFooterHint, Cs as createExtensionHostRuntimeBridge, Da as ExtensionScanEntry, Do as ExtensionKeybindingDispatchContext, Ea as ENTRY_CANDIDATES, Eo as ExtensionKeybinding, Fa as discoverAndBuildExtensionRegistry, Fo as ExtensionPromptTransform, Ga as ExtensionConfigChangeBehavior, Go as ExtensionToolCatalogTransform, Ha as ExtensionConfigActionStatus, Ho as ExtensionSource, Ia as ExtensionPromptBridge, Io as ExtensionProviderMiddleware, Ja as ExtensionConfigItemBase, Jo as ExtensionToolRenderer, Ka as ExtensionConfigEnumItem, Ko as ExtensionToolPolicy, La as ExtensionPromptDelivery, Lo as ExtensionRegistry, Ma as parseExtensionScanPathEnv, Mo as ExtensionOrderedContribution, Na as scanExtensionDirectories, No as ExtensionPaths, Oa as defaultExtensionScanPaths, Oo as ExtensionManifest, Pa as DiscoverAndBuildExtensionRegistryOptions, Po as ExtensionPermission, Qa as ExtensionConfigStringItem, Qi as BuildExtensionRegistryOptions, Qo as ExtensionToolResultPatch, Ra as createExtensionPromptBridge, Ro as ExtensionRunTransform, Sa as readExtensionInstallProvenance, So as ExtensionDefinition, Ss as ExtensionWorkspaceSurface, Ta as registerExtensionHostModules, To as ExtensionGuiSurface, Ua as ExtensionConfigBooleanItem, Uo as ExtensionStorageScope, Va as ExtensionConfigActionResult, Vo as ExtensionSkillPolicy, Wa as ExtensionConfigCategory, Wo as ExtensionStorageSurface, Xa as ExtensionConfigNumberItem, Xo as ExtensionToolRendererRegistration, Ya as ExtensionConfigModelItem, Yo as ExtensionToolRendererEntry, Za as ExtensionConfigScope, Zo as ExtensionToolResultMetadataRegistration, _a as InstalledExtensionTargetOptions, _o as ExtensionContext, _s as ExtensionModelEntry, aa as mergeContributions, ao as clampExtensionConfigNumber, as as ExtensionBannerOptions, ba as listExtensionCandidates, bo as ExtensionCustomRenderer, bs as ExtensionSessionsSurface, ca as ExtensionInstallCandidate, co as isValidExtensionConfigValue, cs as ExtensionHudStatus, da as ExtensionInstallIo, do as sanitizeExtensionConfigActionPatch, ds as ExtensionNotifyOptions, ea as buildExtensionPreset, eo as ExtensionConfigValue, es as ExtensionToolVerdict, fa as ExtensionInstallProvenance, fo as toWireConfigSchema, fs as ExtensionNotifyTone, ga as InstallExtensionFromSpecOptions, go as ExtensionCapability, gs as ExtensionHostRuntimeImpl, ha as ExtensionInstallSource, ho as ExtensionBehaviorTransform, hs as ExtensionHostRuntimeBridge, ia as filterExtensionRegistry, io as WireExtensionConfigSchema, is as TuiContributions, ja as isExtensionDefinition, jo as ExtensionModalNode, ka as discoverExtensions, ko as ExtensionMcpConfigTransform, la as ExtensionInstallError, lo as resolveExtensionConfig, ls as ExtensionHudWriter, ma as ExtensionInstallScope, mo as ExtensionApiVersion, ms as createExtensionHud, na as composeExtensionPreset, no as StoredExtensionConfigItem, ns as GuiContributions, oa as partitionExtensionCatalog, oo as coerceExtensionConfigInput, os as ExtensionHud, pa as ExtensionInstallResult, po as EMPTY_EXTENSION_REGISTRY, ps as ExtensionStatusOptions, qa as ExtensionConfigItem, qo as ExtensionToolRenderProps, ra as disposeExtensionRegistry, ro as WireExtensionConfigItem, rs as LoadedExtension, sa as ExtensionFetchResult, so as isValidExtensionConfigItem, ss as ExtensionHudState, ta as buildExtensionRegistry, to as ExtensionConfigValueItem, ts as ExtensionTuiSurface, ua as ExtensionInstallErrorCode, uo as resolveExtensionConfigValue, us as ExtensionNotification, va as fetchExtensionSource, vo as ExtensionContextTransform, vs as ExtensionRuntimeSurface, wa as updateInstalledExtension, wo as ExtensionGuiPanel, ws as createWorkspaceSurface, xa as parseExtensionInstallSource, xo as ExtensionCustomRendererEntry, xs as ExtensionWorkspacePair, ya as installExtensionFromSpec, yo as ExtensionContributions, ys as ExtensionSessionSummary, za as defineExtension, zo as ExtensionRuntimeEnv } from "./index-1Dr4Yqw1.js";
1
+ import { $a as ExtensionConfigSurface, $i as ExtensionCatalogPartition, $o as ExtensionToolResultTransform, Aa as inlineLoadedExtension, Ao as ExtensionModal, Ba as ExtensionConfigActionItem, Bo as ExtensionSessionStateSurface, Ca as removeInstalledExtension, Co as ExtensionFooterHint, Cs as createExtensionHostRuntimeBridge, Da as ExtensionScanEntry, Do as ExtensionKeybindingDispatchContext, Ea as ENTRY_CANDIDATES, Eo as ExtensionKeybinding, Fa as discoverAndBuildExtensionRegistry, Fo as ExtensionPromptTransform, Ga as ExtensionConfigChangeBehavior, Go as ExtensionToolCatalogTransform, Ha as ExtensionConfigActionStatus, Ho as ExtensionSource, Ia as ExtensionPromptBridge, Io as ExtensionProviderMiddleware, Ja as ExtensionConfigItemBase, Jo as ExtensionToolRenderer, Ka as ExtensionConfigEnumItem, Ko as ExtensionToolPolicy, La as ExtensionPromptDelivery, Lo as ExtensionRegistry, Ma as parseExtensionScanPathEnv, Mo as ExtensionOrderedContribution, Na as scanExtensionDirectories, No as ExtensionPaths, Oa as defaultExtensionScanPaths, Oo as ExtensionManifest, Pa as DiscoverAndBuildExtensionRegistryOptions, Po as ExtensionPermission, Qa as ExtensionConfigStringItem, Qi as BuildExtensionRegistryOptions, Qo as ExtensionToolResultPatch, Ra as createExtensionPromptBridge, Ro as ExtensionRunTransform, Sa as readExtensionInstallProvenance, So as ExtensionDefinition, Ss as ExtensionWorkspaceSurface, Ta as registerExtensionHostModules, To as ExtensionGuiSurface, Ua as ExtensionConfigBooleanItem, Uo as ExtensionStorageScope, Va as ExtensionConfigActionResult, Vo as ExtensionSkillPolicy, Wa as ExtensionConfigCategory, Wo as ExtensionStorageSurface, Xa as ExtensionConfigNumberItem, Xo as ExtensionToolRendererRegistration, Ya as ExtensionConfigModelItem, Yo as ExtensionToolRendererEntry, Za as ExtensionConfigScope, Zo as ExtensionToolResultMetadataRegistration, _a as InstalledExtensionTargetOptions, _o as ExtensionContext, _s as ExtensionModelEntry, aa as mergeContributions, ao as clampExtensionConfigNumber, as as ExtensionBannerOptions, ba as listExtensionCandidates, bo as ExtensionCustomRenderer, bs as ExtensionSessionsSurface, ca as ExtensionInstallCandidate, co as isValidExtensionConfigValue, cs as ExtensionHudStatus, da as ExtensionInstallIo, do as sanitizeExtensionConfigActionPatch, ds as ExtensionNotifyOptions, ea as buildExtensionPreset, eo as ExtensionConfigValue, es as ExtensionToolVerdict, fa as ExtensionInstallProvenance, fo as toWireConfigSchema, fs as ExtensionNotifyTone, ga as InstallExtensionFromSpecOptions, go as ExtensionCapability, gs as ExtensionHostRuntimeImpl, ha as ExtensionInstallSource, ho as ExtensionBehaviorTransform, hs as ExtensionHostRuntimeBridge, ia as filterExtensionRegistry, io as WireExtensionConfigSchema, is as TuiContributions, ja as isExtensionDefinition, jo as ExtensionModalNode, ka as discoverExtensions, ko as ExtensionMcpConfigTransform, la as ExtensionInstallError, lo as resolveExtensionConfig, ls as ExtensionHudWriter, ma as ExtensionInstallScope, mo as ExtensionApiVersion, ms as createExtensionHud, na as composeExtensionPreset, no as StoredExtensionConfigItem, ns as GuiContributions, oa as partitionExtensionCatalog, oo as coerceExtensionConfigInput, os as ExtensionHud, pa as ExtensionInstallResult, po as EMPTY_EXTENSION_REGISTRY, ps as ExtensionStatusOptions, qa as ExtensionConfigItem, qo as ExtensionToolRenderProps, ra as disposeExtensionRegistry, ro as WireExtensionConfigItem, rs as LoadedExtension, sa as ExtensionFetchResult, so as isValidExtensionConfigItem, ss as ExtensionHudState, ta as buildExtensionRegistry, to as ExtensionConfigValueItem, ts as ExtensionTuiSurface, ua as ExtensionInstallErrorCode, uo as resolveExtensionConfigValue, us as ExtensionNotification, va as fetchExtensionSource, vo as ExtensionContextTransform, vs as ExtensionRuntimeSurface, wa as updateInstalledExtension, wo as ExtensionGuiPanel, ws as createWorkspaceSurface, xa as parseExtensionInstallSource, xo as ExtensionCustomRendererEntry, xs as ExtensionWorkspacePair, ya as installExtensionFromSpec, yo as ExtensionContributions, ys as ExtensionSessionSummary, za as defineExtension, zo as ExtensionRuntimeEnv } from "./index-Gy9wi80M.js";
2
2
  export { type BuildExtensionRegistryOptions, type DiscoverAndBuildExtensionRegistryOptions, EMPTY_EXTENSION_REGISTRY, ENTRY_CANDIDATES, type ExtensionApiVersion, type ExtensionBannerOptions, type ExtensionBehaviorTransform, type ExtensionCapability, type ExtensionCatalogPartition, type ExtensionConfigActionItem, type ExtensionConfigActionResult, type ExtensionConfigActionStatus, type ExtensionConfigBooleanItem, type ExtensionConfigCategory, type ExtensionConfigChangeBehavior, type ExtensionConfigEnumItem, type ExtensionConfigItem, type ExtensionConfigItemBase, type ExtensionConfigModelItem, type ExtensionConfigNumberItem, type ExtensionConfigScope, type ExtensionConfigStringItem, type ExtensionConfigSurface, type ExtensionConfigValue, type ExtensionConfigValueItem, type ExtensionContext, type ExtensionContextTransform, type ExtensionContributions, type ExtensionCustomRenderer, type ExtensionCustomRendererEntry, type ExtensionDefinition, type ExtensionFetchResult, type ExtensionFooterHint, type ExtensionGuiPanel, type ExtensionGuiSurface, type ExtensionHostRuntimeBridge, type ExtensionHostRuntimeImpl, type ExtensionHud, type ExtensionHudState, type ExtensionHudStatus, type ExtensionHudWriter, type ExtensionInstallCandidate, ExtensionInstallError, type ExtensionInstallErrorCode, type ExtensionInstallIo, type ExtensionInstallProvenance, type ExtensionInstallResult, type ExtensionInstallScope, type ExtensionInstallSource, type ExtensionKeybinding, type ExtensionKeybindingDispatchContext, type ExtensionManifest, type ExtensionMcpConfigTransform, type ExtensionModal, type ExtensionModalNode, type ExtensionModelEntry, type ExtensionNotification, type ExtensionNotifyOptions, type ExtensionNotifyTone, type ExtensionOrderedContribution, type ExtensionPaths, type ExtensionPermission, type ExtensionPromptBridge, type ExtensionPromptDelivery, type ExtensionPromptTransform, type ExtensionProviderMiddleware, type ExtensionRegistry, type ExtensionRunTransform, type ExtensionRuntimeEnv, type ExtensionRuntimeSurface, type ExtensionScanEntry, type ExtensionSessionStateSurface, type ExtensionSessionSummary, type ExtensionSessionsSurface, type ExtensionSkillPolicy, type ExtensionSource, type ExtensionStatusOptions, type ExtensionStorageScope, type ExtensionStorageSurface, type ExtensionToolCatalogTransform, type ExtensionToolPolicy, type ExtensionToolRenderProps, type ExtensionToolRenderer, type ExtensionToolRendererEntry, type ExtensionToolRendererRegistration, type ExtensionToolResultMetadataRegistration, type ExtensionToolResultPatch, type ExtensionToolResultTransform, type ExtensionToolVerdict, type ExtensionTuiSurface, type ExtensionWorkspacePair, type ExtensionWorkspaceSurface, type GuiContributions, type InstallExtensionFromSpecOptions, type InstalledExtensionTargetOptions, type LoadedExtension, type StoredExtensionConfigItem, type TuiContributions, type WireExtensionConfigItem, type WireExtensionConfigSchema, buildExtensionPreset, buildExtensionRegistry, clampExtensionConfigNumber, coerceExtensionConfigInput, composeExtensionPreset, createExtensionHostRuntimeBridge, createExtensionHud, createExtensionPromptBridge, createWorkspaceSurface, defaultExtensionScanPaths, defineExtension, discoverAndBuildExtensionRegistry, discoverExtensions, disposeExtensionRegistry, fetchExtensionSource, filterExtensionRegistry, inlineLoadedExtension, installExtensionFromSpec, isExtensionDefinition, isValidExtensionConfigItem, isValidExtensionConfigValue, listExtensionCandidates, mergeContributions, parseExtensionInstallSource, parseExtensionScanPathEnv, partitionExtensionCatalog, readExtensionInstallProvenance, registerExtensionHostModules, removeInstalledExtension, resolveExtensionConfig, resolveExtensionConfigValue, sanitizeExtensionConfigActionPatch, scanExtensionDirectories, toWireConfigSchema, updateInstalledExtension };
@@ -1,2 +1,2 @@
1
- import { $ as removeInstalledExtension, G as EMPTY_EXTENSION_REGISTRY, J as fetchExtensionSource, K as createExtensionPromptBridge, Q as readExtensionInstallProvenance, X as listExtensionCandidates, Y as installExtensionFromSpec, Z as parseExtensionInstallSource, _n as resolveExtensionConfigValue, an as defaultExtensionScanPaths, at as composeExtensionPreset, cn as isExtensionDefinition, ct as mergeContributions, dn as defineExtension, dt as createWorkspaceSurface, et as updateInstalledExtension, fn as clampExtensionConfigNumber, gn as resolveExtensionConfig, hn as isValidExtensionConfigValue, in as ENTRY_CANDIDATES, it as buildExtensionRegistry, ln as parseExtensionScanPathEnv, lt as partitionExtensionCatalog, mn as isValidExtensionConfigItem, nt as discoverAndBuildExtensionRegistry, on as discoverExtensions, ot as disposeExtensionRegistry, pn as coerceExtensionConfigInput, q as ExtensionInstallError, rn as registerExtensionHostModules, rt as buildExtensionPreset, sn as inlineLoadedExtension, st as filterExtensionRegistry, tt as createExtensionHud, un as scanExtensionDirectories, ut as createExtensionHostRuntimeBridge, vn as sanitizeExtensionConfigActionPatch, yn as toWireConfigSchema } from "./agent-COHX5SpM.js";
1
+ import { $ as removeInstalledExtension, G as EMPTY_EXTENSION_REGISTRY, J as fetchExtensionSource, K as createExtensionPromptBridge, Q as readExtensionInstallProvenance, X as listExtensionCandidates, Y as installExtensionFromSpec, Z as parseExtensionInstallSource, _n as resolveExtensionConfigValue, an as defaultExtensionScanPaths, at as composeExtensionPreset, cn as isExtensionDefinition, ct as mergeContributions, dn as defineExtension, dt as createWorkspaceSurface, et as updateInstalledExtension, fn as clampExtensionConfigNumber, gn as resolveExtensionConfig, hn as isValidExtensionConfigValue, in as ENTRY_CANDIDATES, it as buildExtensionRegistry, ln as parseExtensionScanPathEnv, lt as partitionExtensionCatalog, mn as isValidExtensionConfigItem, nt as discoverAndBuildExtensionRegistry, on as discoverExtensions, ot as disposeExtensionRegistry, pn as coerceExtensionConfigInput, q as ExtensionInstallError, rn as registerExtensionHostModules, rt as buildExtensionPreset, sn as inlineLoadedExtension, st as filterExtensionRegistry, tt as createExtensionHud, un as scanExtensionDirectories, ut as createExtensionHostRuntimeBridge, vn as sanitizeExtensionConfigActionPatch, yn as toWireConfigSchema } from "./agent-BMJKrD84.js";
2
2
  export { EMPTY_EXTENSION_REGISTRY, ENTRY_CANDIDATES, ExtensionInstallError, buildExtensionPreset, buildExtensionRegistry, clampExtensionConfigNumber, coerceExtensionConfigInput, composeExtensionPreset, createExtensionHostRuntimeBridge, createExtensionHud, createExtensionPromptBridge, createWorkspaceSurface, defaultExtensionScanPaths, defineExtension, discoverAndBuildExtensionRegistry, discoverExtensions, disposeExtensionRegistry, fetchExtensionSource, filterExtensionRegistry, inlineLoadedExtension, installExtensionFromSpec, isExtensionDefinition, isValidExtensionConfigItem, isValidExtensionConfigValue, listExtensionCandidates, mergeContributions, parseExtensionInstallSource, parseExtensionScanPathEnv, partitionExtensionCatalog, readExtensionInstallProvenance, registerExtensionHostModules, removeInstalledExtension, resolveExtensionConfig, resolveExtensionConfigValue, sanitizeExtensionConfigActionPatch, scanExtensionDirectories, toWireConfigSchema, updateInstalledExtension };
@@ -1,4 +1,4 @@
1
- import { l as errorMessage } from "./errors-DJUxZg9b.js";
1
+ import { u as errorMessage } from "./errors-BwBxu3zD.js";
2
2
  import { Buffer } from "node:buffer";
3
3
  import { request } from "node:http";
4
4
  import { promises } from "node:dns";
@@ -531,4 +531,4 @@ const fetchUrl = {
531
531
  //#endregion
532
532
  export { isBlockedAddress as a, stripHtmlInline as c, fetchWithSsrfGuard as i, clearFetchUrlCache as n, isHostAllowed as o, fetchUrl as r, pinnedRequest as s, __fetchCacheTestApi as t };
533
533
 
534
- //# sourceMappingURL=fetch-url-_5WKWpbQ.js.map
534
+ //# sourceMappingURL=fetch-url-B7aSg6Bp.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fetch-url-_5WKWpbQ.js","names":["dns","request","httpsRequest","httpRequest"],"sources":["../src/tools/_html.ts","../src/tools/fetch-url.ts"],"sourcesContent":["/**\n * Shared HTML → plain-text helpers used by the web-egress tools (`web_search`\n * snippet extraction, `fetch_url` body decoding).\n *\n * Best-effort by contract: a real HTML parser would be more correct but the\n * payload is always model context, never user-facing rendered output, so a\n * tag-stripper plus a curated entity table covers the practical cases\n * (Wikipedia, GitHub READMEs, MDN docs, Stack Overflow answers). When a tool\n * needs richer parsing it should reach for an actual parser rather than\n * extending these helpers ad-hoc.\n */\n\n/**\n * Curated named-entity table. Kept narrow on purpose — the long tail\n * (`&Aring;`, `&times;`, mathematical refs, …) is out of scope because the\n * model handles unknown entities fine when they pass through verbatim. Add\n * entries when an entity is observed mangling real output, not speculatively.\n *\n * Keys are stored without the leading `&` / trailing `;` and matched\n * case-insensitively by the decoder.\n */\nconst NAMED_ENTITIES: Record<string, string> = {\n amp: '&',\n apos: '\\'',\n bull: '•',\n copy: '\\u00A9',\n ensp: ' ',\n emsp: ' ',\n gt: '>',\n hellip: '\\u2026',\n laquo: '\\u00AB',\n ldquo: '\\u201C',\n lsquo: '\\u2018',\n lt: '<',\n mdash: '\\u2014',\n middot: '\\u00B7',\n nbsp: ' ',\n ndash: '\\u2013',\n quot: '\"',\n raquo: '\\u00BB',\n rdquo: '\\u201D',\n reg: '\\u00AE',\n rsquo: '\\u2019',\n thinsp: ' ',\n trade: '\\u2122',\n}\n\n/**\n * `String.fromCodePoint` raises on out-of-range / non-finite inputs; the\n * agent's untrusted-payload assumption means we can't let a single broken\n * numeric reference crash the whole decode. Empty string on rejection is\n * the safest outcome (matches what most browsers do for invalid refs).\n */\nfunction safeFromCodePoint(cp: number): string {\n if (!Number.isFinite(cp) || cp < 0 || cp > 0x10FFFF)\n return ''\n try {\n return String.fromCodePoint(cp)\n }\n catch {\n return ''\n }\n}\n\n/**\n * Decode numeric character references (`&#x...;` / `&#NNN;`) and the curated\n * subset of named entities in {@link NAMED_ENTITIES}. Unknown named entities\n * are left as-is so the model can detect them rather than seeing a silently\n * corrupted token.\n *\n * `&amp;` is decoded LAST so a double-escaped string like `&amp;lt;` resolves\n * to `&lt;` (not `<`) — that's the spec-correct single-pass decode shape.\n */\nexport function decodeHtmlEntities(text: string): string {\n let s = text\n .replace(/&#x([0-9a-f]+);/gi, (_, h) => safeFromCodePoint(Number.parseInt(h, 16)))\n .replace(/&#(\\d+);/g, (_, n) => safeFromCodePoint(Number.parseInt(n, 10)))\n s = s.replace(/&([a-z][a-z0-9]*);/gi, (full, name) => {\n const key = name.toLowerCase()\n // Defer `amp` so `&amp;lt;` doesn't double-decode in a single pass.\n if (key === 'amp')\n return full\n const replacement = NAMED_ENTITIES[key]\n return replacement ?? full\n })\n return s.replace(/&amp;/gi, '&')\n}\n\n/**\n * Strip `<script>`, `<style>`, `<noscript>`, comments, and every other tag.\n * Block-level openers (`<br>`, `<p>`, `<div>`, `<li>`, `<tr>`, `<h1-6>`) are\n * replaced with newlines so the resulting plaintext preserves readable\n * structure. Other tags collapse to spaces.\n */\nexport function stripHtml(html: string): string {\n return html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, ' ')\n .replace(/<!--[\\s\\S]*?-->/g, ' ')\n .replace(/<(?:br|p|div|li|tr|h[1-6])[^>]*>/gi, '\\n')\n .replace(/<[^>]+>/g, ' ')\n}\n\n/**\n * Inline variant — strip tags + decode entities + collapse all whitespace\n * (including line breaks) into single spaces. For short snippets where\n * structural breaks would be visual noise (search-result titles, link text).\n */\nexport function stripHtmlInline(html: string): string {\n return decodeHtmlEntities(stripHtml(html))\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\n/**\n * Block variant — strip tags + decode entities, preserve newlines emitted\n * by block-level openers, then collapse inline whitespace per-line and drop\n * empty lines. For full-page reductions where structure aids reading.\n */\nexport function stripHtmlBlock(html: string): string {\n return decodeHtmlEntities(stripHtml(html))\n .split('\\n')\n .map(line => line.replace(/[ \\t]+/g, ' ').trim())\n .filter(line => line.length > 0)\n .join('\\n')\n}\n","import type { RequestOptions as HttpRequestOptions } from 'node:http'\nimport type { RequestOptions as HttpsRequestOptions } from 'node:https'\nimport type { ToolContext, ToolDef } from './types'\nimport { Buffer } from 'node:buffer'\nimport { promises as dns } from 'node:dns'\nimport { request as httpRequest } from 'node:http'\nimport { request as httpsRequest } from 'node:https'\nimport { isIP } from 'node:net'\nimport { errorMessage } from '../errors'\nimport { stripHtmlBlock } from './_html'\n\n/**\n * Fetch a URL and return its text content.\n *\n * Companion to `web_search` (when registered) — after the model finds a\n * promising result it fetches the page to read the body in full. HTML is\n * reduced to plain text because the model rarely benefits from the markup\n * and we want to keep the payload inside the per-turn output budget.\n *\n * Restrictions:\n * - Only http(s) URLs. Anything else (file://, data:, ftp:) is rejected so\n * the tool can't be coerced into reading local files or arbitrary\n * resources.\n * - SSRF guard with TOCTOU defense: the host is DNS-resolved against the\n * loopback / link-local / private / reserved blocklist BEFORE the\n * request, and the resolved IP is then PINNED at the connection layer\n * via `node:http(s).request({ host: <resolved IP>, headers: { Host: ... },\n * servername: ... })`. This closes the classic DNS-rebinding gap where a\n * `globalThis.fetch` re-resolves the hostname and connects to a freshly\n * minted private IP. TLS verification still runs against the original\n * hostname via the explicit `servername` option.\n *\n * Note: the more idiomatic Node fix (an `undici.Agent` with a custom\n * `connect.lookup`) is silently a no-op on Bun ≤1.3 — both\n * `undici.Agent` and `node:https.Agent.lookup` are stubbed out. The\n * explicit `host: IP` + `Host:` header dance is the only mechanism that\n * actually pins on the current Bun runtime.\n * - Redirects are followed manually (up to `MAX_REDIRECTS`) and each hop\n * is re-validated, so a public hostname that 302s into a metadata\n * endpoint is rejected at the redirect step.\n * - 15s hard timeout per request.\n * - Output capped at `max_bytes` (default 200 KiB) — long pages are\n * truncated with an explicit marker. The pinned reader also stops\n * buffering past 2× the cap so a multi-MB body can't OOM us.\n */\n\nconst DEFAULT_MAX_BYTES = 200 * 1024\nconst HARD_MAX_BYTES = 1024 * 1024\nconst HTTP_TIMEOUT_MS = 15_000\nconst MAX_REDIRECTS = 5\n\n/**\n * IPv4 ranges that the SSRF guard refuses to fetch from. Covers the cloud\n * metadata services (AWS/Azure 169.254.169.254, GCP routes through the same\n * link-local block) plus every RFC1918 / loopback / reserved block a model\n * could be prompt-injected into hitting.\n */\nfunction isBlockedIPv4(ip: string): boolean {\n const parts = ip.split('.').map(Number)\n if (parts.length !== 4 || parts.some(p => !Number.isInteger(p) || p < 0 || p > 255))\n return true\n const [a, b] = parts as [number, number, number, number]\n if (a === 0)\n return true // 0.0.0.0/8 unspecified / \"this network\"\n if (a === 10)\n return true // 10/8 private\n if (a === 127)\n return true // loopback\n if (a === 169 && b === 254)\n return true // link-local + cloud metadata\n if (a === 172 && b >= 16 && b <= 31)\n return true // 172.16/12 private\n if (a === 192 && b === 168)\n return true // 192.168/16 private\n if (a === 192 && b === 0 && parts[2] === 0)\n return true // 192.0.0/24 IETF\n if (a === 198 && (b === 18 || b === 19))\n return true // 198.18/15 benchmark\n if (a >= 224)\n return true // multicast + reserved (224/4, 240/4)\n return false\n}\n\nfunction isBlockedIPv6(ip: string): boolean {\n const lower = ip.toLowerCase()\n // Normalise IPv4-mapped (::ffff:1.2.3.4) — recurse on the v4 tail. URL\n // parsing tends to canonicalise the dotted form into the hex pair\n // `::ffff:a9fe:a9fe`, so accept both shapes.\n const v4MappedDotted = lower.match(/^::ffff:([0-9.]+)$/)\n if (v4MappedDotted)\n return isBlockedIPv4(v4MappedDotted[1]!)\n const v4MappedHex = lower.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/)\n if (v4MappedHex) {\n const hi = Number.parseInt(v4MappedHex[1]!, 16)\n const lo = Number.parseInt(v4MappedHex[2]!, 16)\n const ipv4 = `${(hi >> 8) & 0xFF}.${hi & 0xFF}.${(lo >> 8) & 0xFF}.${lo & 0xFF}`\n return isBlockedIPv4(ipv4)\n }\n if (lower === '::' || lower === '::1')\n return true\n // fc00::/7 unique-local (covers fc.. and fd..)\n if (/^f[cd][0-9a-f]{0,2}:/.test(lower))\n return true\n // fe80::/10 link-local\n if (/^fe[89ab][0-9a-f]?:/.test(lower))\n return true\n // ff00::/8 multicast\n if (lower.startsWith('ff'))\n return true\n return false\n}\n\nexport function isBlockedAddress(ip: string): boolean {\n const family = isIP(ip)\n if (family === 4)\n return isBlockedIPv4(ip)\n if (family === 6)\n return isBlockedIPv6(ip)\n return true // not a recognised IP literal — refuse\n}\n\n/**\n * Normalize a hostname for allowlist comparison: lowercase, strip a trailing\n * dot (FQDN root) and IPv6 brackets, drop a leading dot on allowlist entries.\n */\nfunction normalizeHost(host: string): string {\n let h = host.trim().toLowerCase()\n if (h.startsWith('[') && h.endsWith(']'))\n h = h.slice(1, -1)\n if (h.endsWith('.'))\n h = h.slice(0, -1)\n if (h.startsWith('.'))\n h = h.slice(1)\n return h\n}\n\n/**\n * Site identity for cross-host redirect detection: the lowercased hostname\n * with a leading `www.` stripped, so `example.com` ⇄ `www.example.com` and a\n * path-only redirect aren't flagged as cross-host. Returns `null` for an\n * unparseable URL (caller skips the note rather than guessing).\n */\nfunction sameSiteHost(url: string): string | null {\n try {\n return new URL(url).hostname.toLowerCase().replace(/^www\\./, '')\n }\n catch {\n return null\n }\n}\n\n/**\n * Host-suffix allowlist check. An empty / undefined list means \"no allowlist\"\n * → every host passes (the SSRF blocklist is the only gate). Otherwise the\n * host must equal, or be a subdomain of, one of the entries. Subdomain match\n * is on a dot boundary so `example.com` matches `docs.example.com` but not\n * `notexample.com`.\n */\nexport function isHostAllowed(hostname: string, allowHosts: readonly string[] | undefined): boolean {\n if (!allowHosts || allowHosts.length === 0)\n return true\n const host = normalizeHost(hostname)\n for (const entry of allowHosts) {\n const allowed = normalizeHost(entry)\n if (allowed.length === 0)\n continue\n if (host === allowed || host.endsWith(`.${allowed}`))\n return true\n }\n return false\n}\n\n/**\n * Resolve `hostname` and refuse if any answer falls in a blocked range.\n *\n * Returns the first allowed `{ address, family }` so the caller can pin\n * the connection to it. Throws on any blocked answer so a multi-record\n * response with one private record fails closed.\n */\nasync function resolveAndCheck(hostname: string, allowHosts?: readonly string[]): Promise<{ address: string, family: 4 | 6 }> {\n // Egress allowlist (when configured) gates BEFORE DNS so a non-approved\n // host never even triggers a lookup. Enforced here so every redirect hop\n // is re-checked, not just the initial URL.\n if (!isHostAllowed(hostname, allowHosts))\n throw new Error(`refused: ${hostname} is not in the configured egress allowlist`)\n // `URL.hostname` keeps brackets around IPv6 literals (`[::1]`) — strip them\n // before the IP check so `isIP` recognises the literal and `dns.lookup`\n // doesn't try to resolve `[::1]` as a name.\n const bare = hostname.startsWith('[') && hostname.endsWith(']')\n ? hostname.slice(1, -1)\n : hostname\n const family = isIP(bare)\n if (family === 4 || family === 6) {\n if (isBlockedAddress(bare))\n throw new Error(`refused: ${bare} is in a blocked range`)\n return { address: bare, family }\n }\n const answers = await dns.lookup(bare, { all: true, verbatim: true })\n if (answers.length === 0)\n throw new Error(`DNS lookup returned no records for ${bare}`)\n for (const { address } of answers) {\n if (isBlockedAddress(address))\n throw new Error(`refused: ${bare} resolves to blocked address ${address}`)\n }\n const first = answers[0]!\n const fam = first.family === 6 ? 6 : 4\n return { address: first.address, family: fam }\n}\n\n/**\n * Pinned HTTP/HTTPS request. Connects to `pinnedIp` directly (bypassing\n * Node/Bun's own DNS resolution) while preserving the `Host:` header and\n * (for HTTPS) TLS SNI on the URL's original hostname. This is the\n * concrete defense against DNS rebinding — see the file-level docstring.\n *\n * Reads up to `maxBufferBytes` of body and then forcibly closes the\n * connection. The body is decoded as UTF-8; binary responses degrade to\n * mojibake but the tool's contract is text payloads anyway.\n */\ninterface PinnedResponse {\n status: number\n url: string\n contentType: string\n body: string\n location: string | null\n /**\n * True when the body was cut at `maxBufferBytes` before the server\n * finished sending. Optional so test seams that stub `requestImpl`\n * don't have to populate it; absent means \"not truncated\".\n */\n truncated?: boolean\n}\n\nfunction buildHostHeader(url: URL): string {\n if (!url.port)\n return url.hostname\n const defaultPort = url.protocol === 'https:' ? '443' : '80'\n return url.port === defaultPort ? url.hostname : `${url.hostname}:${url.port}`\n}\n\nexport function pinnedRequest(\n url: URL,\n pinnedIp: string,\n family: 4 | 6,\n headers: Record<string, string>,\n signal: AbortSignal,\n maxBufferBytes: number,\n): Promise<PinnedResponse> {\n return new Promise((resolve, reject) => {\n const isHttps = url.protocol === 'https:'\n const port = url.port\n ? Number.parseInt(url.port, 10)\n : (isHttps ? 443 : 80)\n\n // `host` is the literal IP, `servername` is the original hostname so\n // TLS cert verification still matches the cert's SAN/CN against the\n // user-visible name. Node uses `servername` for `checkServerIdentity`\n // automatically when set.\n const options: HttpRequestOptions & HttpsRequestOptions = {\n host: pinnedIp,\n port,\n path: `${url.pathname}${url.search}`,\n method: 'GET',\n family,\n headers: { ...headers, Host: buildHostHeader(url) },\n ...(isHttps ? { servername: url.hostname } : {}),\n }\n\n const request = isHttps ? httpsRequest : httpRequest\n const chunks: Buffer[] = []\n let received = 0\n // Single-shot settle guard. Bun's `node:http` is quirky around\n // `req.destroy(err)` — passing an error doesn't reliably surface as an\n // `error` event the way it does on Node. We track the settle state\n // ourselves and call `resolve` / `reject` directly from the abort /\n // timeout paths so the promise terminates even when the underlying\n // socket teardown is silent.\n let settled = false\n // Forward-declared so the `finish` / abort / timeout handlers can\n // close over `req` before it's assigned below. The request object is\n // wired into them via mutable refs because the handlers must be set\n // up *before* `request(options, callback)` fires its first event.\n let req: ReturnType<typeof httpRequest> | undefined\n let timer: ReturnType<typeof setTimeout> | undefined\n\n const teardown = (): void => {\n try { req?.destroy() }\n catch { /* tear-down best effort */ }\n }\n\n const finish = (settler: () => void): void => {\n if (settled)\n return\n settled = true\n if (timer)\n clearTimeout(timer)\n signal.removeEventListener('abort', onSignalAbort)\n settler()\n }\n\n function onSignalAbort(): void {\n finish(() => reject(new Error('request aborted')))\n teardown()\n }\n\n // Pre-aborted signal — short-circuit so we don't even open a socket.\n // (This is the realistic shape when a user hits Ctrl+C while the agent\n // is already shutting down: the signal is `.aborted` by the time the\n // tool function runs.)\n if (signal.aborted) {\n reject(new Error('request aborted'))\n return\n }\n\n timer = setTimeout(() => {\n finish(() => reject(new Error(`request timed out after ${HTTP_TIMEOUT_MS}ms`)))\n teardown()\n }, HTTP_TIMEOUT_MS)\n\n signal.addEventListener('abort', onSignalAbort, { once: true })\n\n req = request(options, (res) => {\n const status = res.statusCode ?? 0\n const headersOut = res.headers\n const contentType = (headersOut['content-type'] ?? '').toString().toLowerCase()\n const location = typeof headersOut.location === 'string' ? headersOut.location : null\n\n // Short-circuit on redirect responses — body is irrelevant.\n if (status >= 300 && status < 400 && location) {\n res.resume() // drain so the socket can be released\n finish(() => resolve({ status, url: url.toString(), contentType, body: '', location }))\n return\n }\n\n let bodyTruncated = false\n res.on('data', (chunk: Buffer) => {\n if (received >= maxBufferBytes) {\n // Stop accumulating; tear the socket down so the server stops\n // sending. We still resolve cleanly from `end` (or `close` if\n // the server doesn't finish flushing before the kill lands).\n bodyTruncated = true\n teardown()\n return\n }\n // Keep only what fits in the budget — a chunk straddling the cap\n // would otherwise overshoot it by up to one chunk. A partial slice\n // means the body was cut, so flag it and stop the transfer.\n const room = maxBufferBytes - received\n if (chunk.length > room) {\n chunks.push(chunk.subarray(0, room))\n received += room\n bodyTruncated = true\n teardown()\n return\n }\n received += chunk.length\n chunks.push(chunk)\n })\n res.on('end', () => {\n const body = Buffer.concat(chunks).toString('utf-8')\n finish(() => resolve({ status, url: url.toString(), contentType, body, location: null, truncated: bodyTruncated }))\n })\n res.on('close', () => {\n // Socket torn down before `end` (e.g. when our maxBufferBytes\n // trigger destroyed the request). Resolve with whatever we\n // buffered so far — `truncated` tells the caller the body is cut.\n if (!settled) {\n const body = Buffer.concat(chunks).toString('utf-8')\n finish(() => resolve({ status, url: url.toString(), contentType, body, location: null, truncated: bodyTruncated }))\n }\n })\n res.on('error', err => finish(() => reject(err)))\n })\n\n req.on('error', (err: Error) => finish(() => reject(err)))\n req.end()\n })\n}\n\n/**\n * Walk up to {@link MAX_REDIRECTS} hops, validating the target host of each\n * 3xx response against the SSRF blocklist before following.\n *\n * `deps` is an internal seam for tests — production callers use the\n * defaults. Both knobs are intentionally opaque: hosts that want to\n * customize the blocklist should use a higher-level mechanism (a future\n * `behavior.fetchUrlAllowHosts` setting) rather than reaching into this.\n */\nexport interface FetchSsrfDeps {\n /** Resolve + validate a hostname. Defaults to {@link resolveAndCheck}. */\n resolver?: (hostname: string) => Promise<{ address: string, family: 4 | 6 }>\n /** Execute a single pinned HTTP request. Defaults to {@link pinnedRequest}. */\n requestImpl?: typeof pinnedRequest\n}\n\nexport async function fetchWithSsrfGuard(\n startUrl: URL,\n headers: Record<string, string>,\n signal: AbortSignal,\n maxBufferBytes: number,\n deps: FetchSsrfDeps = {},\n allowHosts?: readonly string[],\n): Promise<PinnedResponse> {\n // Default resolver binds the egress allowlist; a test-injected resolver\n // owns its own policy.\n const resolver = deps.resolver ?? ((hostname: string) => resolveAndCheck(hostname, allowHosts))\n const requestImpl = deps.requestImpl ?? pinnedRequest\n let current = startUrl\n for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {\n const { address, family } = await resolver(current.hostname)\n const res = await requestImpl(current, address, family, headers, signal, maxBufferBytes)\n if (!res.location)\n return res\n if (hop === MAX_REDIRECTS)\n throw new Error(`too many redirects (>${MAX_REDIRECTS})`)\n let next: URL\n try {\n next = new URL(res.location, current)\n }\n catch {\n throw new Error(`invalid redirect target: ${res.location}`)\n }\n if (next.protocol !== 'http:' && next.protocol !== 'https:')\n throw new Error(`refused redirect to non-http(s) target: ${next.protocol}`)\n current = next\n }\n throw new Error('redirect loop exited unexpectedly')\n}\n\n/**\n * Opt-in, process-local response cache for `fetch_url`. Disabled unless\n * `behavior.fetchUrlCacheTtlMs` is set (> 0). Bounded by entry count and total\n * cached bytes; eviction is oldest-first (insertion order via `Map`, which is\n * a good-enough LRU because we delete-then-set on hit to refresh recency).\n *\n * Keyed on `<url>\\u0000<cap>\\u0000<egress-policy>` so two calls with different\n * `max_bytes` (hence different truncation) don't alias, and — because the\n * cache is module-global — an agent with a permissive `fetchUrlAllowHosts`\n * can't populate entries that a co-resident agent with a stricter allowlist\n * would then be served. Only successful text responses are stored — the\n * caller gates on status before writing.\n */\nconst FETCH_CACHE_MAX_ENTRIES = 64\nconst FETCH_CACHE_MAX_BYTES = 16 * 1024 * 1024 // 16 MiB total\n\ninterface FetchCacheEntry {\n /** Fully-formatted tool output (header + body) ready to return verbatim. */\n output: string\n expiresAt: number\n bytes: number\n}\n\nconst fetchCache = new Map<string, FetchCacheEntry>()\nlet fetchCacheBytes = 0\n\nfunction cacheKey(url: string, cap: number, allowHosts?: readonly string[]): string {\n // Normalize + sort so equivalent policies (`['A.com', 'b.com']` vs\n // `['b.com', 'a.com.']`) share entries; an absent/empty allowlist keys\n // as the empty policy.\n const policy = (allowHosts ?? []).map(normalizeHost).sort().join(',')\n return `${url}\\u0000${cap}\\u0000${policy}`\n}\n\nfunction cacheGet(key: string): string | null {\n const entry = fetchCache.get(key)\n if (!entry)\n return null\n if (Date.now() >= entry.expiresAt) {\n fetchCache.delete(key)\n fetchCacheBytes -= entry.bytes\n return null\n }\n // Refresh recency: re-insert at the tail of the Map's iteration order.\n fetchCache.delete(key)\n fetchCache.set(key, entry)\n return entry.output\n}\n\nfunction cacheSet(key: string, output: string, ttlMs: number): void {\n const bytes = Buffer.byteLength(output, 'utf-8')\n // A single oversize payload that can't fit under the byte cap is simply not\n // cached (still returned to the caller) rather than evicting everything.\n if (bytes > FETCH_CACHE_MAX_BYTES)\n return\n // Drop any stale entry for this key first so the byte accounting stays exact.\n const prev = fetchCache.get(key)\n if (prev) {\n fetchCache.delete(key)\n fetchCacheBytes -= prev.bytes\n }\n fetchCache.set(key, { output, expiresAt: Date.now() + ttlMs, bytes })\n fetchCacheBytes += bytes\n // Evict oldest-first until both caps are satisfied.\n while (fetchCache.size > FETCH_CACHE_MAX_ENTRIES || fetchCacheBytes > FETCH_CACHE_MAX_BYTES) {\n const oldest = fetchCache.keys().next().value\n if (oldest === undefined)\n break\n const victim = fetchCache.get(oldest)!\n fetchCache.delete(oldest)\n fetchCacheBytes -= victim.bytes\n }\n}\n\n/** Test seam — drop all cached entries. */\nexport function clearFetchUrlCache(): void {\n fetchCache.clear()\n fetchCacheBytes = 0\n}\n\n/**\n * Test seam — exercise the cache get/set/eviction in isolation without\n * standing up the full SSRF + HTTP path. Not part of the public tool surface;\n * `execute` uses the module-private functions directly.\n */\nexport const __fetchCacheTestApi = {\n key: cacheKey,\n get: cacheGet,\n set: cacheSet,\n size: () => fetchCache.size,\n bytes: () => fetchCacheBytes,\n}\n\nexport const fetchUrl: ToolDef = {\n isConcurrencySafe: true,\n spec: {\n name: 'fetch_url',\n description: 'Fetch a public URL and return its body as plain text. HTML is reduced to text (scripts, styles, tags stripped; entities decoded). If a `web_search` tool is also available, use it first when you do not already know the exact URL. Only http(s) URLs are accepted; loopback, link-local, private, and cloud-metadata addresses are refused. Output is capped (default 200 KiB).',\n inputSchema: {\n type: 'object',\n properties: {\n url: {\n type: 'string',\n description: 'HTTP or HTTPS URL to fetch.',\n },\n max_bytes: {\n type: 'number',\n description: `Truncate the response body beyond this many bytes. Default: ${DEFAULT_MAX_BYTES}. Hard cap: ${HARD_MAX_BYTES}.`,\n },\n },\n required: ['url'],\n },\n },\n async execute({ url, max_bytes }, ctx: ToolContext) {\n const raw = typeof url === 'string' ? url.trim() : ''\n if (!raw)\n return 'fetch_url error: `url` is required'\n let parsed: URL\n try {\n parsed = new URL(raw)\n }\n catch {\n return `fetch_url error: invalid URL: ${raw}`\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:')\n return `fetch_url error: only http(s) URLs are allowed (got ${parsed.protocol})`\n\n const cap = Math.min(\n typeof max_bytes === 'number' && max_bytes > 0 ? Math.floor(max_bytes) : DEFAULT_MAX_BYTES,\n HARD_MAX_BYTES,\n )\n // Buffer up to 2× the cap so HTML overhead doesn't starve the visible\n // text budget — a 200 KiB cap on rendered text can legitimately need to\n // read ~400 KiB of raw HTML before stripping. Hard ceiling is still\n // governed by `HARD_MAX_BYTES * 2` which is comfortably below OOM.\n const bufferCap = Math.min(cap * 2, HARD_MAX_BYTES * 2)\n\n // Opt-in response cache (off unless `behavior.fetchUrlCacheTtlMs > 0`).\n // The egress allowlist is part of the key AND re-checked before serving\n // a hit — the cache is module-global, so neither a policy change within\n // an agent nor a co-resident agent's entries may bypass this agent's\n // allowlist.\n const allowHosts = ctx.behavior?.fetchUrlAllowHosts\n const ttlMs = ctx.behavior?.fetchUrlCacheTtlMs\n const cacheEnabled = typeof ttlMs === 'number' && ttlMs > 0\n const key = cacheKey(parsed.toString(), cap, allowHosts)\n if (cacheEnabled && isHostAllowed(parsed.hostname, allowHosts)) {\n const hit = cacheGet(key)\n if (hit !== null)\n return hit\n }\n\n try {\n const res = await fetchWithSsrfGuard(\n parsed,\n {\n 'user-agent': 'Mozilla/5.0 (compatible; zidane/1.0)',\n 'accept': 'text/html,text/plain,application/json;q=0.9,*/*;q=0.5',\n 'accept-encoding': 'identity', // no gzip — we don't decompress\n },\n ctx.signal,\n bufferCap,\n {},\n allowHosts,\n )\n const body = res.body\n const isHtml = res.contentType.includes('html') || /^\\s*<!doctype html|^\\s*<html/i.test(body)\n const text = isHtml ? stripHtmlBlock(body) : body\n const truncated = text.length > cap\n // Two distinct truncation reasons: the rendered text overflowing `cap`,\n // and the raw transfer being cut at the buffer ceiling (`res.truncated`)\n // — the latter can leave the rendered text under `cap` (HTML overhead\n // stripped away), so it needs its own marker or the model would treat\n // a partial body as complete.\n const out = truncated\n ? `${text.slice(0, cap)}\\n\\n[truncated at ${cap} bytes; full length ${text.length}]`\n : res.truncated\n ? `${text}\\n\\n[response truncated: body exceeded the ${bufferCap}-byte transfer buffer]`\n : text\n // `res.url` reflects the FINAL hop after redirects; flag a cross-host\n // landing so the model knows the content came from a different origin\n // than it asked for (open-redirect awareness). Same-host path changes\n // and www add/strip are treated as the same site and not flagged.\n const finalHost = sameSiteHost(res.url)\n const requestedHost = sameSiteHost(parsed.toString())\n const redirectNote = finalHost && requestedHost && finalHost !== requestedHost\n ? `Note: ${parsed.hostname} redirected to a different host (${new URL(res.url).hostname}).\\n`\n : ''\n const header = `URL: ${res.url}\\nStatus: ${res.status}\\nContent-Type: ${res.contentType || '(none)'}\\n${redirectNote}\\n`\n const formatted = header + out\n // Cache only successful, complete text responses — never errors /\n // redirects / transfer-truncated bodies (a retry may get the rest).\n if (cacheEnabled && res.status >= 200 && res.status < 300 && res.truncated !== true)\n cacheSet(key, formatted, ttlMs)\n return formatted\n }\n catch (err) {\n return `fetch_url error: ${errorMessage(err)}`\n }\n },\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"fetch-url-B7aSg6Bp.js","names":["dns","request","httpsRequest","httpRequest"],"sources":["../src/tools/_html.ts","../src/tools/fetch-url.ts"],"sourcesContent":["/**\n * Shared HTML → plain-text helpers used by the web-egress tools (`web_search`\n * snippet extraction, `fetch_url` body decoding).\n *\n * Best-effort by contract: a real HTML parser would be more correct but the\n * payload is always model context, never user-facing rendered output, so a\n * tag-stripper plus a curated entity table covers the practical cases\n * (Wikipedia, GitHub READMEs, MDN docs, Stack Overflow answers). When a tool\n * needs richer parsing it should reach for an actual parser rather than\n * extending these helpers ad-hoc.\n */\n\n/**\n * Curated named-entity table. Kept narrow on purpose — the long tail\n * (`&Aring;`, `&times;`, mathematical refs, …) is out of scope because the\n * model handles unknown entities fine when they pass through verbatim. Add\n * entries when an entity is observed mangling real output, not speculatively.\n *\n * Keys are stored without the leading `&` / trailing `;` and matched\n * case-insensitively by the decoder.\n */\nconst NAMED_ENTITIES: Record<string, string> = {\n amp: '&',\n apos: '\\'',\n bull: '•',\n copy: '\\u00A9',\n ensp: ' ',\n emsp: ' ',\n gt: '>',\n hellip: '\\u2026',\n laquo: '\\u00AB',\n ldquo: '\\u201C',\n lsquo: '\\u2018',\n lt: '<',\n mdash: '\\u2014',\n middot: '\\u00B7',\n nbsp: ' ',\n ndash: '\\u2013',\n quot: '\"',\n raquo: '\\u00BB',\n rdquo: '\\u201D',\n reg: '\\u00AE',\n rsquo: '\\u2019',\n thinsp: ' ',\n trade: '\\u2122',\n}\n\n/**\n * `String.fromCodePoint` raises on out-of-range / non-finite inputs; the\n * agent's untrusted-payload assumption means we can't let a single broken\n * numeric reference crash the whole decode. Empty string on rejection is\n * the safest outcome (matches what most browsers do for invalid refs).\n */\nfunction safeFromCodePoint(cp: number): string {\n if (!Number.isFinite(cp) || cp < 0 || cp > 0x10FFFF)\n return ''\n try {\n return String.fromCodePoint(cp)\n }\n catch {\n return ''\n }\n}\n\n/**\n * Decode numeric character references (`&#x...;` / `&#NNN;`) and the curated\n * subset of named entities in {@link NAMED_ENTITIES}. Unknown named entities\n * are left as-is so the model can detect them rather than seeing a silently\n * corrupted token.\n *\n * `&amp;` is decoded LAST so a double-escaped string like `&amp;lt;` resolves\n * to `&lt;` (not `<`) — that's the spec-correct single-pass decode shape.\n */\nexport function decodeHtmlEntities(text: string): string {\n let s = text\n .replace(/&#x([0-9a-f]+);/gi, (_, h) => safeFromCodePoint(Number.parseInt(h, 16)))\n .replace(/&#(\\d+);/g, (_, n) => safeFromCodePoint(Number.parseInt(n, 10)))\n s = s.replace(/&([a-z][a-z0-9]*);/gi, (full, name) => {\n const key = name.toLowerCase()\n // Defer `amp` so `&amp;lt;` doesn't double-decode in a single pass.\n if (key === 'amp')\n return full\n const replacement = NAMED_ENTITIES[key]\n return replacement ?? full\n })\n return s.replace(/&amp;/gi, '&')\n}\n\n/**\n * Strip `<script>`, `<style>`, `<noscript>`, comments, and every other tag.\n * Block-level openers (`<br>`, `<p>`, `<div>`, `<li>`, `<tr>`, `<h1-6>`) are\n * replaced with newlines so the resulting plaintext preserves readable\n * structure. Other tags collapse to spaces.\n */\nexport function stripHtml(html: string): string {\n return html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, ' ')\n .replace(/<!--[\\s\\S]*?-->/g, ' ')\n .replace(/<(?:br|p|div|li|tr|h[1-6])[^>]*>/gi, '\\n')\n .replace(/<[^>]+>/g, ' ')\n}\n\n/**\n * Inline variant — strip tags + decode entities + collapse all whitespace\n * (including line breaks) into single spaces. For short snippets where\n * structural breaks would be visual noise (search-result titles, link text).\n */\nexport function stripHtmlInline(html: string): string {\n return decodeHtmlEntities(stripHtml(html))\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\n/**\n * Block variant — strip tags + decode entities, preserve newlines emitted\n * by block-level openers, then collapse inline whitespace per-line and drop\n * empty lines. For full-page reductions where structure aids reading.\n */\nexport function stripHtmlBlock(html: string): string {\n return decodeHtmlEntities(stripHtml(html))\n .split('\\n')\n .map(line => line.replace(/[ \\t]+/g, ' ').trim())\n .filter(line => line.length > 0)\n .join('\\n')\n}\n","import type { RequestOptions as HttpRequestOptions } from 'node:http'\nimport type { RequestOptions as HttpsRequestOptions } from 'node:https'\nimport type { ToolContext, ToolDef } from './types'\nimport { Buffer } from 'node:buffer'\nimport { promises as dns } from 'node:dns'\nimport { request as httpRequest } from 'node:http'\nimport { request as httpsRequest } from 'node:https'\nimport { isIP } from 'node:net'\nimport { errorMessage } from '../errors'\nimport { stripHtmlBlock } from './_html'\n\n/**\n * Fetch a URL and return its text content.\n *\n * Companion to `web_search` (when registered) — after the model finds a\n * promising result it fetches the page to read the body in full. HTML is\n * reduced to plain text because the model rarely benefits from the markup\n * and we want to keep the payload inside the per-turn output budget.\n *\n * Restrictions:\n * - Only http(s) URLs. Anything else (file://, data:, ftp:) is rejected so\n * the tool can't be coerced into reading local files or arbitrary\n * resources.\n * - SSRF guard with TOCTOU defense: the host is DNS-resolved against the\n * loopback / link-local / private / reserved blocklist BEFORE the\n * request, and the resolved IP is then PINNED at the connection layer\n * via `node:http(s).request({ host: <resolved IP>, headers: { Host: ... },\n * servername: ... })`. This closes the classic DNS-rebinding gap where a\n * `globalThis.fetch` re-resolves the hostname and connects to a freshly\n * minted private IP. TLS verification still runs against the original\n * hostname via the explicit `servername` option.\n *\n * Note: the more idiomatic Node fix (an `undici.Agent` with a custom\n * `connect.lookup`) is silently a no-op on Bun ≤1.3 — both\n * `undici.Agent` and `node:https.Agent.lookup` are stubbed out. The\n * explicit `host: IP` + `Host:` header dance is the only mechanism that\n * actually pins on the current Bun runtime.\n * - Redirects are followed manually (up to `MAX_REDIRECTS`) and each hop\n * is re-validated, so a public hostname that 302s into a metadata\n * endpoint is rejected at the redirect step.\n * - 15s hard timeout per request.\n * - Output capped at `max_bytes` (default 200 KiB) — long pages are\n * truncated with an explicit marker. The pinned reader also stops\n * buffering past 2× the cap so a multi-MB body can't OOM us.\n */\n\nconst DEFAULT_MAX_BYTES = 200 * 1024\nconst HARD_MAX_BYTES = 1024 * 1024\nconst HTTP_TIMEOUT_MS = 15_000\nconst MAX_REDIRECTS = 5\n\n/**\n * IPv4 ranges that the SSRF guard refuses to fetch from. Covers the cloud\n * metadata services (AWS/Azure 169.254.169.254, GCP routes through the same\n * link-local block) plus every RFC1918 / loopback / reserved block a model\n * could be prompt-injected into hitting.\n */\nfunction isBlockedIPv4(ip: string): boolean {\n const parts = ip.split('.').map(Number)\n if (parts.length !== 4 || parts.some(p => !Number.isInteger(p) || p < 0 || p > 255))\n return true\n const [a, b] = parts as [number, number, number, number]\n if (a === 0)\n return true // 0.0.0.0/8 unspecified / \"this network\"\n if (a === 10)\n return true // 10/8 private\n if (a === 127)\n return true // loopback\n if (a === 169 && b === 254)\n return true // link-local + cloud metadata\n if (a === 172 && b >= 16 && b <= 31)\n return true // 172.16/12 private\n if (a === 192 && b === 168)\n return true // 192.168/16 private\n if (a === 192 && b === 0 && parts[2] === 0)\n return true // 192.0.0/24 IETF\n if (a === 198 && (b === 18 || b === 19))\n return true // 198.18/15 benchmark\n if (a >= 224)\n return true // multicast + reserved (224/4, 240/4)\n return false\n}\n\nfunction isBlockedIPv6(ip: string): boolean {\n const lower = ip.toLowerCase()\n // Normalise IPv4-mapped (::ffff:1.2.3.4) — recurse on the v4 tail. URL\n // parsing tends to canonicalise the dotted form into the hex pair\n // `::ffff:a9fe:a9fe`, so accept both shapes.\n const v4MappedDotted = lower.match(/^::ffff:([0-9.]+)$/)\n if (v4MappedDotted)\n return isBlockedIPv4(v4MappedDotted[1]!)\n const v4MappedHex = lower.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/)\n if (v4MappedHex) {\n const hi = Number.parseInt(v4MappedHex[1]!, 16)\n const lo = Number.parseInt(v4MappedHex[2]!, 16)\n const ipv4 = `${(hi >> 8) & 0xFF}.${hi & 0xFF}.${(lo >> 8) & 0xFF}.${lo & 0xFF}`\n return isBlockedIPv4(ipv4)\n }\n if (lower === '::' || lower === '::1')\n return true\n // fc00::/7 unique-local (covers fc.. and fd..)\n if (/^f[cd][0-9a-f]{0,2}:/.test(lower))\n return true\n // fe80::/10 link-local\n if (/^fe[89ab][0-9a-f]?:/.test(lower))\n return true\n // ff00::/8 multicast\n if (lower.startsWith('ff'))\n return true\n return false\n}\n\nexport function isBlockedAddress(ip: string): boolean {\n const family = isIP(ip)\n if (family === 4)\n return isBlockedIPv4(ip)\n if (family === 6)\n return isBlockedIPv6(ip)\n return true // not a recognised IP literal — refuse\n}\n\n/**\n * Normalize a hostname for allowlist comparison: lowercase, strip a trailing\n * dot (FQDN root) and IPv6 brackets, drop a leading dot on allowlist entries.\n */\nfunction normalizeHost(host: string): string {\n let h = host.trim().toLowerCase()\n if (h.startsWith('[') && h.endsWith(']'))\n h = h.slice(1, -1)\n if (h.endsWith('.'))\n h = h.slice(0, -1)\n if (h.startsWith('.'))\n h = h.slice(1)\n return h\n}\n\n/**\n * Site identity for cross-host redirect detection: the lowercased hostname\n * with a leading `www.` stripped, so `example.com` ⇄ `www.example.com` and a\n * path-only redirect aren't flagged as cross-host. Returns `null` for an\n * unparseable URL (caller skips the note rather than guessing).\n */\nfunction sameSiteHost(url: string): string | null {\n try {\n return new URL(url).hostname.toLowerCase().replace(/^www\\./, '')\n }\n catch {\n return null\n }\n}\n\n/**\n * Host-suffix allowlist check. An empty / undefined list means \"no allowlist\"\n * → every host passes (the SSRF blocklist is the only gate). Otherwise the\n * host must equal, or be a subdomain of, one of the entries. Subdomain match\n * is on a dot boundary so `example.com` matches `docs.example.com` but not\n * `notexample.com`.\n */\nexport function isHostAllowed(hostname: string, allowHosts: readonly string[] | undefined): boolean {\n if (!allowHosts || allowHosts.length === 0)\n return true\n const host = normalizeHost(hostname)\n for (const entry of allowHosts) {\n const allowed = normalizeHost(entry)\n if (allowed.length === 0)\n continue\n if (host === allowed || host.endsWith(`.${allowed}`))\n return true\n }\n return false\n}\n\n/**\n * Resolve `hostname` and refuse if any answer falls in a blocked range.\n *\n * Returns the first allowed `{ address, family }` so the caller can pin\n * the connection to it. Throws on any blocked answer so a multi-record\n * response with one private record fails closed.\n */\nasync function resolveAndCheck(hostname: string, allowHosts?: readonly string[]): Promise<{ address: string, family: 4 | 6 }> {\n // Egress allowlist (when configured) gates BEFORE DNS so a non-approved\n // host never even triggers a lookup. Enforced here so every redirect hop\n // is re-checked, not just the initial URL.\n if (!isHostAllowed(hostname, allowHosts))\n throw new Error(`refused: ${hostname} is not in the configured egress allowlist`)\n // `URL.hostname` keeps brackets around IPv6 literals (`[::1]`) — strip them\n // before the IP check so `isIP` recognises the literal and `dns.lookup`\n // doesn't try to resolve `[::1]` as a name.\n const bare = hostname.startsWith('[') && hostname.endsWith(']')\n ? hostname.slice(1, -1)\n : hostname\n const family = isIP(bare)\n if (family === 4 || family === 6) {\n if (isBlockedAddress(bare))\n throw new Error(`refused: ${bare} is in a blocked range`)\n return { address: bare, family }\n }\n const answers = await dns.lookup(bare, { all: true, verbatim: true })\n if (answers.length === 0)\n throw new Error(`DNS lookup returned no records for ${bare}`)\n for (const { address } of answers) {\n if (isBlockedAddress(address))\n throw new Error(`refused: ${bare} resolves to blocked address ${address}`)\n }\n const first = answers[0]!\n const fam = first.family === 6 ? 6 : 4\n return { address: first.address, family: fam }\n}\n\n/**\n * Pinned HTTP/HTTPS request. Connects to `pinnedIp` directly (bypassing\n * Node/Bun's own DNS resolution) while preserving the `Host:` header and\n * (for HTTPS) TLS SNI on the URL's original hostname. This is the\n * concrete defense against DNS rebinding — see the file-level docstring.\n *\n * Reads up to `maxBufferBytes` of body and then forcibly closes the\n * connection. The body is decoded as UTF-8; binary responses degrade to\n * mojibake but the tool's contract is text payloads anyway.\n */\ninterface PinnedResponse {\n status: number\n url: string\n contentType: string\n body: string\n location: string | null\n /**\n * True when the body was cut at `maxBufferBytes` before the server\n * finished sending. Optional so test seams that stub `requestImpl`\n * don't have to populate it; absent means \"not truncated\".\n */\n truncated?: boolean\n}\n\nfunction buildHostHeader(url: URL): string {\n if (!url.port)\n return url.hostname\n const defaultPort = url.protocol === 'https:' ? '443' : '80'\n return url.port === defaultPort ? url.hostname : `${url.hostname}:${url.port}`\n}\n\nexport function pinnedRequest(\n url: URL,\n pinnedIp: string,\n family: 4 | 6,\n headers: Record<string, string>,\n signal: AbortSignal,\n maxBufferBytes: number,\n): Promise<PinnedResponse> {\n return new Promise((resolve, reject) => {\n const isHttps = url.protocol === 'https:'\n const port = url.port\n ? Number.parseInt(url.port, 10)\n : (isHttps ? 443 : 80)\n\n // `host` is the literal IP, `servername` is the original hostname so\n // TLS cert verification still matches the cert's SAN/CN against the\n // user-visible name. Node uses `servername` for `checkServerIdentity`\n // automatically when set.\n const options: HttpRequestOptions & HttpsRequestOptions = {\n host: pinnedIp,\n port,\n path: `${url.pathname}${url.search}`,\n method: 'GET',\n family,\n headers: { ...headers, Host: buildHostHeader(url) },\n ...(isHttps ? { servername: url.hostname } : {}),\n }\n\n const request = isHttps ? httpsRequest : httpRequest\n const chunks: Buffer[] = []\n let received = 0\n // Single-shot settle guard. Bun's `node:http` is quirky around\n // `req.destroy(err)` — passing an error doesn't reliably surface as an\n // `error` event the way it does on Node. We track the settle state\n // ourselves and call `resolve` / `reject` directly from the abort /\n // timeout paths so the promise terminates even when the underlying\n // socket teardown is silent.\n let settled = false\n // Forward-declared so the `finish` / abort / timeout handlers can\n // close over `req` before it's assigned below. The request object is\n // wired into them via mutable refs because the handlers must be set\n // up *before* `request(options, callback)` fires its first event.\n let req: ReturnType<typeof httpRequest> | undefined\n let timer: ReturnType<typeof setTimeout> | undefined\n\n const teardown = (): void => {\n try { req?.destroy() }\n catch { /* tear-down best effort */ }\n }\n\n const finish = (settler: () => void): void => {\n if (settled)\n return\n settled = true\n if (timer)\n clearTimeout(timer)\n signal.removeEventListener('abort', onSignalAbort)\n settler()\n }\n\n function onSignalAbort(): void {\n finish(() => reject(new Error('request aborted')))\n teardown()\n }\n\n // Pre-aborted signal — short-circuit so we don't even open a socket.\n // (This is the realistic shape when a user hits Ctrl+C while the agent\n // is already shutting down: the signal is `.aborted` by the time the\n // tool function runs.)\n if (signal.aborted) {\n reject(new Error('request aborted'))\n return\n }\n\n timer = setTimeout(() => {\n finish(() => reject(new Error(`request timed out after ${HTTP_TIMEOUT_MS}ms`)))\n teardown()\n }, HTTP_TIMEOUT_MS)\n\n signal.addEventListener('abort', onSignalAbort, { once: true })\n\n req = request(options, (res) => {\n const status = res.statusCode ?? 0\n const headersOut = res.headers\n const contentType = (headersOut['content-type'] ?? '').toString().toLowerCase()\n const location = typeof headersOut.location === 'string' ? headersOut.location : null\n\n // Short-circuit on redirect responses — body is irrelevant.\n if (status >= 300 && status < 400 && location) {\n res.resume() // drain so the socket can be released\n finish(() => resolve({ status, url: url.toString(), contentType, body: '', location }))\n return\n }\n\n let bodyTruncated = false\n res.on('data', (chunk: Buffer) => {\n if (received >= maxBufferBytes) {\n // Stop accumulating; tear the socket down so the server stops\n // sending. We still resolve cleanly from `end` (or `close` if\n // the server doesn't finish flushing before the kill lands).\n bodyTruncated = true\n teardown()\n return\n }\n // Keep only what fits in the budget — a chunk straddling the cap\n // would otherwise overshoot it by up to one chunk. A partial slice\n // means the body was cut, so flag it and stop the transfer.\n const room = maxBufferBytes - received\n if (chunk.length > room) {\n chunks.push(chunk.subarray(0, room))\n received += room\n bodyTruncated = true\n teardown()\n return\n }\n received += chunk.length\n chunks.push(chunk)\n })\n res.on('end', () => {\n const body = Buffer.concat(chunks).toString('utf-8')\n finish(() => resolve({ status, url: url.toString(), contentType, body, location: null, truncated: bodyTruncated }))\n })\n res.on('close', () => {\n // Socket torn down before `end` (e.g. when our maxBufferBytes\n // trigger destroyed the request). Resolve with whatever we\n // buffered so far — `truncated` tells the caller the body is cut.\n if (!settled) {\n const body = Buffer.concat(chunks).toString('utf-8')\n finish(() => resolve({ status, url: url.toString(), contentType, body, location: null, truncated: bodyTruncated }))\n }\n })\n res.on('error', err => finish(() => reject(err)))\n })\n\n req.on('error', (err: Error) => finish(() => reject(err)))\n req.end()\n })\n}\n\n/**\n * Walk up to {@link MAX_REDIRECTS} hops, validating the target host of each\n * 3xx response against the SSRF blocklist before following.\n *\n * `deps` is an internal seam for tests — production callers use the\n * defaults. Both knobs are intentionally opaque: hosts that want to\n * customize the blocklist should use a higher-level mechanism (a future\n * `behavior.fetchUrlAllowHosts` setting) rather than reaching into this.\n */\nexport interface FetchSsrfDeps {\n /** Resolve + validate a hostname. Defaults to {@link resolveAndCheck}. */\n resolver?: (hostname: string) => Promise<{ address: string, family: 4 | 6 }>\n /** Execute a single pinned HTTP request. Defaults to {@link pinnedRequest}. */\n requestImpl?: typeof pinnedRequest\n}\n\nexport async function fetchWithSsrfGuard(\n startUrl: URL,\n headers: Record<string, string>,\n signal: AbortSignal,\n maxBufferBytes: number,\n deps: FetchSsrfDeps = {},\n allowHosts?: readonly string[],\n): Promise<PinnedResponse> {\n // Default resolver binds the egress allowlist; a test-injected resolver\n // owns its own policy.\n const resolver = deps.resolver ?? ((hostname: string) => resolveAndCheck(hostname, allowHosts))\n const requestImpl = deps.requestImpl ?? pinnedRequest\n let current = startUrl\n for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {\n const { address, family } = await resolver(current.hostname)\n const res = await requestImpl(current, address, family, headers, signal, maxBufferBytes)\n if (!res.location)\n return res\n if (hop === MAX_REDIRECTS)\n throw new Error(`too many redirects (>${MAX_REDIRECTS})`)\n let next: URL\n try {\n next = new URL(res.location, current)\n }\n catch {\n throw new Error(`invalid redirect target: ${res.location}`)\n }\n if (next.protocol !== 'http:' && next.protocol !== 'https:')\n throw new Error(`refused redirect to non-http(s) target: ${next.protocol}`)\n current = next\n }\n throw new Error('redirect loop exited unexpectedly')\n}\n\n/**\n * Opt-in, process-local response cache for `fetch_url`. Disabled unless\n * `behavior.fetchUrlCacheTtlMs` is set (> 0). Bounded by entry count and total\n * cached bytes; eviction is oldest-first (insertion order via `Map`, which is\n * a good-enough LRU because we delete-then-set on hit to refresh recency).\n *\n * Keyed on `<url>\\u0000<cap>\\u0000<egress-policy>` so two calls with different\n * `max_bytes` (hence different truncation) don't alias, and — because the\n * cache is module-global — an agent with a permissive `fetchUrlAllowHosts`\n * can't populate entries that a co-resident agent with a stricter allowlist\n * would then be served. Only successful text responses are stored — the\n * caller gates on status before writing.\n */\nconst FETCH_CACHE_MAX_ENTRIES = 64\nconst FETCH_CACHE_MAX_BYTES = 16 * 1024 * 1024 // 16 MiB total\n\ninterface FetchCacheEntry {\n /** Fully-formatted tool output (header + body) ready to return verbatim. */\n output: string\n expiresAt: number\n bytes: number\n}\n\nconst fetchCache = new Map<string, FetchCacheEntry>()\nlet fetchCacheBytes = 0\n\nfunction cacheKey(url: string, cap: number, allowHosts?: readonly string[]): string {\n // Normalize + sort so equivalent policies (`['A.com', 'b.com']` vs\n // `['b.com', 'a.com.']`) share entries; an absent/empty allowlist keys\n // as the empty policy.\n const policy = (allowHosts ?? []).map(normalizeHost).sort().join(',')\n return `${url}\\u0000${cap}\\u0000${policy}`\n}\n\nfunction cacheGet(key: string): string | null {\n const entry = fetchCache.get(key)\n if (!entry)\n return null\n if (Date.now() >= entry.expiresAt) {\n fetchCache.delete(key)\n fetchCacheBytes -= entry.bytes\n return null\n }\n // Refresh recency: re-insert at the tail of the Map's iteration order.\n fetchCache.delete(key)\n fetchCache.set(key, entry)\n return entry.output\n}\n\nfunction cacheSet(key: string, output: string, ttlMs: number): void {\n const bytes = Buffer.byteLength(output, 'utf-8')\n // A single oversize payload that can't fit under the byte cap is simply not\n // cached (still returned to the caller) rather than evicting everything.\n if (bytes > FETCH_CACHE_MAX_BYTES)\n return\n // Drop any stale entry for this key first so the byte accounting stays exact.\n const prev = fetchCache.get(key)\n if (prev) {\n fetchCache.delete(key)\n fetchCacheBytes -= prev.bytes\n }\n fetchCache.set(key, { output, expiresAt: Date.now() + ttlMs, bytes })\n fetchCacheBytes += bytes\n // Evict oldest-first until both caps are satisfied.\n while (fetchCache.size > FETCH_CACHE_MAX_ENTRIES || fetchCacheBytes > FETCH_CACHE_MAX_BYTES) {\n const oldest = fetchCache.keys().next().value\n if (oldest === undefined)\n break\n const victim = fetchCache.get(oldest)!\n fetchCache.delete(oldest)\n fetchCacheBytes -= victim.bytes\n }\n}\n\n/** Test seam — drop all cached entries. */\nexport function clearFetchUrlCache(): void {\n fetchCache.clear()\n fetchCacheBytes = 0\n}\n\n/**\n * Test seam — exercise the cache get/set/eviction in isolation without\n * standing up the full SSRF + HTTP path. Not part of the public tool surface;\n * `execute` uses the module-private functions directly.\n */\nexport const __fetchCacheTestApi = {\n key: cacheKey,\n get: cacheGet,\n set: cacheSet,\n size: () => fetchCache.size,\n bytes: () => fetchCacheBytes,\n}\n\nexport const fetchUrl: ToolDef = {\n isConcurrencySafe: true,\n spec: {\n name: 'fetch_url',\n description: 'Fetch a public URL and return its body as plain text. HTML is reduced to text (scripts, styles, tags stripped; entities decoded). If a `web_search` tool is also available, use it first when you do not already know the exact URL. Only http(s) URLs are accepted; loopback, link-local, private, and cloud-metadata addresses are refused. Output is capped (default 200 KiB).',\n inputSchema: {\n type: 'object',\n properties: {\n url: {\n type: 'string',\n description: 'HTTP or HTTPS URL to fetch.',\n },\n max_bytes: {\n type: 'number',\n description: `Truncate the response body beyond this many bytes. Default: ${DEFAULT_MAX_BYTES}. Hard cap: ${HARD_MAX_BYTES}.`,\n },\n },\n required: ['url'],\n },\n },\n async execute({ url, max_bytes }, ctx: ToolContext) {\n const raw = typeof url === 'string' ? url.trim() : ''\n if (!raw)\n return 'fetch_url error: `url` is required'\n let parsed: URL\n try {\n parsed = new URL(raw)\n }\n catch {\n return `fetch_url error: invalid URL: ${raw}`\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:')\n return `fetch_url error: only http(s) URLs are allowed (got ${parsed.protocol})`\n\n const cap = Math.min(\n typeof max_bytes === 'number' && max_bytes > 0 ? Math.floor(max_bytes) : DEFAULT_MAX_BYTES,\n HARD_MAX_BYTES,\n )\n // Buffer up to 2× the cap so HTML overhead doesn't starve the visible\n // text budget — a 200 KiB cap on rendered text can legitimately need to\n // read ~400 KiB of raw HTML before stripping. Hard ceiling is still\n // governed by `HARD_MAX_BYTES * 2` which is comfortably below OOM.\n const bufferCap = Math.min(cap * 2, HARD_MAX_BYTES * 2)\n\n // Opt-in response cache (off unless `behavior.fetchUrlCacheTtlMs > 0`).\n // The egress allowlist is part of the key AND re-checked before serving\n // a hit — the cache is module-global, so neither a policy change within\n // an agent nor a co-resident agent's entries may bypass this agent's\n // allowlist.\n const allowHosts = ctx.behavior?.fetchUrlAllowHosts\n const ttlMs = ctx.behavior?.fetchUrlCacheTtlMs\n const cacheEnabled = typeof ttlMs === 'number' && ttlMs > 0\n const key = cacheKey(parsed.toString(), cap, allowHosts)\n if (cacheEnabled && isHostAllowed(parsed.hostname, allowHosts)) {\n const hit = cacheGet(key)\n if (hit !== null)\n return hit\n }\n\n try {\n const res = await fetchWithSsrfGuard(\n parsed,\n {\n 'user-agent': 'Mozilla/5.0 (compatible; zidane/1.0)',\n 'accept': 'text/html,text/plain,application/json;q=0.9,*/*;q=0.5',\n 'accept-encoding': 'identity', // no gzip — we don't decompress\n },\n ctx.signal,\n bufferCap,\n {},\n allowHosts,\n )\n const body = res.body\n const isHtml = res.contentType.includes('html') || /^\\s*<!doctype html|^\\s*<html/i.test(body)\n const text = isHtml ? stripHtmlBlock(body) : body\n const truncated = text.length > cap\n // Two distinct truncation reasons: the rendered text overflowing `cap`,\n // and the raw transfer being cut at the buffer ceiling (`res.truncated`)\n // — the latter can leave the rendered text under `cap` (HTML overhead\n // stripped away), so it needs its own marker or the model would treat\n // a partial body as complete.\n const out = truncated\n ? `${text.slice(0, cap)}\\n\\n[truncated at ${cap} bytes; full length ${text.length}]`\n : res.truncated\n ? `${text}\\n\\n[response truncated: body exceeded the ${bufferCap}-byte transfer buffer]`\n : text\n // `res.url` reflects the FINAL hop after redirects; flag a cross-host\n // landing so the model knows the content came from a different origin\n // than it asked for (open-redirect awareness). Same-host path changes\n // and www add/strip are treated as the same site and not flagged.\n const finalHost = sameSiteHost(res.url)\n const requestedHost = sameSiteHost(parsed.toString())\n const redirectNote = finalHost && requestedHost && finalHost !== requestedHost\n ? `Note: ${parsed.hostname} redirected to a different host (${new URL(res.url).hostname}).\\n`\n : ''\n const header = `URL: ${res.url}\\nStatus: ${res.status}\\nContent-Type: ${res.contentType || '(none)'}\\n${redirectNote}\\n`\n const formatted = header + out\n // Cache only successful, complete text responses — never errors /\n // redirects / transfer-truncated bodies (a retry may get the rest).\n if (cacheEnabled && res.status >= 200 && res.status < 300 && res.truncated !== true)\n cacheSet(key, formatted, ttlMs)\n return formatted\n }\n catch (err) {\n return `fetch_url error: ${errorMessage(err)}`\n }\n },\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { $n as HeadlessResult, Jn as FormattedHeadlessTurnEvent, Qn as HeadlessOutputFormat, Xn as HeadlessEvent, Yn as HeadlessErrorInfo, Zn as HeadlessOptions, ar as exitCodeForHeadlessResult, cr as formattedHeadlessTurnEventToJsonl, dr as providerTranscriptFormatForProvider, er as HeadlessStatus, fr as runHeadless, ir as ProviderTranscriptFormat, lr as headlessEventToJsonl, mr as transcriptToProviderMessages, nr as OpenAIChatContentPart, or as formatHeadlessResult, pr as transcriptToOpenAIMessages, qn as FormattedHeadlessResult, rr as OpenAIChatMessage, sr as formatHeadlessTurnEvent, tr as HeadlessUsage, ur as installHeadlessEventAdapter } from "./index-1Dr4Yqw1.js";
1
+ import { $n as HeadlessResult, Jn as FormattedHeadlessTurnEvent, Qn as HeadlessOutputFormat, Xn as HeadlessEvent, Yn as HeadlessErrorInfo, Zn as HeadlessOptions, ar as exitCodeForHeadlessResult, cr as formattedHeadlessTurnEventToJsonl, dr as providerTranscriptFormatForProvider, er as HeadlessStatus, fr as runHeadless, ir as ProviderTranscriptFormat, lr as headlessEventToJsonl, mr as transcriptToProviderMessages, nr as OpenAIChatContentPart, or as formatHeadlessResult, pr as transcriptToOpenAIMessages, qn as FormattedHeadlessResult, rr as OpenAIChatMessage, sr as formatHeadlessTurnEvent, tr as HeadlessUsage, ur as installHeadlessEventAdapter } from "./index-Gy9wi80M.js";
2
2
  export { FormattedHeadlessResult, FormattedHeadlessTurnEvent, HeadlessErrorInfo, HeadlessEvent, HeadlessOptions, HeadlessOutputFormat, HeadlessResult, HeadlessStatus, HeadlessUsage, OpenAIChatContentPart, OpenAIChatMessage, ProviderTranscriptFormat, exitCodeForHeadlessResult, formatHeadlessResult, formatHeadlessTurnEvent, formattedHeadlessTurnEventToJsonl, headlessEventToJsonl, installHeadlessEventAdapter, providerTranscriptFormatForProvider, runHeadless, transcriptToOpenAIMessages, transcriptToProviderMessages };
package/dist/headless.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { a as isWireTurn, i as documentBlockMarker, l as toolResultToText, n as assertResolvedMediaBlock } from "./types-BIarq1qE.js";
2
- import { ht as basic_default, t as createAgent } from "./agent-COHX5SpM.js";
2
+ import { ht as basic_default, t as createAgent } from "./agent-BMJKrD84.js";
3
3
  import { r as createProcessContext } from "./contexts-DWVt7MvF.js";
4
4
  import { t as audioFormatFromMediaType } from "./media-sniff-UKijEaiQ.js";
5
- import { c as ensureToolResultPairing, g as toAnthropic } from "./messages-DIxD2UCr.js";
6
- import { d as createMemoryStore, t as createSession } from "./session-DY2LWai4.js";
5
+ import { c as ensureToolResultPairing, g as toAnthropic } from "./messages-D1EryrDs.js";
6
+ import { d as createMemoryStore, t as createSession } from "./session-B40flcj7.js";
7
7
  import { t as createRunSummaryCollector } from "./run-summary-BU_NgwUT.js";
8
8
  //#region src/headless.ts
9
9
  function exitCodeForHeadlessResult(result) {