zidane 5.8.2 → 5.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/{agent-acjWZ_4E.d.ts → agent-CL4nT5Ti.d.ts} +145 -10
  2. package/dist/agent-CL4nT5Ti.d.ts.map +1 -0
  3. package/dist/chat/pure.d.ts +3 -3
  4. package/dist/chat.d.ts +6 -6
  5. package/dist/chat.js +2 -2
  6. package/dist/{errors-CoQnKRf1.js → errors-B-GeaKTX.js} +24 -2
  7. package/dist/{errors-CoQnKRf1.js.map → errors-B-GeaKTX.js.map} +1 -1
  8. package/dist/{fetch-url-CPxfiXDa.js → fetch-url-D0M3oft5.js} +2 -2
  9. package/dist/{fetch-url-CPxfiXDa.js.map → fetch-url-D0M3oft5.js.map} +1 -1
  10. package/dist/{headless-CJFFU6DI.js → headless-AnwtKahq.js} +54 -32
  11. package/dist/headless-AnwtKahq.js.map +1 -0
  12. package/dist/headless.d.ts +1 -1
  13. package/dist/headless.js +1 -1
  14. package/dist/{index-zy4OtFSv.d.ts → index-BDMVtgHD.d.ts} +6 -2
  15. package/dist/index-BDMVtgHD.d.ts.map +1 -0
  16. package/dist/{index-Cgr_mbMJ.d.ts → index-DtLfTUXt.d.ts} +2 -2
  17. package/dist/{index-Cgr_mbMJ.d.ts.map → index-DtLfTUXt.d.ts.map} +1 -1
  18. package/dist/index.d.ts +4 -4
  19. package/dist/index.js +10 -10
  20. package/dist/{interpolate-TySiqKzc.js → interpolate-CmcrnzDZ.js} +2 -2
  21. package/dist/{interpolate-TySiqKzc.js.map → interpolate-CmcrnzDZ.js.map} +1 -1
  22. package/dist/{login-BjY_sBdn.js → login-9b_Q2DVg.js} +4 -4
  23. package/dist/{login-BjY_sBdn.js.map → login-9b_Q2DVg.js.map} +1 -1
  24. package/dist/{mcp-Br3b1Xm3.js → mcp-Bp4tWsdM.js} +2 -2
  25. package/dist/{mcp-Br3b1Xm3.js.map → mcp-Bp4tWsdM.js.map} +1 -1
  26. package/dist/mcp.d.ts +1 -1
  27. package/dist/mcp.js +1 -1
  28. package/dist/{messages-CvRQTdbR.js → messages-Dhva-Ewy.js} +7 -2
  29. package/dist/messages-Dhva-Ewy.js.map +1 -0
  30. package/dist/{presets-BmsTNxjR.js → presets-J9EyUhvT.js} +2 -2
  31. package/dist/{presets-BmsTNxjR.js.map → presets-J9EyUhvT.js.map} +1 -1
  32. package/dist/presets.d.ts +2 -2
  33. package/dist/presets.js +1 -1
  34. package/dist/{providers-h4HJPbbv.js → providers-ByITfqRA.js} +119 -95
  35. package/dist/providers-ByITfqRA.js.map +1 -0
  36. package/dist/providers.d.ts +1 -1
  37. package/dist/providers.js +2 -2
  38. package/dist/restate.d.ts +1 -1
  39. package/dist/session/sqlite.d.ts +1 -1
  40. package/dist/session/sqlite.js +1 -1
  41. package/dist/{session-BzLou2_-.js → session-7CKYn9qT.js} +2 -2
  42. package/dist/{session-BzLou2_-.js.map → session-7CKYn9qT.js.map} +1 -1
  43. package/dist/session.d.ts +1 -1
  44. package/dist/session.js +2 -2
  45. package/dist/skills.d.ts +2 -2
  46. package/dist/skills.js +1 -1
  47. package/dist/{tool-formatters-B5UNV_sy.d.ts → tool-formatters-D-aWpu2N.d.ts} +2 -2
  48. package/dist/{tool-formatters-B5UNV_sy.d.ts.map → tool-formatters-D-aWpu2N.d.ts.map} +1 -1
  49. package/dist/tools/fetch-url.d.ts +1 -1
  50. package/dist/tools/fetch-url.js +1 -1
  51. package/dist/tools/web-search.d.ts +1 -1
  52. package/dist/tools/web-search.js +2 -2
  53. package/dist/{tools-BzQtic6M.js → tools-DCFiAUel.js} +99 -39
  54. package/dist/tools-DCFiAUel.js.map +1 -0
  55. package/dist/tools.d.ts +2 -2
  56. package/dist/tools.js +1 -1
  57. package/dist/{transcript-anchors-C571npbs.js → transcript-anchors-D-X067Sc.js} +9 -9
  58. package/dist/{transcript-anchors-C571npbs.js.map → transcript-anchors-D-X067Sc.js.map} +1 -1
  59. package/dist/{transcript-anchors-Dtz6U4GW.d.ts → transcript-anchors-DYsnGyel.d.ts} +4 -4
  60. package/dist/{transcript-anchors-Dtz6U4GW.d.ts.map → transcript-anchors-DYsnGyel.d.ts.map} +1 -1
  61. package/dist/tui.d.ts +3 -3
  62. package/dist/tui.js +7 -7
  63. package/dist/{turn-operations-CqJAEzoe.d.ts → turn-operations-D-fypW6K.d.ts} +3 -3
  64. package/dist/{turn-operations-CqJAEzoe.d.ts.map → turn-operations-D-fypW6K.d.ts.map} +1 -1
  65. package/dist/types-BPw_i5vb.js.map +1 -1
  66. package/dist/types.d.ts +3 -3
  67. package/dist/types.js +1 -1
  68. package/package.json +1 -1
  69. package/dist/agent-acjWZ_4E.d.ts.map +0 -1
  70. package/dist/headless-CJFFU6DI.js.map +0 -1
  71. package/dist/index-zy4OtFSv.d.ts.map +0 -1
  72. package/dist/messages-CvRQTdbR.js.map +0 -1
  73. package/dist/providers-h4HJPbbv.js.map +0 -1
  74. package/dist/tools-BzQtic6M.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"fetch-url-CPxfiXDa.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\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 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 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 }))\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 — the caller will treat it as truncated text.\n if (!settled) {\n const body = Buffer.concat(chunks).toString('utf-8')\n finish(() => resolve({ status, url: url.toString(), contentType, body, location: null }))\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>` so two calls with different `max_bytes` (hence\n * different truncation) don't alias. Only successful text responses are stored\n * — the 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): string {\n return `${url}\\u0000${cap}`\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 to find the 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 const ttlMs = ctx.behavior?.fetchUrlCacheTtlMs\n const cacheEnabled = typeof ttlMs === 'number' && ttlMs > 0\n const key = cacheKey(parsed.toString(), cap)\n if (cacheEnabled) {\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 ctx.behavior?.fetchUrlAllowHosts,\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 const out = truncated ? `${text.slice(0, cap)}\\n\\n[truncated at ${cap} bytes; full length ${text.length}]` : 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 text responses — never errors / redirects.\n if (cacheEnabled && res.status >= 200 && res.status < 300)\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-D0M3oft5.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\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 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 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 }))\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 — the caller will treat it as truncated text.\n if (!settled) {\n const body = Buffer.concat(chunks).toString('utf-8')\n finish(() => resolve({ status, url: url.toString(), contentType, body, location: null }))\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>` so two calls with different `max_bytes` (hence\n * different truncation) don't alias. Only successful text responses are stored\n * — the 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): string {\n return `${url}\\u0000${cap}`\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 to find the 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 const ttlMs = ctx.behavior?.fetchUrlCacheTtlMs\n const cacheEnabled = typeof ttlMs === 'number' && ttlMs > 0\n const key = cacheKey(parsed.toString(), cap)\n if (cacheEnabled) {\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 ctx.behavior?.fetchUrlAllowHosts,\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 const out = truncated ? `${text.slice(0, cap)}\\n\\n[truncated at ${cap} bytes; full length ${text.length}]` : 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 text responses — never errors / redirects.\n if (cacheEnabled && res.status >= 200 && res.status < 300)\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,9 +1,10 @@
1
- import { d as createAgent } from "./tools-BzQtic6M.js";
1
+ import { d as createAgent } from "./tools-DCFiAUel.js";
2
+ import { s as ensureToolResultPairing } from "./messages-Dhva-Ewy.js";
2
3
  import { n as createProcessContext } from "./contexts-BD2U_xpi.js";
3
4
  import { r as toolResultToText } from "./types-BPw_i5vb.js";
4
5
  import { i as statsByModel } from "./stats-DAKBEKjc.js";
5
- import { i as basic_default } from "./presets-BmsTNxjR.js";
6
- import { i as createMemoryStore, t as createSession } from "./session-BzLou2_-.js";
6
+ import { i as basic_default } from "./presets-J9EyUhvT.js";
7
+ import { i as createMemoryStore, t as createSession } from "./session-7CKYn9qT.js";
7
8
  //#region src/run-summary.ts
8
9
  /**
9
10
  * Build a run-summary collector. State is created fresh inside each
@@ -335,7 +336,7 @@ async function runHeadless(opts) {
335
336
  turns: stats?.turns ?? 0,
336
337
  durationMs: stats?.elapsed ?? Date.now() - startedAt,
337
338
  numToolCalls: countToolCalls(rawTranscript),
338
- ...lastFinishReason(stats) ? { finishReason: lastFinishReason(stats) } : {},
339
+ ...status !== "aborted" && status !== "timeout" && lastFinishReason(stats) ? { finishReason: lastFinishReason(stats) } : {},
339
340
  ...error ? { error } : {},
340
341
  sessionId: session.id,
341
342
  ...summary ? { summary } : {},
@@ -353,47 +354,68 @@ async function runHeadless(opts) {
353
354
  * `role: 'tool'` message. This is the drop-in shape for an SFT renderer —
354
355
  * unlike `toOpenAI` (session/messages.ts), which emits an internal `_tag`
355
356
  * envelope meant for re-sending to a provider, not for training data.
357
+ *
358
+ * Fails closed on corrupt raw turns instead of fabricating tool results; silent
359
+ * placeholders would create structurally-valid but semantically-poisoned SFT
360
+ * examples.
356
361
  */
357
362
  function transcriptToOpenAIMessages(turns) {
358
363
  const messages = [];
364
+ let chunk = [];
365
+ const flushChunk = () => {
366
+ if (chunk.length === 0) return;
367
+ const repairs = [];
368
+ const paired = ensureToolResultPairing(chunk, { onRepair: (repair) => repairs.push(repair) });
369
+ if (repairs.length > 0) throw new Error(`Cannot convert transcript to OpenAI messages: tool pairing repair required (${repairs.map((r) => r.mode).join(", ")})`);
370
+ for (const msg of paired) pushOpenAIChatMessage(messages, msg);
371
+ chunk = [];
372
+ };
359
373
  for (const turn of turns) {
360
- const text = textOf(turn.content);
361
374
  if (turn.role === "system") {
375
+ flushChunk();
362
376
  messages.push({
363
377
  role: "system",
364
- content: text
378
+ content: textOf(turn.content)
365
379
  });
366
380
  continue;
367
381
  }
368
- if (turn.role === "assistant") {
369
- const toolCalls = turn.content.filter((b) => b.type === "tool_call");
370
- const msg = {
371
- role: "assistant",
372
- content: text || null
373
- };
374
- if (toolCalls.length > 0) msg.tool_calls = toolCalls.map((b) => ({
375
- id: b.id,
376
- type: "function",
377
- function: {
378
- name: b.name,
379
- arguments: JSON.stringify(b.input)
380
- }
381
- }));
382
- messages.push(msg);
383
- continue;
384
- }
385
- if (text) messages.push({
386
- role: "user",
387
- content: text
388
- });
389
- for (const tr of turn.content.filter((b) => b.type === "tool_result")) messages.push({
390
- role: "tool",
391
- tool_call_id: tr.callId,
392
- content: toolResultToText(tr.output)
382
+ chunk.push({
383
+ role: turn.role,
384
+ content: turn.content
393
385
  });
394
386
  }
387
+ flushChunk();
395
388
  return messages;
396
389
  }
390
+ function pushOpenAIChatMessage(messages, msg) {
391
+ const text = textOf(msg.content);
392
+ if (msg.role === "assistant") {
393
+ const toolCalls = msg.content.filter((b) => b.type === "tool_call");
394
+ const out = {
395
+ role: "assistant",
396
+ content: text || null
397
+ };
398
+ if (toolCalls.length > 0) out.tool_calls = toolCalls.map((b) => ({
399
+ id: b.id,
400
+ type: "function",
401
+ function: {
402
+ name: b.name,
403
+ arguments: JSON.stringify(b.input)
404
+ }
405
+ }));
406
+ messages.push(out);
407
+ return;
408
+ }
409
+ if (text) messages.push({
410
+ role: "user",
411
+ content: text
412
+ });
413
+ for (const tr of msg.content.filter((b) => b.type === "tool_result")) messages.push({
414
+ role: "tool",
415
+ tool_call_id: tr.callId,
416
+ content: toolResultToText(tr.output)
417
+ });
418
+ }
397
419
  function noop() {}
398
420
  function textOf(content) {
399
421
  return content.filter((b) => b.type === "text").map((b) => b.text).join("");
@@ -499,4 +521,4 @@ function installEventAdapter(hooks, onEvent) {
499
521
  //#endregion
500
522
  export { createRunSummaryCollector as i, runHeadless as n, transcriptToOpenAIMessages as r, headlessEventToJsonl as t };
501
523
 
502
- //# sourceMappingURL=headless-CJFFU6DI.js.map
524
+ //# sourceMappingURL=headless-AnwtKahq.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless-AnwtKahq.js","names":["basic"],"sources":["../src/run-summary.ts","../src/headless.ts"],"sourcesContent":["/**\n * Run summary collector — one JSON postmortem per `agent.run()`.\n *\n * `AgentStats` is great for billing and per-turn accounting but doesn't\n * carry a record of the *interesting* events that happened during a run\n * (errors, gate blocks, validation rejects, budget hits, MCP failures).\n * Reconstructing that from a hook stream after the fact is exactly the\n * kind of plumbing every consumer ends up re-implementing.\n *\n * This module ships:\n *\n * - {@link RunSummary} — a serializable shape that bundles totals,\n * per-model breakdown, and all the per-run incident lists.\n * - {@link createRunSummaryCollector} — installs hook listeners that\n * build up a {@link RunSummary} during the run and surfaces it on\n * `agent:done`. Calls an optional `onSummary` callback so the host can\n * forward to a log aggregator / DB / postmortem dashboard without\n * touching `agent.run()`'s return value.\n *\n * The collector is purely additive — it doesn't touch the agent loop,\n * doesn't change return shapes, and doesn't suppress any other hook\n * handlers. Drop it in alongside tracing / metrics / logging or use it\n * standalone when you only need the summary.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from './agent'\nimport type { AgentStats } from './types'\nimport { statsByModel } from './stats'\n\n// ---------------------------------------------------------------------------\n// Public shape\n// ---------------------------------------------------------------------------\n\nexport interface RunSummaryTokens {\n input: number\n output: number\n cacheRead: number\n cacheCreation: number\n cost?: number\n /** First observable byte from the provider, ms from run start. */\n ttftMs?: number\n}\n\nexport interface RunSummaryByModel {\n modelId: string\n input: number\n output: number\n cacheRead: number\n cacheCreation: number\n cost: number\n turns: number\n}\n\nexport interface RunSummaryError {\n kind: 'stream' | 'tool' | 'mcp-tool' | 'mcp' | 'spawn'\n message: string\n errorType?: string\n turnId?: string\n callId?: string\n server?: string\n toolName?: string\n childId?: string\n statusCode?: number\n requestId?: string\n}\n\nexport interface RunSummaryBlock {\n callId: string\n toolName: string\n outcome: 'gate-block' | 'unknown' | 'invalid-input'\n reason?: string\n}\n\nexport interface RunSummaryValidation {\n callId: string\n toolName: string\n reason: string\n}\n\nexport interface RunSummaryBudget {\n kind: 'bytes' | 'tool-count'\n /** Tool name (for `'tool-count'`); absent for byte budgets. */\n toolName?: string\n /** `mode` for `'tool-count'`; absent for byte budgets. */\n mode?: 'steer' | 'block'\n observed: number\n limit: number\n turnId?: string\n}\n\nexport interface RunSummaryRepeatGuard {\n toolName: string\n /** Consecutive identical calls including the one that tripped the guard. */\n count: number\n threshold: number\n action: 'block' | 'abort'\n turnId?: string\n}\n\n/**\n * Postmortem snapshot of one `agent.run()`. Strictly serializable — every\n * field round-trips through `JSON.stringify` / `JSON.parse` without loss\n * so a log aggregator can ingest it as-is.\n */\nexport interface RunSummary {\n runId?: string\n parentRunId?: string\n depth: number\n agentName?: string\n startedAt: number\n endedAt: number\n durationMs: number\n status: 'completed' | 'aborted'\n turns: number\n totals: RunSummaryTokens\n byModel: RunSummaryByModel[]\n errors: RunSummaryError[]\n blocks: RunSummaryBlock[]\n validationRejects: RunSummaryValidation[]\n budgetEvents: RunSummaryBudget[]\n /**\n * Consecutive-identical repeat-guard escalations. An `action: 'abort'`\n * entry means the guard terminated the run via the agent's\n * `AbortController` (the run finalizes as `'aborted'`).\n */\n repeatGuardEvents: RunSummaryRepeatGuard[]\n /** Counts of pairing repairs, keyed by repair mode. */\n pairingRepairs: Record<string, number>\n /**\n * Postmortem snapshots of child runs that bubbled their stats up via\n * `spawn:complete`. Only present when the run actually spawned.\n */\n children?: RunSummary[]\n}\n\n// ---------------------------------------------------------------------------\n// Collector\n// ---------------------------------------------------------------------------\n\nexport interface RunSummaryCollectorOptions {\n /**\n * Called with the assembled {@link RunSummary} on every `agent:done`.\n * Synchronous — heavy I/O should be deferred (e.g. via `setImmediate`).\n */\n onSummary?: (summary: RunSummary) => void\n}\n\nexport interface RunSummaryCollector {\n /** Install the collector's hook handlers. Returns an uninstall fn. */\n install: (hooks: Hookable<AgentHooks>) => () => void\n /** Most-recent summary; `undefined` until the first `agent:done` fires. */\n latest: () => RunSummary | undefined\n}\n\n/**\n * Build a run-summary collector. State is created fresh inside each\n * `install()` call, so a single collector instance can be installed\n * across multiple agents without attribution cross-talk. `latest()`\n * returns the most-recent summary across **any** install — install\n * per-agent collectors if you need separate post-run snapshots.\n *\n * @example\n * ```ts\n * const collector = createRunSummaryCollector({\n * onSummary: s => console.log(JSON.stringify(s)),\n * })\n * const uninstall = collector.install(agent.hooks)\n * try { await agent.run({ prompt }) }\n * finally { uninstall() }\n * ```\n */\nexport function createRunSummaryCollector(\n options: RunSummaryCollectorOptions = {},\n): RunSummaryCollector {\n let last: RunSummary | undefined\n\n return {\n latest: () => last,\n install(hooks: Hookable<AgentHooks>): () => void {\n // Per-run in-progress accumulators. The hookable bus serializes\n // agent.run lifecycles per agent — we reset between runs on\n // `agent:start` and consume on `agent:done`.\n let runId: string | undefined\n let parentRunId: string | undefined\n let depth = 0\n let agentName: string | undefined\n let startedAt = Date.now()\n let aborted = false\n const errors: RunSummaryError[] = []\n const blocks: RunSummaryBlock[] = []\n const validationRejects: RunSummaryValidation[] = []\n const budgetEvents: RunSummaryBudget[] = []\n const repeatGuardEvents: RunSummaryRepeatGuard[] = []\n const pairingRepairs: Record<string, number> = {}\n const children: RunSummary[] = []\n\n function resetForNewRun(): void {\n aborted = false\n errors.length = 0\n blocks.length = 0\n validationRejects.length = 0\n budgetEvents.length = 0\n repeatGuardEvents.length = 0\n for (const k of Object.keys(pairingRepairs))\n delete pairingRepairs[k]\n children.length = 0\n }\n\n const unregisters: Array<() => void> = []\n\n unregisters.push(hooks.hook('agent:start', (ctx) => {\n resetForNewRun()\n runId = ctx.runId\n parentRunId = ctx.parentRunId\n depth = ctx.depth\n agentName = ctx.agentName\n startedAt = ctx.startedAt\n }))\n\n unregisters.push(hooks.hook('agent:abort', () => {\n aborted = true\n }))\n\n unregisters.push(hooks.hook('stream:error', (ctx) => {\n const msg = ctx.err instanceof Error ? ctx.err.message : String(ctx.err)\n const errorType = ctx.err instanceof Error ? ctx.err.name : 'unknown'\n errors.push({\n kind: 'stream',\n message: msg,\n errorType,\n turnId: ctx.turnId,\n ...(ctx.statusCode !== undefined ? { statusCode: ctx.statusCode } : {}),\n ...(ctx.requestId !== undefined ? { requestId: ctx.requestId } : {}),\n })\n }))\n\n unregisters.push(hooks.hook('tool:error', (ctx) => {\n errors.push({\n kind: 'tool',\n message: ctx.error.message,\n errorType: ctx.error.name,\n turnId: ctx.turnId,\n callId: ctx.callId,\n toolName: ctx.name,\n })\n }))\n\n unregisters.push(hooks.hook('mcp:tool:error', (ctx) => {\n errors.push({\n kind: 'mcp-tool',\n message: ctx.error.message,\n errorType: ctx.error.name,\n turnId: ctx.turnId,\n callId: ctx.callId,\n server: ctx.server,\n toolName: ctx.displayName,\n })\n }))\n\n unregisters.push(hooks.hook('mcp:error', (ctx) => {\n errors.push({\n kind: 'mcp',\n message: ctx.error.message,\n errorType: ctx.error.name,\n server: ctx.name,\n })\n }))\n\n unregisters.push(hooks.hook('spawn:error', (ctx) => {\n errors.push({\n kind: 'spawn',\n message: ctx.error.message,\n errorType: ctx.error.name,\n childId: ctx.id,\n })\n }))\n\n unregisters.push(hooks.hook('tool:dispatched', (ctx) => {\n if (ctx.outcome === 'gate-block' || ctx.outcome === 'unknown' || ctx.outcome === 'invalid-input') {\n blocks.push({\n callId: ctx.callId,\n toolName: ctx.name,\n outcome: ctx.outcome,\n ...(ctx.reason ? { reason: ctx.reason } : {}),\n })\n }\n }))\n\n unregisters.push(hooks.hook('validation:reject', (ctx) => {\n validationRejects.push({\n callId: ctx.callId,\n toolName: ctx.name,\n reason: ctx.reason,\n })\n }))\n\n unregisters.push(hooks.hook('budget:exceeded', (ctx) => {\n budgetEvents.push({\n kind: 'bytes',\n observed: ctx.bytes,\n limit: ctx.budget,\n turnId: ctx.turnId,\n })\n }))\n\n unregisters.push(hooks.hook('tool-budget:exceeded', (ctx) => {\n budgetEvents.push({\n kind: 'tool-count',\n toolName: ctx.tool,\n mode: ctx.mode,\n observed: ctx.count,\n limit: ctx.max,\n turnId: ctx.turnId,\n })\n }))\n\n unregisters.push(hooks.hook('repeat-guard:exceeded', (ctx) => {\n repeatGuardEvents.push({\n toolName: ctx.tool,\n count: ctx.count,\n threshold: ctx.threshold,\n action: ctx.action,\n turnId: ctx.turnId,\n })\n }))\n\n unregisters.push(hooks.hook('pairing:repair', (ctx) => {\n pairingRepairs[ctx.mode] = (pairingRepairs[ctx.mode] ?? 0) + 1\n }))\n\n unregisters.push(hooks.hook('agent:done', (stats) => {\n const endedAt = Date.now()\n\n // Build per-model rollup via the existing `statsByModel` helper\n // so we stay in lockstep with how the rest of the harness\n // attributes cost and tokens by model id.\n const byModel: RunSummaryByModel[] = []\n for (const [modelId, usage] of statsByModel(stats)) {\n byModel.push({\n modelId,\n input: usage.input,\n output: usage.output,\n cacheRead: usage.cacheRead,\n cacheCreation: usage.cacheCreation,\n cost: usage.cost,\n turns: usage.turns,\n })\n }\n\n // Flatten child stats into nested summaries. We don't have the\n // child's full event lists here (those landed on the child's\n // own hooks), so the nested entry is a minimal totals-only\n // record — enough for a flat per-run audit trail; consumers\n // wanting full per-child event lists install a collector on\n // each subagent.\n for (const c of stats.children ?? []) {\n children.push(minimalSummaryFromStats(c.stats, {\n depth: c.depth ?? depth + 1,\n status: c.status === 'aborted' ? 'aborted' : 'completed',\n }))\n }\n\n const summary: RunSummary = {\n ...(runId ? { runId } : {}),\n ...(parentRunId ? { parentRunId } : {}),\n depth,\n ...(agentName ? { agentName } : {}),\n startedAt,\n endedAt,\n durationMs: endedAt - startedAt,\n status: aborted ? 'aborted' : 'completed',\n turns: stats.turns,\n totals: buildTotals(stats),\n byModel,\n errors: errors.slice(),\n blocks: blocks.slice(),\n validationRejects: validationRejects.slice(),\n budgetEvents: budgetEvents.slice(),\n repeatGuardEvents: repeatGuardEvents.slice(),\n pairingRepairs: { ...pairingRepairs },\n ...(children.length > 0 ? { children: children.slice() } : {}),\n }\n\n last = summary\n try {\n options.onSummary?.(summary)\n }\n catch {\n // Sink errors are not the collector's concern.\n }\n }))\n\n let disposed = false\n return function uninstall() {\n if (disposed)\n return\n disposed = true\n for (const un of unregisters) {\n try {\n un()\n }\n catch { /* ignore */ }\n }\n }\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction buildTotals(stats: AgentStats): RunSummaryTokens {\n return {\n input: stats.totalIn,\n output: stats.totalOut,\n cacheRead: stats.totalCacheRead,\n cacheCreation: stats.totalCacheCreation,\n ...(typeof stats.cost === 'number' ? { cost: stats.cost } : {}),\n ...(typeof stats.timeTillFirstTokenMs === 'number' ? { ttftMs: stats.timeTillFirstTokenMs } : {}),\n }\n}\n\nfunction minimalSummaryFromStats(\n stats: AgentStats,\n meta: { depth: number, status: 'completed' | 'aborted' },\n): RunSummary {\n const byModel: RunSummaryByModel[] = []\n for (const [modelId, usage] of statsByModel(stats)) {\n byModel.push({\n modelId,\n input: usage.input,\n output: usage.output,\n cacheRead: usage.cacheRead,\n cacheCreation: usage.cacheCreation,\n cost: usage.cost,\n turns: usage.turns,\n })\n }\n const children: RunSummary[] = []\n for (const c of stats.children ?? []) {\n children.push(minimalSummaryFromStats(c.stats, {\n depth: c.depth ?? meta.depth + 1,\n status: c.status === 'aborted' ? 'aborted' : 'completed',\n }))\n }\n return {\n depth: meta.depth,\n startedAt: 0,\n endedAt: 0,\n durationMs: stats.elapsed,\n status: meta.status,\n turns: stats.turns,\n totals: buildTotals(stats),\n byModel,\n errors: [],\n blocks: [],\n validationRejects: [],\n budgetEvents: [],\n repeatGuardEvents: [],\n pairingRepairs: {},\n ...(children.length > 0 ? { children } : {}),\n }\n}\n","/**\n * Headless mode — a non-interactive, fully-structured way to drive the agent\n * for automation and RL rollouts.\n *\n * `agent.run()` already returns rich {@link AgentStats}, the session captures a\n * lossless transcript (`session.turns`), and the hook bus exposes every\n * streaming/tool/turn event. What this module adds is the *contract* an RL loop\n * needs: one call (`runHeadless`) that runs a prompt to completion in a chosen\n * workdir, bounded by turns + wall-clock, and hands back a single serializable\n * {@link HeadlessResult} — final answer, verifiable structured output, usage,\n * and the complete trajectory — plus an optional live {@link HeadlessEvent}\n * stream (the in-process equivalent of `--output-format stream-json`).\n *\n * It is provider-agnostic: the caller passes a built {@link Provider} (e.g.\n * `local()` pointed at a vLLM server, or any of the named providers). The thin\n * CLI in `src/headless-cli.ts` wraps this with arg parsing, file/stdin I/O, and\n * JSONL transcript writing.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks, AgentOptions } from './agent'\nimport type { ExecutionContext } from './contexts'\nimport type { Provider } from './providers'\nimport type { RunSummary } from './run-summary'\nimport type { Session, SessionStore } from './session'\nimport type { PairingRepair } from './session/messages'\nimport type { ToolDef } from './tools'\nimport type {\n AgentStats,\n McpServerConfig,\n PromptPart,\n SessionContentBlock,\n SessionTurn,\n ThinkingLevel,\n TurnFinishReason,\n TurnUsage,\n} from './types'\nimport { createAgent } from './agent'\nimport { createProcessContext } from './contexts'\nimport { basic } from './presets'\nimport { createRunSummaryCollector } from './run-summary'\nimport { createMemoryStore, createSession } from './session'\nimport { ensureToolResultPairing } from './session/messages'\nimport { toolResultToText } from './types'\n\n// ---------------------------------------------------------------------------\n// Public shapes\n// ---------------------------------------------------------------------------\n\nexport type HeadlessStatus = 'completed' | 'aborted' | 'error' | 'timeout'\n\nexport interface HeadlessUsage {\n input: number\n output: number\n cacheRead: number\n cacheCreation: number\n /** Cumulative USD cost when the provider/registry could price the run. */\n cost?: number\n}\n\nexport interface HeadlessErrorInfo {\n message: string\n /** Typed-error class name (`AgentAbortedError`, `AgentContextExceededError`, …). */\n type: string\n}\n\n/**\n * Strictly JSON-serializable postmortem of one headless run. Everything an RL\n * reward function needs: the final answer (`finalText`), the verifiable\n * structured output (`output`, present iff a `schema` was set), usage/turns,\n * and the lossless `transcript` (the SFT training data).\n */\nexport interface HeadlessResult {\n status: HeadlessStatus\n /** Concatenated text of the last assistant turn that produced any text. */\n finalText: string\n /** Schema-enforced structured output (only when `opts.schema` is set). */\n output?: Record<string, unknown>\n usage: HeadlessUsage\n turns: number\n durationMs: number\n /** Total `tool_call` blocks across the whole transcript. */\n numToolCalls: number\n /** Finish reason of the final turn that reported one. */\n finishReason?: TurnFinishReason\n error?: HeadlessErrorInfo\n sessionId: string\n /** Incident postmortem (errors, gate blocks, budget events) via run-summary. */\n summary?: RunSummary\n /** Lossless transcript — raw `session.turns`. Thinking stripped when `includeThinking: false`. */\n transcript: SessionTurn[]\n}\n\n/**\n * Live event union — the in-process equivalent of a `stream-json` line. Every\n * member is JSON-serializable; render to JSONL with {@link headlessEventToJsonl}.\n */\nexport type HeadlessEvent\n = | { type: 'start', runId: string, provider?: string }\n | { type: 'text', delta: string }\n | { type: 'thinking', delta: string }\n | { type: 'tool_call', callId: string, name: string, input: Record<string, unknown> }\n | { type: 'tool_result', callId: string, name: string, output: string, isError: boolean }\n | { type: 'turn', index: number, usage: TurnUsage }\n | { type: 'spawn', event: 'before' | 'complete' | 'error', id: string, info?: Record<string, unknown> }\n | { type: 'error', message: string, errorType?: string }\n | { type: 'result', result: HeadlessResult }\n\n/** Serialize one event as a newline-terminated JSON line (stream-json). */\nexport function headlessEventToJsonl(event: HeadlessEvent): string {\n return `${JSON.stringify(event)}\\n`\n}\n\nexport interface HeadlessOptions {\n /** User prompt — plain string or multimodal `PromptPart[]`. */\n prompt: string | PromptPart[]\n /** Built provider (e.g. `local()`, `openaiCompat(...)`, `anthropic(...)`). */\n provider: Provider\n model?: string\n /** Override the preset system prompt for this run. */\n system?: string\n thinking?: ThinkingLevel\n maxTurns?: number\n maxTokens?: number\n /** Wall-clock cap; on expiry the run is aborted and `status` becomes `'timeout'`. */\n timeoutMs?: number\n /** External abort signal — chained with the internal timeout controller. */\n signal?: AbortSignal\n /** JSON Schema for structured-output enforcement → populates `result.output`. */\n schema?: Record<string, unknown>\n /** Tool overrides. Omit to use the basic preset's tools. */\n tools?: Record<string, ToolDef>\n mcpServers?: McpServerConfig[]\n skills?: AgentOptions['skills']\n /** Execution context. Defaults to a process context rooted at `cwd`. */\n execution?: ExecutionContext\n /** Working directory for the default process context (ignored if `execution` is set). */\n cwd?: string\n /** Reuse / resume an existing session. */\n session?: Session\n /** Session store for a fresh session (defaults to an in-memory store). */\n store?: SessionStore\n /** Keep `thinking` blocks in `result.transcript` (default true). */\n includeThinking?: boolean\n /** Live event callback — the in-process stream-json equivalent. */\n onEvent?: (event: HeadlessEvent) => void\n}\n\n// ---------------------------------------------------------------------------\n// runHeadless\n// ---------------------------------------------------------------------------\n\n/**\n * Run a prompt to completion, headless, and return a single serializable\n * {@link HeadlessResult}. Safe to call concurrently for parallel rollouts —\n * each call builds its own agent + session and tears them down in `finally`.\n */\nexport async function runHeadless(opts: HeadlessOptions): Promise<HeadlessResult> {\n const startedAt = Date.now()\n const execution = opts.execution ?? createProcessContext({ cwd: opts.cwd })\n const session = opts.session ?? await createSession({ store: opts.store ?? createMemoryStore() })\n\n const behavior: NonNullable<AgentOptions['behavior']> = {}\n if (opts.maxTurns !== undefined)\n behavior.maxTurns = opts.maxTurns\n if (opts.maxTokens !== undefined)\n behavior.maxTokens = opts.maxTokens\n if (opts.schema !== undefined)\n behavior.schema = opts.schema\n\n const agent = createAgent({\n ...basic,\n provider: opts.provider,\n execution,\n session,\n behavior,\n ...(opts.tools !== undefined ? { tools: opts.tools } : {}),\n ...(opts.mcpServers !== undefined ? { mcpServers: opts.mcpServers } : {}),\n ...(opts.skills !== undefined ? { skills: opts.skills } : {}),\n })\n\n const collector = createRunSummaryCollector()\n const uninstallSummary = collector.install(agent.hooks)\n const uninstallEvents = opts.onEvent ? installEventAdapter(agent.hooks, opts.onEvent) : noop\n\n // Internal controller drives the wall-clock timeout and chains any external\n // signal so a host cancel and a timeout both abort the same run.\n const controller = new AbortController()\n if (opts.signal) {\n if (opts.signal.aborted)\n controller.abort(opts.signal.reason)\n else\n opts.signal.addEventListener('abort', () => controller.abort(opts.signal!.reason), { once: true })\n }\n let timedOut = false\n const timer = opts.timeoutMs && opts.timeoutMs > 0\n ? setTimeout(() => {\n timedOut = true\n controller.abort(new Error(`Headless run timed out after ${opts.timeoutMs}ms`))\n }, opts.timeoutMs)\n : undefined\n\n let stats: AgentStats | undefined\n let error: HeadlessErrorInfo | undefined\n\n try {\n stats = await agent.run({\n prompt: opts.prompt,\n signal: controller.signal,\n ...(opts.model !== undefined ? { model: opts.model } : {}),\n ...(opts.system !== undefined ? { system: opts.system } : {}),\n ...(opts.thinking !== undefined ? { thinking: opts.thinking } : {}),\n })\n }\n catch (err) {\n // The agent loop throws typed errors (AgentAbortedError,\n // AgentContextExceededError, AgentProviderError, …) — their `name` already\n // classifies the failure, so surface it directly.\n const e = err instanceof Error ? err : new Error(String(err))\n error = { message: e.message, type: e.name }\n }\n finally {\n if (timer)\n clearTimeout(timer)\n uninstallEvents()\n uninstallSummary()\n await agent.destroy()\n }\n\n // Status: a thrown error wins, but an abort/timeout can also surface as a\n // clean resolve (the loop returns partial stats), so check the signal too.\n let status: HeadlessStatus\n if (error)\n status = timedOut ? 'timeout' : controller.signal.aborted ? 'aborted' : 'error'\n else if (controller.signal.aborted)\n status = timedOut ? 'timeout' : 'aborted'\n else\n status = 'completed'\n\n const rawTranscript = session.turns.slice()\n const transcript = opts.includeThinking === false ? stripThinking(rawTranscript) : rawTranscript\n const summary = collector.latest()\n\n const result: HeadlessResult = {\n status,\n finalText: extractFinalText(rawTranscript),\n ...(stats?.output ? { output: stats.output } : {}),\n usage: {\n input: stats?.totalIn ?? 0,\n output: stats?.totalOut ?? 0,\n cacheRead: stats?.totalCacheRead ?? 0,\n cacheCreation: stats?.totalCacheCreation ?? 0,\n ...(typeof stats?.cost === 'number' ? { cost: stats.cost } : {}),\n },\n turns: stats?.turns ?? 0,\n durationMs: stats?.elapsed ?? (Date.now() - startedAt),\n numToolCalls: countToolCalls(rawTranscript),\n // Suppress `finishReason` on abort/timeout: the last persisted turn can\n // carry `finishReason: 'stop'` (e.g. the model finished a turn, a follow-up\n // continued, then the run was cancelled), which would make a consumer\n // keyed on `finishReason === 'stop'` misread a cancel as \"model finished\".\n // `status` is authoritative for those exits; let it speak alone. The\n // `'pause'` exhaustion exit keeps `status: 'completed'` so it still\n // surfaces its `finishReason: 'pause'` here.\n ...(status !== 'aborted' && status !== 'timeout' && lastFinishReason(stats)\n ? { finishReason: lastFinishReason(stats) }\n : {}),\n ...(error ? { error } : {}),\n sessionId: session.id,\n ...(summary ? { summary } : {}),\n transcript,\n }\n\n opts.onEvent?.({ type: 'result', result })\n return result\n}\n\n// ---------------------------------------------------------------------------\n// Transcript → OpenAI chat messages (SFT-ready)\n// ---------------------------------------------------------------------------\n\nexport interface OpenAIChatMessage {\n role: 'system' | 'user' | 'assistant' | 'tool'\n content: string | null\n tool_calls?: Array<{ id: string, type: 'function', function: { name: string, arguments: string } }>\n tool_call_id?: string\n}\n\n/**\n * Convert raw `session.turns` into standard OpenAI chat-completion messages:\n * assistant turns carry `tool_calls`, and each `tool_result` becomes its own\n * `role: 'tool'` message. This is the drop-in shape for an SFT renderer —\n * unlike `toOpenAI` (session/messages.ts), which emits an internal `_tag`\n * envelope meant for re-sending to a provider, not for training data.\n *\n * Fails closed on corrupt raw turns instead of fabricating tool results; silent\n * placeholders would create structurally-valid but semantically-poisoned SFT\n * examples.\n */\nexport function transcriptToOpenAIMessages(turns: SessionTurn[]): OpenAIChatMessage[] {\n const messages: OpenAIChatMessage[] = []\n let chunk: Array<{ role: 'user' | 'assistant', content: SessionContentBlock[] }> = []\n const flushChunk = () => {\n if (chunk.length === 0)\n return\n const repairs: PairingRepair[] = []\n const paired = ensureToolResultPairing(chunk, { onRepair: repair => repairs.push(repair) })\n if (repairs.length > 0) {\n throw new Error(\n `Cannot convert transcript to OpenAI messages: tool pairing repair required (${repairs.map(r => r.mode).join(', ')})`,\n )\n }\n for (const msg of paired)\n pushOpenAIChatMessage(messages, msg)\n chunk = []\n }\n\n for (const turn of turns) {\n if (turn.role === 'system') {\n flushChunk()\n messages.push({ role: 'system', content: textOf(turn.content) })\n continue\n }\n chunk.push({ role: turn.role, content: turn.content })\n }\n flushChunk()\n\n return messages\n}\n\nfunction pushOpenAIChatMessage(messages: OpenAIChatMessage[], msg: { role: 'user' | 'assistant', content: SessionContentBlock[] }): void {\n const text = textOf(msg.content)\n\n if (msg.role === 'assistant') {\n const toolCalls = msg.content.filter((b): b is ToolCallBlock => b.type === 'tool_call')\n const out: OpenAIChatMessage = { role: 'assistant', content: text || null }\n if (toolCalls.length > 0) {\n out.tool_calls = toolCalls.map(b => ({\n id: b.id,\n type: 'function' as const,\n function: { name: b.name, arguments: JSON.stringify(b.input) },\n }))\n }\n messages.push(out)\n return\n }\n\n // user turn — may carry prompt text and/or tool_result blocks\n if (text)\n messages.push({ role: 'user', content: text })\n for (const tr of msg.content.filter((b): b is ToolResultBlock => b.type === 'tool_result'))\n messages.push({ role: 'tool', tool_call_id: tr.callId, content: toolResultToText(tr.output) })\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\ntype TextBlock = Extract<SessionContentBlock, { type: 'text' }>\ntype ToolCallBlock = Extract<SessionContentBlock, { type: 'tool_call' }>\ntype ToolResultBlock = Extract<SessionContentBlock, { type: 'tool_result' }>\n\nfunction noop(): void {}\n\nfunction textOf(content: SessionContentBlock[]): string {\n return content.filter((b): b is TextBlock => b.type === 'text').map(b => b.text).join('')\n}\n\nfunction extractFinalText(turns: SessionTurn[]): string {\n for (let i = turns.length - 1; i >= 0; i--) {\n const turn = turns[i]\n if (turn.role !== 'assistant')\n continue\n const text = textOf(turn.content)\n if (text)\n return text\n }\n return ''\n}\n\nfunction countToolCalls(turns: SessionTurn[]): number {\n let n = 0\n for (const turn of turns) {\n for (const block of turn.content) {\n if (block.type === 'tool_call')\n n++\n }\n }\n return n\n}\n\nfunction lastFinishReason(stats?: AgentStats): TurnFinishReason | undefined {\n const usages = stats?.turnUsage\n if (!usages)\n return undefined\n for (let i = usages.length - 1; i >= 0; i--) {\n if (usages[i].finishReason)\n return usages[i].finishReason\n }\n return undefined\n}\n\nfunction stripThinking(turns: SessionTurn[]): SessionTurn[] {\n return turns.map(turn => ({\n ...turn,\n content: turn.content.filter(b => b.type !== 'thinking' && b.type !== 'redacted_thinking'),\n }))\n}\n\nfunction installEventAdapter(\n hooks: Hookable<AgentHooks>,\n onEvent: (event: HeadlessEvent) => void,\n): () => void {\n const unregs: Array<() => void> = []\n const emit = (event: HeadlessEvent): void => {\n try {\n onEvent(event)\n }\n catch {\n // A consumer's sink throwing is not the adapter's concern.\n }\n }\n\n unregs.push(hooks.hook('agent:start', ctx => emit({\n type: 'start',\n runId: ctx.runId,\n ...(ctx.providerName ? { provider: ctx.providerName } : {}),\n })))\n unregs.push(hooks.hook('stream:text', ctx => emit({ type: 'text', delta: ctx.delta })))\n unregs.push(hooks.hook('stream:thinking', ctx => emit({ type: 'thinking', delta: ctx.delta })))\n unregs.push(hooks.hook('tool:before', ctx => emit({\n type: 'tool_call',\n callId: ctx.callId,\n name: ctx.name,\n input: ctx.input,\n })))\n unregs.push(hooks.hook('tool:after', ctx => emit({\n type: 'tool_result',\n callId: ctx.callId,\n name: ctx.name,\n output: toolResultToText(ctx.result),\n isError: false,\n })))\n unregs.push(hooks.hook('tool:error', ctx => emit({\n type: 'tool_result',\n callId: ctx.callId,\n name: ctx.name,\n output: ctx.error.message,\n isError: true,\n })))\n unregs.push(hooks.hook('turn:after', ctx => emit({ type: 'turn', index: ctx.turn, usage: ctx.usage })))\n unregs.push(hooks.hook('spawn:before', ctx => emit({ type: 'spawn', event: 'before', id: ctx.id })))\n unregs.push(hooks.hook('spawn:complete', ctx => emit({\n type: 'spawn',\n event: 'complete',\n id: ctx.id,\n info: { status: ctx.status ?? 'completed' },\n })))\n unregs.push(hooks.hook('spawn:error', ctx => emit({\n type: 'spawn',\n event: 'error',\n id: ctx.id,\n info: { message: ctx.error.message },\n })))\n unregs.push(hooks.hook('stream:error', ctx => emit({\n type: 'error',\n message: ctx.err instanceof Error ? ctx.err.message : String(ctx.err),\n ...(ctx.err instanceof Error ? { errorType: ctx.err.name } : {}),\n })))\n\n return () => {\n for (const un of unregs) {\n try {\n un()\n }\n catch {\n // ignore\n }\n }\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { Ct as HeadlessUsage, Dt as transcriptToOpenAIMessages, Et as runHeadless, St as HeadlessStatus, Tt as headlessEventToJsonl, bt as HeadlessOptions, vt as HeadlessErrorInfo, wt as OpenAIChatMessage, xt as HeadlessResult, yt as HeadlessEvent } from "./index-zy4OtFSv.js";
1
+ import { Ct as HeadlessUsage, Dt as transcriptToOpenAIMessages, Et as runHeadless, St as HeadlessStatus, Tt as headlessEventToJsonl, bt as HeadlessOptions, vt as HeadlessErrorInfo, wt as OpenAIChatMessage, xt as HeadlessResult, yt as HeadlessEvent } from "./index-BDMVtgHD.js";
2
2
  export { HeadlessErrorInfo, HeadlessEvent, HeadlessOptions, HeadlessResult, HeadlessStatus, HeadlessUsage, OpenAIChatMessage, headlessEventToJsonl, runHeadless, transcriptToOpenAIMessages };
package/dist/headless.js CHANGED
@@ -1,2 +1,2 @@
1
- import { n as runHeadless, r as transcriptToOpenAIMessages, t as headlessEventToJsonl } from "./headless-CJFFU6DI.js";
1
+ import { n as runHeadless, r as transcriptToOpenAIMessages, t as headlessEventToJsonl } from "./headless-AnwtKahq.js";
2
2
  export { headlessEventToJsonl, runHeadless, transcriptToOpenAIMessages };
@@ -1,4 +1,4 @@
1
- import { Cn as TurnUsage, Kt as AgentStats, L as SessionStore, O as SkillConfig, P as Session, Qt as McpServerConfig, Sn as TurnFinishReason, _n as ThinkingLevel, b as ToolDef, i as AgentOptions, in as PromptPart, l as SkillActivationState, mn as SessionTurn, pt as StreamOptions, qt as ChildRunStats, r as AgentHooks, s as ActiveSkill, ut as Provider, y as ToolContext, yn as ToolResultContent } from "./agent-acjWZ_4E.js";
1
+ import { Cn as TurnFinishReason, Kt as AgentStats, L as SessionStore, O as SkillConfig, P as Session, Qt as McpServerConfig, _n as ThinkingLevel, b as ToolDef, bn as ToolResultContent, i as AgentOptions, in as PromptPart, l as SkillActivationState, mn as SessionTurn, pt as StreamOptions, qt as ChildRunStats, r as AgentHooks, s as ActiveSkill, ut as Provider, wn as TurnUsage, y as ToolContext } from "./agent-CL4nT5Ti.js";
2
2
  import { a as ExecutionContext, o as ExecutionHandle } from "./types-CEAMIUXw.js";
3
3
  import { Hookable } from "hookable";
4
4
  import { OAuthClientProvider, OAuthDiscoveryState } from "@modelcontextprotocol/sdk/client/auth.js";
@@ -1342,6 +1342,10 @@ interface OpenAIChatMessage {
1342
1342
  * `role: 'tool'` message. This is the drop-in shape for an SFT renderer —
1343
1343
  * unlike `toOpenAI` (session/messages.ts), which emits an internal `_tag`
1344
1344
  * envelope meant for re-sending to a provider, not for training data.
1345
+ *
1346
+ * Fails closed on corrupt raw turns instead of fabricating tool results; silent
1347
+ * placeholders would create structurally-valid but semantically-poisoned SFT
1348
+ * examples.
1345
1349
  */
1346
1350
  declare function transcriptToOpenAIMessages(turns: SessionTurn[]): OpenAIChatMessage[];
1347
1351
  //#endregion
@@ -2443,4 +2447,4 @@ declare function definePreset(config: Preset): Preset;
2443
2447
  declare function composePresets(...presets: Preset[]): Preset;
2444
2448
  //#endregion
2445
2449
  export { cleanupPersistedSession as $, CacheDimensionSnapshot as $n, InteractionToolOptions as $t, MetricAttributes as A, BASE_INSTRUCTIONS as An, validateToolArgs as At, LoginMcpServerResult as B, buildUpToCompactPrompt as Bn, SkillsUseToolOptions as Bt, ModelUsage as C, selectFilesFromSession as Cn, HeadlessUsage as Ct, Histogram as D, compactConversation as Dn, transcriptToOpenAIMessages as Dt, Counter as E, CompactResult as En, runHeadless as Et, OAuthCallbackHandle as F, TRAILER as Fn, SpawnToolOptions as Ft, McpOAuthProviderOptions as G, anchorPreviewFor as Gn, createSkillsReadTool as Gt, McpCredentialEntry as H, CompactScope as Hn, SkillsRunScriptToolOptions as Ht, OAuthCallbackOptions as I, buildCompactPrompt as In, SpawnToolState as It, PERSISTED_STUB_PREFIX as J, summaryToTurn as Jn, createShellTool as Jt, createMemoryMcpCredentialStore as K, sliceForCompaction as Kn, shellKill as Kt, OAuthCallbackResult as L, buildFromCompactPrompt as Ln, SubagentDef as Lt, MetricsHooksOptions as M, CompactPromptBuilder as Mn, ToolSearchToolOptions as Mt, UpDownCounter as N, CompactPromptOptions as Nn, createToolSearchTool as Nt, InstrumentOptions as O, CompactInvalidInputError as On, writeFile as Ot, createMetricsHooks as P, NO_TOOLS_PREAMBLE as Pn, ChildAgent as Pt, buildPersistedStub as Q, CacheDimensionName as Qn, listFiles as Qt, startOAuthCallback as R, buildFullCompactPrompt as Rn, SubagentRegistry as Rt, splitSystemPrompt as S, selectFilesFromReadState as Sn, HeadlessStatus as St, statsByModel as T, CompactOptions as Tn, headlessEventToJsonl as Tt, McpCredentialStore as U, CompactionSlice as Un, createSkillsRunScriptTool as Ut, loginMcpServer as V, ANCHOR_PREVIEW_MAX_CHARS as Vn, createSkillsUseTool as Vt, McpOAuthProvider as W, SummaryToTurnInput as Wn, SkillsReadToolOptions as Wt, PersistInput as X, CacheBreakLoggerOptions as Xn, readFile as Xt, PERSISTENCE_PREVIEW_BYTES as Y, truncateHeadForPtlRetry as Yn, shell as Yt, PersistOutcome as Z, CacheDimensionDiff as Zn, multiEdit as Zt, appendStaticSection as _, utf8ByteLength as _n, jsonSink as _t, basicTools as a, RunSummaryBlock as an, TOOL_USE_CANCELLED_MESSAGE as at, renderSystemForWire as b, RecentFile as bn, HeadlessOptions as bt, Span as c, RunSummaryCollector as cn, LogLevel as ct, TracingHookSet as d, RunSummaryRepeatGuard as dn, Logger as dt, createInteractionTool as en, diffCacheDimensions as er, maybePersistToolResult as et, TracingHooksOptions as f, RunSummaryTokens as fn, LoggingHookSet as ft, appendDynamicSection as g, estimateTokens as gn, createLoggingHooks as gt, SystemPromptParts as h, BYTES_PER_TOKEN as hn, createLogger as ht, _default as i, RunSummary as in, SHELL_CASCADE_CANCEL_MESSAGE as it, MetricsHookSet as j, CompactDirection as jn, LazyToolEntry as jt, Meter as k, CompactPromptTooLongError as kn, ValidationResult as kt, StartSpan as l, RunSummaryCollectorOptions as ln, LogRecord as lt, SYSTEM_PROMPT_BOUNDARY as m, createRunSummaryCollector as mn, consoleSink as mt, composePresets as n, glob as nn, installCacheBreakLogger as nr, resolveTasksDir as nt, zodToJsonSchema as o, RunSummaryBudget as on, TOOL_USE_SKIPPED_MESSAGE as ot, createTracingHooks as p, RunSummaryValidation as pn, LoggingHooksOptions as pt, hasAuthorizationHeader as q, stripImagesFromTurns as qn, CreateShellToolOptions as qt, definePreset as r, edit as rn, snapshotCacheDimensions as rr, INTERRUPT_MESSAGE_FOR_TOOL_USE as rt, GEN_AI_ATTRIBUTES as s, RunSummaryByModel as sn, ConsoleSinkOptions as st, Preset as t, grep as tn, fnv1a32 as tr, resolvePersistDir as tt, TracingConventions as u, RunSummaryError as un, LogSink as ut, hasSystemPromptBoundary as v, PostCompactAttachments as vn, HeadlessErrorInfo as vt, flattenTurns as w, selectRecentFiles as wn, OpenAIChatMessage as wt, replaceDynamicSection as x, buildPostCompactAttachments as xn, HeadlessResult as xt, joinSystemPrompt as y, PostCompactRestoreOptions as yn, HeadlessEvent as yt, LoginMcpServerOptions as z, buildTailCompactPrompt as zn, createSpawnTool as zt };
2446
- //# sourceMappingURL=index-zy4OtFSv.d.ts.map
2450
+ //# sourceMappingURL=index-BDMVtgHD.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-BDMVtgHD.d.ts","names":[],"sources":["../src/cache-telemetry.ts","../src/compact/messages.ts","../src/compact/prompt.ts","../src/compact/errors.ts","../src/compact/compact.ts","../src/compact/restore.ts","../src/compact/utils.ts","../src/run-summary.ts","../src/tools/edit.ts","../src/tools/glob.ts","../src/tools/grep.ts","../src/tools/interaction.ts","../src/tools/list-files.ts","../src/tools/multi-edit.ts","../src/tools/read-file.ts","../src/tools/shell.ts","../src/tools/shell-kill.ts","../src/tools/skills-read.ts","../src/tools/skills-run-script.ts","../src/tools/skills-use.ts","../src/tools/spawn.ts","../src/tools/tool-search.ts","../src/tools/validation.ts","../src/tools/write-file.ts","../src/headless.ts","../src/logger.ts","../src/loop.ts","../src/loop-persistence.ts","../src/mcp/oauth-provider.ts","../src/mcp/login.ts","../src/mcp/oauth-callback.ts","../src/metrics.ts","../src/stats.ts","../src/system-prompt.ts","../src/tracing.ts","../src/zod.ts","../src/presets/basic.ts","../src/presets/index.ts"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { M as SkillsConfig, O as SkillConfig, j as SkillSource, k as SkillDiagnostic, l as SkillActivationState, r as AgentHooks } from "./agent-acjWZ_4E.js";
1
+ import { M as SkillsConfig, O as SkillConfig, j as SkillSource, k as SkillDiagnostic, l as SkillActivationState, r as AgentHooks } from "./agent-CL4nT5Ti.js";
2
2
  import { a as ExecutionContext, o as ExecutionHandle } from "./types-CEAMIUXw.js";
3
3
  import { Hookable } from "hookable";
4
4
 
@@ -267,4 +267,4 @@ declare function defineSkill(config: Omit<SkillConfig, 'source'> & {
267
267
  }): SkillConfig;
268
268
  //#endregion
269
269
  export { installAllowedToolsGate as S, inferSource as _, SkillValidationResult as a, buildCatalog as b, parseAllowedToolPattern as c, validateSkillName as d, resolveSkills as f, getDefaultScanPaths as g, discoverSkills as h, SkillValidationIssue as i, validateResourcePath as l, SourcedScanPath as m, writeSkillToDisk as n, isToolAllowedByUnion as o, interpolateShellCommands as p, writeSkillsToDisk as r, matchesAllowedTool as s, defineSkill as t, validateSkillForWrite as u, parseFrontmatter as v, IMPLICITLY_ALLOWED_SKILL_TOOLS as x, parseSkillFile as y };
270
- //# sourceMappingURL=index-Cgr_mbMJ.d.ts.map
270
+ //# sourceMappingURL=index-DtLfTUXt.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-Cgr_mbMJ.d.ts","names":[],"sources":["../src/skills/allowed-tools.ts","../src/skills/catalog.ts","../src/skills/discovery.ts","../src/skills/interpolate.ts","../src/skills/resolve.ts","../src/skills/validate.ts","../src/skills/writer.ts","../src/skills/index.ts"],"mappings":";;;;;;cAuBa,8BAAA;;;;;;AAkBgB;;;;ACrB7B;iBDmBgB,uBAAA,CACd,KAAA,EAAO,QAAA,CAAS,UAAA,GAChB,KAAA,EAAO,oBAAA;;;UCrBQ,mBAAA;EDoBR;;;;;ECdP,oBAAA;EDe2B;;;;ECV3B,YAAY;AAAA;;;AAAA;iBAME,YAAA,CACd,MAAA,EAAQ,WAAA,IACR,OAAA,GAAS,mBAAwB;;;UC4EzB,eAAA;EACR,WAAA,EAAa,MAAA;EACb,IAAA;EACA,WAAA,EAAa,eAAe;AAAA;;;;;;;;AF7ED;;;;ACrB7B;;;;AAWc;iBC0GE,gBAAA,CAAiB,OAAA,WAAkB,eAAe;AAAA,UAuUxD,iBAAA;;EAER,MAAA,GAAS,WAAW;AAAA;;;;;AD3aa;;;;AC3BoD;;;iBAodjE,cAAA,CACpB,QAAA,UACA,OAAA,GAAS,iBAAA,GACR,OAAA,CAAQ,WAAA;;UAqNM,eAAA;EACf,IAAA;EACA,MAAA,EAAQ,WAAW;AAAA;;AApkBS;AAmB9B;;;iBAyjBgB,mBAAA,CAAA,GAAuB,eAAe;AAzjBY;AAiHjE;;;AAjHiE,iBA0kBlD,WAAA,CAAY,IAAA,WAAe,WAAW;AAjQhC;AActB;;;;;;;;;AAdsB,iBAmRA,cAAA,CACpB,KAAA,EAAO,eAAA,IACP,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,WAAA;;;;;;;;;;;;;;;iBC1sBW,wBAAA,CACpB,YAAA,UACA,SAAA,EAAW,gBAAA,EACX,MAAA,EAAQ,eAAA,GACP,OAAA;;;AHXH;;;;AAIC;AAYD;;;;AAhBA,UIGiB,oBAAA;EACf,MAAA,EAAQ,WAAW;EACnB,OAAA;AAAA;;;;;;;AJa2B;;;;ACrB7B;;;;AAWc;AAMd;;;iBGYsB,aAAA,CAAc,MAAA,EAAQ,YAAA,GAAe,OAAA,CAAQ,oBAAA;;;;;AJtBlE;AAYD;;UKCiB,oBAAA;ELAC;EKEhB,IAAA;ELDO;EKGP,OAAA;ELH2B;EKK3B,KAAA;AAAA;AAAA,UAGe,qBAAA;EACf,KAAA;EACA,MAAA,EAAQ,oBAAoB;AAAA;ALVD;;;;ACrB7B;;;;AAWc;AAMd;ADI6B,iBK2Bb,iBAAA,CAAkB,IAAY;;;;;;iBAmB9B,qBAAA,CAAsB,KAAA,EAAO,WAAA,GAAc,qBAAqB;;AJhD7C;;;;AC3BoD;;;;;;iBGiLvE,oBAAA,CACd,OAAA,UACA,OAAA;EACG,KAAA;EAAa,YAAA;AAAA;EAA2B,KAAA;EAAc,KAAA;AAAA;;;AHvDO;AAiHjE;;;;iBGXe,uBAAA,CAAwB,KAAA;EAAkB,IAAA;EAAc,SAAA;AAAA;;;;;;;;;;;;AHoPlD;AAqNtB;;iBG5agB,kBAAA,CACd,WAAA,UACA,KAAA,EAAO,MAAM,mBACb,OAAA;;;;;;iBAyBc,oBAAA,CACd,WAAA,UACA,KAAA,EAAO,MAAM,mBACb,KAAA;;;;;ALhRD;AAYD;;;;;iBM8BgB,gBAAA,CAAiB,KAAA,EAAO,WAAW,EAAE,SAAA;;;;;;iBAoCrC,iBAAA,CAAkB,MAAA,EAAQ,WAAW,IAAI,SAAA;;;;;;;;;iBCnDzC,WAAA,CAAY,MAAA,EAAQ,IAAA,CAAK,WAAA;EAA2B,MAAA,GAAS,WAAA;AAAA,IAA0B,WAAA"}
1
+ {"version":3,"file":"index-DtLfTUXt.d.ts","names":[],"sources":["../src/skills/allowed-tools.ts","../src/skills/catalog.ts","../src/skills/discovery.ts","../src/skills/interpolate.ts","../src/skills/resolve.ts","../src/skills/validate.ts","../src/skills/writer.ts","../src/skills/index.ts"],"mappings":";;;;;;cAuBa,8BAAA;;;;;;AAkBgB;;;;ACrB7B;iBDmBgB,uBAAA,CACd,KAAA,EAAO,QAAA,CAAS,UAAA,GAChB,KAAA,EAAO,oBAAA;;;UCrBQ,mBAAA;EDoBR;;;;;ECdP,oBAAA;EDe2B;;;;ECV3B,YAAY;AAAA;;;AAAA;iBAME,YAAA,CACd,MAAA,EAAQ,WAAA,IACR,OAAA,GAAS,mBAAwB;;;UC4EzB,eAAA;EACR,WAAA,EAAa,MAAA;EACb,IAAA;EACA,WAAA,EAAa,eAAe;AAAA;;;;;;;;AF7ED;;;;ACrB7B;;;;AAWc;iBC0GE,gBAAA,CAAiB,OAAA,WAAkB,eAAe;AAAA,UAuUxD,iBAAA;;EAER,MAAA,GAAS,WAAW;AAAA;;;;;AD3aa;;;;AC3BoD;;;iBAodjE,cAAA,CACpB,QAAA,UACA,OAAA,GAAS,iBAAA,GACR,OAAA,CAAQ,WAAA;;UAqNM,eAAA;EACf,IAAA;EACA,MAAA,EAAQ,WAAW;AAAA;;AApkBS;AAmB9B;;;iBAyjBgB,mBAAA,CAAA,GAAuB,eAAe;AAzjBY;AAiHjE;;;AAjHiE,iBA0kBlD,WAAA,CAAY,IAAA,WAAe,WAAW;AAjQhC;AActB;;;;;;;;;AAdsB,iBAmRA,cAAA,CACpB,KAAA,EAAO,eAAA,IACP,MAAA,GAAS,WAAA,GACR,OAAA,CAAQ,WAAA;;;;;;;;;;;;;;;iBC1sBW,wBAAA,CACpB,YAAA,UACA,SAAA,EAAW,gBAAA,EACX,MAAA,EAAQ,eAAA,GACP,OAAA;;;AHXH;;;;AAIC;AAYD;;;;AAhBA,UIGiB,oBAAA;EACf,MAAA,EAAQ,WAAW;EACnB,OAAA;AAAA;;;;;;;AJa2B;;;;ACrB7B;;;;AAWc;AAMd;;;iBGYsB,aAAA,CAAc,MAAA,EAAQ,YAAA,GAAe,OAAA,CAAQ,oBAAA;;;;;AJtBlE;AAYD;;UKCiB,oBAAA;ELAC;EKEhB,IAAA;ELDO;EKGP,OAAA;ELH2B;EKK3B,KAAA;AAAA;AAAA,UAGe,qBAAA;EACf,KAAA;EACA,MAAA,EAAQ,oBAAoB;AAAA;ALVD;;;;ACrB7B;;;;AAWc;AAMd;ADI6B,iBK2Bb,iBAAA,CAAkB,IAAY;;;;;;iBAmB9B,qBAAA,CAAsB,KAAA,EAAO,WAAA,GAAc,qBAAqB;;AJhD7C;;;;AC3BoD;;;;;;iBGiLvE,oBAAA,CACd,OAAA,UACA,OAAA;EACG,KAAA;EAAa,YAAA;AAAA;EAA2B,KAAA;EAAc,KAAA;AAAA;;;AHvDO;AAiHjE;;;;iBGXe,uBAAA,CAAwB,KAAA;EAAkB,IAAA;EAAc,SAAA;AAAA;;;;;;;;;;;;AHoPlD;AAqNtB;;iBG5agB,kBAAA,CACd,WAAA,UACA,KAAA,EAAO,MAAM,mBACb,OAAA;;;;;;iBAyBc,oBAAA,CACd,WAAA,UACA,KAAA,EAAO,MAAM,mBACb,KAAA;;;;;ALhRD;AAYD;;;;;iBM8BgB,gBAAA,CAAiB,KAAA,EAAO,WAAW,EAAE,SAAA;;;;;;iBAoCrC,iBAAA,CAAkB,MAAA,EAAQ,WAAW,IAAI,SAAA;;;;;;;;;iBCnDzC,WAAA,CAAY,MAAA,EAAQ,IAAA,CAAK,WAAA;EAA2B,MAAA,GAAS,WAAA;AAAA,IAA0B,WAAA"}