gemi 0.60.0 → 0.62.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/dist/ai/Agent.d.ts +533 -25
  2. package/dist/ai/Agent.d.ts.map +1 -1
  3. package/dist/ai/Agent.test-d.d.ts +2 -0
  4. package/dist/ai/Agent.test-d.d.ts.map +1 -0
  5. package/dist/ai/AgentController.d.ts +275 -6
  6. package/dist/ai/AgentController.d.ts.map +1 -1
  7. package/dist/ai/AgentProvider.d.ts +255 -0
  8. package/dist/ai/AgentProvider.d.ts.map +1 -0
  9. package/dist/ai/Schema.d.ts +125 -0
  10. package/dist/ai/Schema.d.ts.map +1 -0
  11. package/dist/ai/Schema.test-d.d.ts +2 -0
  12. package/dist/ai/Schema.test-d.d.ts.map +1 -0
  13. package/dist/ai/client/index.d.ts +24 -0
  14. package/dist/ai/client/index.d.ts.map +1 -0
  15. package/dist/ai/client/index.js +1053 -0
  16. package/dist/ai/client/index.js.map +1 -0
  17. package/dist/ai/client/reducer.d.ts +127 -0
  18. package/dist/ai/client/reducer.d.ts.map +1 -0
  19. package/dist/ai/client/reducer.test-d.d.ts +2 -0
  20. package/dist/ai/client/reducer.test-d.d.ts.map +1 -0
  21. package/dist/ai/client/sse.d.ts +54 -0
  22. package/dist/ai/client/sse.d.ts.map +1 -0
  23. package/dist/ai/example.d.ts +129 -0
  24. package/dist/ai/example.d.ts.map +1 -0
  25. package/dist/ai/index.d.ts +35 -0
  26. package/dist/ai/index.d.ts.map +1 -0
  27. package/dist/ai/index.js +20 -0
  28. package/dist/ai/index.js.map +23 -0
  29. package/dist/ai/live/harness.d.ts +137 -0
  30. package/dist/ai/live/harness.d.ts.map +1 -0
  31. package/dist/ai/providers/call.d.ts +42 -0
  32. package/dist/ai/providers/call.d.ts.map +1 -0
  33. package/dist/ai/providers/capabilities.d.ts +50 -0
  34. package/dist/ai/providers/capabilities.d.ts.map +1 -0
  35. package/dist/ai/providers/errors.d.ts +37 -0
  36. package/dist/ai/providers/errors.d.ts.map +1 -0
  37. package/dist/ai/providers/fakeProvider.d.ts +35 -0
  38. package/dist/ai/providers/fakeProvider.d.ts.map +1 -0
  39. package/dist/ai/providers/http.d.ts +46 -0
  40. package/dist/ai/providers/http.d.ts.map +1 -0
  41. package/dist/ai/providers/request.d.ts +69 -0
  42. package/dist/ai/providers/request.d.ts.map +1 -0
  43. package/dist/ai/providers/stream.d.ts +42 -0
  44. package/dist/ai/providers/stream.d.ts.map +1 -0
  45. package/dist/ai/signing.d.ts +195 -0
  46. package/dist/ai/signing.d.ts.map +1 -0
  47. package/dist/ai/store/LiveRuns.d.ts +142 -0
  48. package/dist/ai/store/LiveRuns.d.ts.map +1 -0
  49. package/dist/ai/store/MemoryAgentStore.d.ts +61 -0
  50. package/dist/ai/store/MemoryAgentStore.d.ts.map +1 -0
  51. package/dist/ai/store/index.d.ts +4 -0
  52. package/dist/ai/store/index.d.ts.map +1 -0
  53. package/dist/ai/store/sse.d.ts +58 -0
  54. package/dist/ai/store/sse.d.ts.map +1 -0
  55. package/dist/ai/store/stubAgentRun.d.ts +56 -0
  56. package/dist/ai/store/stubAgentRun.d.ts.map +1 -0
  57. package/dist/ai/types.d.ts +443 -0
  58. package/dist/ai/types.d.ts.map +1 -0
  59. package/dist/ai/useChat.d.ts +253 -7
  60. package/dist/ai/useChat.d.ts.map +1 -1
  61. package/dist/chunk-1aqzcgfr.js +5 -0
  62. package/dist/chunk-1aqzcgfr.js.map +10 -0
  63. package/dist/{chunk-get4mkx8.js → chunk-1b7e9rj7.js} +2 -2
  64. package/dist/{chunk-get4mkx8.js.map → chunk-1b7e9rj7.js.map} +1 -1
  65. package/dist/{chunk-j06g4sqc.js → chunk-528n3vgy.js} +2 -2
  66. package/dist/{chunk-j06g4sqc.js.map → chunk-528n3vgy.js.map} +1 -1
  67. package/dist/{chunk-2khdxyjb.js → chunk-57a0nqfj.js} +1 -1
  68. package/dist/chunk-57a0nqfj.js.map +10 -0
  69. package/dist/chunk-5fj71djg.js +6 -0
  70. package/dist/{chunk-y3zz410b.js.map → chunk-5fj71djg.js.map} +2 -2
  71. package/dist/{chunk-c40n5r4v.js → chunk-5mhcwnyd.js} +2 -2
  72. package/dist/{chunk-c40n5r4v.js.map → chunk-5mhcwnyd.js.map} +1 -1
  73. package/dist/{chunk-gwchvzdp.js → chunk-71pk1mxx.js} +2 -2
  74. package/dist/{chunk-gwchvzdp.js.map → chunk-71pk1mxx.js.map} +1 -1
  75. package/dist/{chunk-spbgpndn.js → chunk-7t1hjs9f.js} +2 -2
  76. package/dist/{chunk-spbgpndn.js.map → chunk-7t1hjs9f.js.map} +1 -1
  77. package/dist/{chunk-9gsdcjt7.js → chunk-7xvaace2.js} +3 -3
  78. package/dist/{chunk-9gsdcjt7.js.map → chunk-7xvaace2.js.map} +1 -1
  79. package/dist/{chunk-fxy42w6n.js → chunk-8ag0da2s.js} +2 -2
  80. package/dist/{chunk-fxy42w6n.js.map → chunk-8ag0da2s.js.map} +1 -1
  81. package/dist/chunk-8r8epsef.js +5 -0
  82. package/dist/chunk-8r8epsef.js.map +11 -0
  83. package/dist/{chunk-0fm6jh9b.js → chunk-9nmvm20t.js} +2 -2
  84. package/dist/{chunk-0fm6jh9b.js.map → chunk-9nmvm20t.js.map} +1 -1
  85. package/dist/chunk-9penj44g.js +5 -0
  86. package/dist/{chunk-khf9xda6.js.map → chunk-9penj44g.js.map} +2 -2
  87. package/dist/{chunk-98a3k7bp.js → chunk-9xpa7dpy.js} +2 -2
  88. package/dist/{chunk-98a3k7bp.js.map → chunk-9xpa7dpy.js.map} +1 -1
  89. package/dist/{chunk-qva4841r.js → chunk-a1exbqcq.js} +3 -3
  90. package/dist/{chunk-qva4841r.js.map → chunk-a1exbqcq.js.map} +1 -1
  91. package/dist/{chunk-cw9y6k15.js → chunk-bb19bwg6.js} +2 -2
  92. package/dist/{chunk-cw9y6k15.js.map → chunk-bb19bwg6.js.map} +1 -1
  93. package/dist/{chunk-3gvjn3q4.js → chunk-cf7bvd12.js} +1 -1
  94. package/dist/{chunk-rkbv3df7.js → chunk-djp2xeqe.js} +2 -2
  95. package/dist/{chunk-rkbv3df7.js.map → chunk-djp2xeqe.js.map} +1 -1
  96. package/dist/chunk-ds44bqr9.js +4 -0
  97. package/dist/{chunk-4mcyyh1v.js.map → chunk-ds44bqr9.js.map} +4 -9
  98. package/dist/{chunk-wzvs3sym.js → chunk-exndjhza.js} +3 -3
  99. package/dist/{chunk-wzvs3sym.js.map → chunk-exndjhza.js.map} +1 -1
  100. package/dist/{chunk-f6dd4gd8.js → chunk-f233yzxf.js} +2 -2
  101. package/dist/{chunk-f6dd4gd8.js.map → chunk-f233yzxf.js.map} +1 -1
  102. package/dist/chunk-fz5g2z6h.js +4 -0
  103. package/dist/{chunk-fbvvqf9b.js.map → chunk-fz5g2z6h.js.map} +2 -2
  104. package/dist/{chunk-vj9538yn.js → chunk-gcszdwcb.js} +2 -2
  105. package/dist/{chunk-vj9538yn.js.map → chunk-gcszdwcb.js.map} +1 -1
  106. package/dist/{chunk-dgasxgsm.js → chunk-hk06nhxh.js} +4 -4
  107. package/dist/{chunk-dgasxgsm.js.map → chunk-hk06nhxh.js.map} +5 -5
  108. package/dist/{chunk-pkjq9833.js → chunk-htesx7ym.js} +4 -4
  109. package/dist/{chunk-pkjq9833.js.map → chunk-htesx7ym.js.map} +1 -1
  110. package/dist/{chunk-stq96kya.js → chunk-k2sjvt0c.js} +2 -2
  111. package/dist/{chunk-stq96kya.js.map → chunk-k2sjvt0c.js.map} +1 -1
  112. package/dist/{chunk-x8beq9c4.js → chunk-k4a2gzyc.js} +2 -2
  113. package/dist/{chunk-x8beq9c4.js.map → chunk-k4a2gzyc.js.map} +1 -1
  114. package/dist/{chunk-zhbrkpb3.js → chunk-k75phgj4.js} +4 -4
  115. package/dist/{chunk-zhbrkpb3.js.map → chunk-k75phgj4.js.map} +1 -1
  116. package/dist/{chunk-23h0dmx2.js → chunk-kac5vmvn.js} +2 -2
  117. package/dist/{chunk-23h0dmx2.js.map → chunk-kac5vmvn.js.map} +1 -1
  118. package/dist/{chunk-y64j80v9.js → chunk-m0tp7zjp.js} +2 -2
  119. package/dist/{chunk-y64j80v9.js.map → chunk-m0tp7zjp.js.map} +1 -1
  120. package/dist/{chunk-06j6rsew.js → chunk-m45j7p1y.js} +2 -2
  121. package/dist/{chunk-06j6rsew.js.map → chunk-m45j7p1y.js.map} +1 -1
  122. package/dist/chunk-mca9wsvs.js +5 -0
  123. package/dist/{chunk-z2tcxwyr.js.map → chunk-mca9wsvs.js.map} +3 -4
  124. package/dist/{chunk-tey1xayb.js → chunk-ms13evzp.js} +2 -2
  125. package/dist/{chunk-tey1xayb.js.map → chunk-ms13evzp.js.map} +1 -1
  126. package/dist/{chunk-bn1v4sfs.js → chunk-r962ae93.js} +2 -2
  127. package/dist/{chunk-bn1v4sfs.js.map → chunk-r962ae93.js.map} +1 -1
  128. package/dist/chunk-snb68dgr.js +4 -0
  129. package/dist/{chunk-hwhw98hc.js.map → chunk-snb68dgr.js.map} +1 -1
  130. package/dist/chunk-sz051605.js +5 -0
  131. package/dist/chunk-sz051605.js.map +14 -0
  132. package/dist/{chunk-2cwcfwg3.js → chunk-tr3cbx8k.js} +2 -2
  133. package/dist/{chunk-2cwcfwg3.js.map → chunk-tr3cbx8k.js.map} +2 -2
  134. package/dist/{chunk-zqsfanvk.js → chunk-wpb1xpdp.js} +2 -2
  135. package/dist/{chunk-zqsfanvk.js.map → chunk-wpb1xpdp.js.map} +1 -1
  136. package/dist/{chunk-z1e55w67.js → chunk-ybqss0jy.js} +2 -2
  137. package/dist/{chunk-z1e55w67.js.map → chunk-ybqss0jy.js.map} +1 -1
  138. package/dist/{chunk-cejf873g.js → chunk-yk5wqmyh.js} +2 -2
  139. package/dist/{chunk-cejf873g.js.map → chunk-yk5wqmyh.js.map} +1 -1
  140. package/dist/{chunk-8kj3zrm9.js → chunk-ywntv8yw.js} +4 -4
  141. package/dist/{chunk-8kj3zrm9.js.map → chunk-ywntv8yw.js.map} +1 -1
  142. package/dist/chunks/{ThemeProvider-ByU4BQdL.js → ThemeProvider-BZ2SsSZ3.js} +60 -39
  143. package/dist/chunks/ThemeProvider-BZ2SsSZ3.js.map +1 -0
  144. package/dist/chunks/useParams-BN3XXfmG.js +20 -0
  145. package/dist/chunks/useParams-BN3XXfmG.js.map +1 -0
  146. package/dist/client/index.js +3 -3
  147. package/dist/client/index.js.map +1 -1
  148. package/dist/client/useDictionary.d.ts.map +1 -1
  149. package/dist/database/index.js +1 -1
  150. package/dist/facades/Storage.d.ts +6 -2
  151. package/dist/facades/Storage.d.ts.map +1 -1
  152. package/dist/facades/index.js +2 -2
  153. package/dist/facades/index.js.map +1 -1
  154. package/dist/http/ApiRouter.d.ts +30 -2
  155. package/dist/http/ApiRouter.d.ts.map +1 -1
  156. package/dist/http/index.js +2 -2
  157. package/dist/http/index.js.map +1 -1
  158. package/dist/i18n/defineDictionary.d.ts +7 -4
  159. package/dist/i18n/defineDictionary.d.ts.map +1 -1
  160. package/dist/i18n/dictionaryRegistry.d.ts +38 -14
  161. package/dist/i18n/dictionaryRegistry.d.ts.map +1 -1
  162. package/dist/i18n/dictionaryRuntime.js +1 -1
  163. package/dist/i18n/index.js +2 -2
  164. package/dist/i18n/index.js.map +2 -2
  165. package/dist/kernel/index.js +2 -2
  166. package/dist/kernel/index.js.map +2 -2
  167. package/dist/orm/index.js +2 -2
  168. package/dist/orm/index.js.map +2 -2
  169. package/dist/server/index.js +1 -1
  170. package/dist/services/file-storage/drivers/AzureBlobDriver.d.ts +3 -2
  171. package/dist/services/file-storage/drivers/AzureBlobDriver.d.ts.map +1 -1
  172. package/dist/services/file-storage/drivers/FileStorageDriver.d.ts +2 -2
  173. package/dist/services/file-storage/drivers/FileStorageDriver.d.ts.map +1 -1
  174. package/dist/services/file-storage/drivers/FileSystemDriver.d.ts +2 -2
  175. package/dist/services/file-storage/drivers/FileSystemDriver.d.ts.map +1 -1
  176. package/dist/services/file-storage/drivers/S3Driver.d.ts +2 -2
  177. package/dist/services/file-storage/drivers/S3Driver.d.ts.map +1 -1
  178. package/dist/services/file-storage/drivers/types.d.ts +9 -1
  179. package/dist/services/file-storage/drivers/types.d.ts.map +1 -1
  180. package/dist/services/index.d.ts +1 -1
  181. package/dist/services/index.d.ts.map +1 -1
  182. package/dist/services/index.js +6 -6
  183. package/dist/services/index.js.map +4 -4
  184. package/dist/testing/index.js +2 -1
  185. package/dist/testing/index.js.map +1 -1
  186. package/package.json +3 -1
  187. package/dist/chunk-2khdxyjb.js.map +0 -10
  188. package/dist/chunk-4mcyyh1v.js +0 -4
  189. package/dist/chunk-fbvvqf9b.js +0 -4
  190. package/dist/chunk-hwhw98hc.js +0 -4
  191. package/dist/chunk-khf9xda6.js +0 -5
  192. package/dist/chunk-q0y0j3ne.js +0 -5
  193. package/dist/chunk-q0y0j3ne.js.map +0 -11
  194. package/dist/chunk-y3zz410b.js +0 -6
  195. package/dist/chunk-z2tcxwyr.js +0 -5
  196. package/dist/chunks/ThemeProvider-ByU4BQdL.js.map +0 -1
  197. /package/dist/{chunk-3gvjn3q4.js.map → chunk-cf7bvd12.js.map} +0 -0
@@ -0,0 +1,23 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../ai/Schema.ts", "../ai/signing.ts", "../ai/store/sse.ts", "../ai/Agent.ts", "../ai/providers/errors.ts", "../ai/providers/http.ts", "../ai/providers/stream.ts", "../ai/providers/call.ts", "../ai/providers/capabilities.ts", "../ai/providers/request.ts", "../ai/AgentProvider.ts", "../ai/store/LiveRuns.ts", "../ai/store/MemoryAgentStore.ts", "../ai/AgentController.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * The schema layer for tool inputs, tool outputs and structured final answers.\n *\n * Two things have to come out of one declaration: a TypeScript type, so\n * `execute(input)` is typed at the call site and the result is typed in the\n * browser, and a JSON Schema, because that is what the model is actually shown.\n * A phantom `Schema<T>` gives the first and nothing of the second, and a\n * hand-written JSON Schema next to a hand-written type gives both and lets them\n * drift. So the builder below is the single source, and `Infer` reads the type\n * back off it.\n *\n * Everything here is deliberately narrower than JSON Schema. OpenAI's strict\n * structured output only accepts a subset — every property listed in\n * `required`, `additionalProperties: false` on every object, no patterns, no\n * `oneOf` at the root — and a builder that cannot express the rejected parts is\n * better than one that lets you write a schema the API refuses at runtime.\n */\n\nexport type JSONSchema = {\n type?: string | string[];\n description?: string;\n enum?: readonly (string | number)[];\n const?: string | number | boolean;\n properties?: Record<string, JSONSchema>;\n required?: readonly string[];\n additionalProperties?: false;\n items?: JSONSchema;\n anyOf?: readonly JSONSchema[];\n};\n\ndeclare const OUTPUT: unique symbol;\ndeclare const OPTIONAL: unique symbol;\n\n/**\n * `T` is carried in a phantom property rather than a real one: it exists only\n * for inference, and a real field would show up on the object the app writes.\n */\nexport interface Schema<T> {\n readonly [OUTPUT]: T;\n /** The JSON Schema handed to the provider. */\n toJSONSchema(): JSONSchema;\n /**\n * Parses a value coming back from the model. Tool arguments arrive as a JSON\n * string the model generated, so they are untrusted in exactly the way a\n * request body is: shape-checked before `execute` ever sees them.\n */\n parse(value: unknown): T;\n safeParse(value: unknown): { ok: true; value: T } | { ok: false; errors: string[] };\n}\n\n/**\n * A schema whose key may be left out of the object containing it.\n *\n * Marked with a property rather than detected from the output type, because\n * `undefined extends T` — the obvious test — is true of *everything* when\n * `strictNullChecks` is off, which is how this package and plenty of apps\n * compile. That version made every field of every tool optional, and did it\n * quietly: the JSON Schema was still right, so only the TypeScript types lied.\n */\nexport interface OptionalSchema<T> extends Schema<T | undefined> {\n readonly [OPTIONAL]: true;\n}\n\nexport type AnySchema = Schema<any>;\n\nexport type Infer<S> = S extends Schema<infer T> ? T : never;\n\n/**\n * Collapses a type into one flat object.\n *\n * `ShapeOutput` builds its result as an intersection of two mapped types, one\n * required and one optional, and that intersection is what every hover, every\n * error message and every type assertion would otherwise show. The difference\n * is between an app reading `{ command: string; cwd?: string }` and reading two\n * mapped types joined by an ampersand.\n *\n * It also drops `readonly`, which the mapped types copy from the shape literal\n * — `s.object({ ... })` infers that literal as `const` to keep the keys, and a\n * tool has no reason to receive an immutable input because of how its schema\n * was written down.\n */\ntype Flatten<T> = { -readonly [K in keyof T]: T[K] };\n\ntype ShapeOutput<S extends Record<string, AnySchema>> = Flatten<\n {\n [K in keyof S as S[K] extends OptionalSchema<any> ? never : K]: Infer<S[K]>;\n } & {\n [K in keyof S as S[K] extends OptionalSchema<any> ? K : never]?: Infer<S[K]>;\n }\n>;\n\ninterface SchemaBuilder<T> extends Schema<T> {\n /**\n * The description is not documentation — it is the only prose the model gets\n * about a field, and it is the difference between a tool that is called\n * correctly and one that is not.\n */\n describe(description: string): this;\n /**\n * Strict mode has no notion of an omitted key: every property must appear in\n * `required`. So `optional()` emits a nullable union and the model is told to\n * send `null`, while the TypeScript type says `| undefined` and the parsed\n * value drops the key. The asymmetry is the point — it is what lets an app\n * write ordinary optional fields against an API that forbids them.\n */\n optional(): OptionalSchemaBuilder<T>;\n nullable(): SchemaBuilder<T | null>;\n}\n\ninterface OptionalSchemaBuilder<T> extends SchemaBuilder<T | undefined>, OptionalSchema<T> {}\n\n// --- the runtime ---------------------------------------------------------\n\n/**\n * What a builder actually is. `optional` and `nullable` are flags rather than\n * wrapper nodes so that `.nullable().optional()` cannot nest into something\n * whose emitted shape depends on which order they were called in.\n */\ntype Definition = {\n node: SchemaNode;\n description?: string;\n optional: boolean;\n nullable: boolean;\n};\n\ntype SchemaNode =\n | { kind: \"string\" }\n | { kind: \"number\" }\n | { kind: \"boolean\" }\n | { kind: \"literal\"; value: string | number | boolean }\n | { kind: \"enum\"; values: readonly string[] }\n | { kind: \"object\"; shape: Record<string, Definition> }\n | { kind: \"array\"; item: Definition }\n | { kind: \"union\"; members: readonly Definition[] };\n\ntype ParseResult = { ok: true; value: unknown } | { ok: false; errors: string[] };\n\n/** The public interface with the phantoms and the generic taken off. */\ninterface RuntimeSchema {\n toJSONSchema(): JSONSchema;\n parse(value: unknown): unknown;\n safeParse(value: unknown): ParseResult;\n describe(description: string): RuntimeSchema;\n optional(): RuntimeSchema;\n nullable(): RuntimeSchema;\n}\n\n/**\n * Definitions hang off the builders here rather than on the builders\n * themselves: a property, however obscurely named, is a property an app can\n * see, serialise or accidentally depend on, and `Schema<T>` promises exactly\n * three methods.\n */\nconst definitions = new WeakMap<object, Definition>();\n\nfunction definitionOf(schema: AnySchema): Definition {\n const definition = definitions.get(schema);\n if (!definition) {\n throw new Error(\"gemi/ai: expected a schema built with `s`, got a foreign object\");\n }\n return definition;\n}\n\n// --- emitting ------------------------------------------------------------\n\nfunction emit(definition: Definition): JSONSchema {\n const body = allowNull(emitNode(definition.node), definition.optional || definition.nullable);\n return definition.description ? { description: definition.description, ...body } : body;\n}\n\nfunction emitNode(node: SchemaNode): JSONSchema {\n switch (node.kind) {\n case \"string\":\n return { type: \"string\" };\n case \"number\":\n return { type: \"number\" };\n case \"boolean\":\n return { type: \"boolean\" };\n // `const` rather than a one-member `enum`, because a boolean literal has no\n // `enum` form and one branch that works for all three beats two that\n // disagree about what a literal is.\n case \"literal\":\n return { type: typeof node.value, const: node.value };\n case \"enum\":\n return { type: \"string\", enum: node.values };\n case \"array\":\n return { type: \"array\", items: emit(node.item) };\n case \"object\":\n return {\n type: \"object\",\n properties: Object.fromEntries(\n Object.entries(node.shape).map(([key, child]) => [key, emit(child)]),\n ),\n // Every declared property, optional ones included. This is the whole of\n // strict mode's bargain: the model is never allowed to omit a key, so\n // \"may be absent\" has to be spelled as \"may be null\" instead.\n required: Object.keys(node.shape),\n additionalProperties: false,\n };\n case \"union\":\n return { anyOf: node.members.map(emit) };\n }\n}\n\n/**\n * Widens a schema to admit `null` — for a `nullable()` field, and for the null\n * an `optional()` field tells the model to send in place of omitting the key.\n */\nfunction allowNull(base: JSONSchema, on: boolean): JSONSchema {\n if (!on) return base;\n // A union is already a list of alternatives; appending to it is flatter than\n // nesting an `anyOf` inside an `anyOf`, and reads the same to the model.\n if (base.anyOf) return { ...base, anyOf: [...base.anyOf, { type: \"null\" }] };\n // `enum` and `const` cannot carry the null themselves — `enum` here is\n // strings and numbers by declaration — so those get wrapped rather than\n // widened.\n if (base.enum || base.const !== undefined) return { anyOf: [base, { type: \"null\" }] };\n if (typeof base.type === \"string\") return { ...base, type: [base.type, \"null\"] };\n return { anyOf: [base, { type: \"null\" }] };\n}\n\n// --- parsing -------------------------------------------------------------\n\nfunction typeName(value: unknown): string {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"array\";\n return typeof value;\n}\n\n/**\n * What the value looked like. For a literal or an enum the *type* is usually\n * right and the value is wrong, and \"expected \\\"refund\\\", got string\" tells\n * whoever is reading the failed tool call nothing they did not know.\n */\nfunction saw(node: SchemaNode, value: unknown): string {\n if (typeof value === \"number\" && !Number.isFinite(value)) return String(value);\n if (node.kind === \"literal\" || node.kind === \"enum\") {\n const primitive =\n typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\";\n if (primitive) return JSON.stringify(value);\n }\n return typeName(value);\n}\n\nfunction wanted(definition: Definition): string {\n const node = definition.node;\n const base = (() => {\n switch (node.kind) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n return node.kind;\n case \"literal\":\n return JSON.stringify(node.value);\n case \"enum\":\n return `one of ${node.values.map((v) => JSON.stringify(v)).join(\" | \")}`;\n case \"array\":\n return \"array\";\n case \"object\":\n return \"object\";\n case \"union\":\n return \"one of the variants\";\n }\n })();\n return definition.optional || definition.nullable ? `${base} or null` : base;\n}\n\n/** `orders[2].total: ` — empty at the root, where a prefix would be noise. */\nfunction at(path: string): string {\n return path ? `${path}: ` : \"\";\n}\n\n/**\n * How well a value matches, used only to pick which union variant to blame.\n * A literal or an enum hit counts for far more than an ordinary field, because\n * that is what a discriminated union turns on: the variant whose `kind` matched\n * is the one the model meant, whatever else it got wrong.\n */\nfunction score(definition: Definition, value: unknown): number {\n if (value === null || value === undefined) {\n return definition.optional || definition.nullable ? 1 : 0;\n }\n const node = definition.node;\n switch (node.kind) {\n case \"string\":\n return typeof value === \"string\" ? 1 : 0;\n case \"number\":\n return typeof value === \"number\" ? 1 : 0;\n case \"boolean\":\n return typeof value === \"boolean\" ? 1 : 0;\n case \"literal\":\n return value === node.value ? 10 : 0;\n case \"enum\":\n return typeof value === \"string\" && node.values.includes(value) ? 10 : 0;\n case \"array\":\n return Array.isArray(value) ? 1 : 0;\n case \"object\": {\n if (typeof value !== \"object\" || Array.isArray(value)) return 0;\n const source = value as Record<string, unknown>;\n let total = 1;\n for (const [key, child] of Object.entries(node.shape)) {\n total += score(child, source[key]);\n }\n return total;\n }\n case \"union\":\n return node.members.reduce((best, member) => Math.max(best, score(member, value)), 0);\n }\n}\n\n/** `drop` is a key that should not appear in the parsed object at all. */\ntype Reading = { drop: boolean; value: unknown };\n\nfunction read(definition: Definition, value: unknown, path: string, errors: string[]): Reading {\n // `optional` is checked before `nullable`, so a schema that is both treats\n // null as \"absent\". They are not distinguishable on the wire: strict mode\n // gives the model one spelling for \"nothing\", and pretending otherwise would\n // mean `.nullable().optional()` silently kept a key the type says is\n // optional. What that trades away is the ability to say \"present and null\" on\n // a field that may also be absent — a distinction no model can express here.\n if (definition.optional && (value === null || value === undefined)) {\n return { drop: true, value: undefined };\n }\n if (definition.nullable && value === null) return { drop: false, value: null };\n return { drop: false, value: readNode(definition, value, path, errors) };\n}\n\nfunction readNode(definition: Definition, value: unknown, path: string, errors: string[]): unknown {\n const node = definition.node;\n const fail = () => {\n errors.push(`${at(path)}expected ${wanted(definition)}, got ${saw(node, value)}`);\n return undefined;\n };\n\n switch (node.kind) {\n case \"string\":\n return typeof value === \"string\" ? value : fail();\n case \"number\":\n // NaN and Infinity do not survive `JSON.stringify`, so a tool that\n // returns one produces a body the provider cannot be sent.\n return typeof value === \"number\" && Number.isFinite(value) ? value : fail();\n case \"boolean\":\n return typeof value === \"boolean\" ? value : fail();\n case \"literal\":\n return value === node.value ? value : fail();\n case \"enum\":\n return typeof value === \"string\" && node.values.includes(value) ? value : fail();\n case \"array\": {\n if (!Array.isArray(value)) return fail();\n return value.map((item, index) => {\n const element = read(node.item, item, `${path}[${index}]`, errors);\n return element.drop ? undefined : element.value;\n });\n }\n case \"object\": {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return fail();\n const source = value as Record<string, unknown>;\n const output: Record<string, unknown> = {};\n for (const [key, child] of Object.entries(node.shape)) {\n const element = read(child, source[key], path ? `${path}.${key}` : key, errors);\n if (!element.drop) output[key] = element.value;\n }\n // Unknown keys are DROPPED, not rejected. `additionalProperties: false`\n // has already told the model not to send them, so one arriving anyway is\n // a slip rather than an attack, and failing a whole tool call over a\n // stray field costs a turn to fix nothing. Dropping is also what keeps\n // `execute` from ever seeing a field its input type says cannot be there.\n return output;\n }\n case \"union\": {\n let best: { errors: string[]; score: number } | undefined;\n for (const member of node.members) {\n const attempt: string[] = [];\n const element = read(member, value, path, attempt);\n if (attempt.length === 0) return element.drop ? undefined : element.value;\n const points = score(member, value);\n if (!best || points > best.score) best = { errors: attempt, score: points };\n }\n // \"no match\" is useless when one field of a five-field variant was wrong.\n // Naming the closest variant and why it stopped is the difference between\n // a debuggable bad tool call and a shrug.\n errors.push(`${at(path)}no matching variant; closest: ${best.errors.join(\"; \")}`);\n return undefined;\n }\n }\n}\n\n/**\n * The one cast in this file, and the reason it has to exist: `OUTPUT` and\n * `OPTIONAL` are `declare const` unique symbols. They have no runtime\n * counterpart — they are inference channels — so no object that can actually be\n * constructed satisfies `Schema<T>` structurally. Funnelling every builder\n * through here means the lie is told once, in one place, and everything else in\n * the module is checked against the real declarations.\n */\nfunction make<T>(definition: Definition): SchemaBuilder<T> {\n return build(definition) as unknown as SchemaBuilder<T>;\n}\n\n/**\n * Builders are immutable: `describe`, `optional` and `nullable` each build a\n * fresh one from a copied definition. Mutating in place is the obvious\n * implementation and it is wrong — `const id = s.string()` reused in two\n * objects, described in one of them, would carry that description into the\n * other, and the only symptom is a model being told the wrong thing about a\n * field somewhere else.\n */\nfunction build(definition: Definition): RuntimeSchema {\n const runtime: RuntimeSchema = {\n toJSONSchema: () => emit(definition),\n parse(value) {\n const errors: string[] = [];\n const result = read(definition, value, \"\", errors);\n if (errors.length > 0) throw new Error(errors.join(\"; \"));\n return result.drop ? undefined : result.value;\n },\n safeParse(value) {\n const errors: string[] = [];\n const result = read(definition, value, \"\", errors);\n if (errors.length > 0) return { ok: false, errors };\n return { ok: true, value: result.drop ? undefined : result.value };\n },\n describe: (description) => build({ ...definition, description }),\n optional: () => build({ ...definition, optional: true }),\n // Clearing `optional` is not tidiness. `nullable()` returns a\n // `SchemaBuilder`, not an `OptionalSchemaBuilder`, so the key it describes\n // is required again in `ShapeOutput` — and a parse that still dropped it\n // would hand back an object missing a key its own type declares.\n nullable: () => build({ ...definition, nullable: true, optional: false }),\n };\n definitions.set(runtime, definition);\n return runtime;\n}\n\nfunction leaf(node: SchemaNode): Definition {\n return { node, optional: false, nullable: false };\n}\n\nexport const s: {\n string(): SchemaBuilder<string>;\n number(): SchemaBuilder<number>;\n boolean(): SchemaBuilder<boolean>;\n literal<const L extends string | number | boolean>(value: L): SchemaBuilder<L>;\n /** Modelled as a JSON Schema `enum`, which strict mode does support. */\n enum<const L extends readonly [string, ...string[]]>(values: L): SchemaBuilder<L[number]>;\n object<const S extends Record<string, AnySchema>>(shape: S): SchemaBuilder<ShapeOutput<S>>;\n array<const S extends AnySchema>(item: S): SchemaBuilder<Infer<S>[]>;\n /**\n * `anyOf` of object schemas, discriminated by a literal member. Left in\n * because tool outputs are frequently a success/failure pair, and modelling\n * that as one object with everything optional is worse for the model.\n */\n union<const S extends readonly [AnySchema, AnySchema, ...AnySchema[]]>(\n members: S,\n ): SchemaBuilder<Infer<S[number]>>;\n} = {\n string: () => make<string>(leaf({ kind: \"string\" })),\n number: () => make<number>(leaf({ kind: \"number\" })),\n boolean: () => make<boolean>(leaf({ kind: \"boolean\" })),\n literal: (value) => make<typeof value>(leaf({ kind: \"literal\", value })),\n enum: (values) => make<(typeof values)[number]>(leaf({ kind: \"enum\", values })),\n object: (shape) =>\n make<ShapeOutput<typeof shape>>(\n leaf({\n kind: \"object\",\n shape: Object.fromEntries(\n Object.entries(shape).map(([key, child]) => [key, definitionOf(child)]),\n ),\n }),\n ),\n array: (item) => make<Infer<typeof item>[]>(leaf({ kind: \"array\", item: definitionOf(item) })),\n // A union is legal wherever a property is, but not as the root of a\n // structured output: the provider wants an object there. That is the\n // provider's check to make, not this one's.\n union: (members) =>\n make<Infer<(typeof members)[number]>>(\n leaf({ kind: \"union\", members: members.map(definitionOf) }),\n ),\n};\n",
6
+ "import { createHmac, randomBytes, timingSafeEqual } from \"crypto\";\n\n/**\n * Signing for pending tool calls.\n *\n * A pending call travels through the browser and comes back — in stateless mode\n * the whole history does — so the server cannot trust that what it gets back is\n * what it sent. Without a signature the client asserts not just *that* a call\n * was approved but *what* was approved, and nothing would stop it from\n * returning `approve: true` against an input it rewrote on the way. Signing is\n * what makes the round trip safe, and it is why approvals need no server-side\n * storage at all.\n *\n * What is signed, and what deliberately is not:\n *\n * signed — `runId`, `toolCallId`, the tool `name`, the `kind` of pending call\n * and a canonical serialization of the input, plus a nonce, an\n * expiry, and — for a call a sub-agent asked — the `path` of\n * tool-call ids it is nested under.\n * not — the client's answer. `approve: true` / `approve: false` and a\n * question's output are the *point* of asking; a client that flips\n * its own answer has refused, not forged. What the signature buys is\n * that the answer is bound to the call the server actually made,\n * with the input the server actually saw.\n *\n * A verified token is not yet an answer the server may act on: it says the\n * question was asked, not that it is still open. `consumePendingCall` at the\n * bottom of this file spends the nonce, which is what makes an approval\n * single-use — see the note there for what that guarantee is worth.\n *\n * `kind` is in there for a specific attack: an `approval`-kind call is one the\n * *server* runs, so a client that reused its signature on the \"here is the\n * output\" arm of `ClientToolResult` would be fabricating a server tool's result\n * rather than approving it. Binding the kind makes that a forgery instead of a\n * shape the caller has to remember to check.\n */\n\n/** Everything the signature commits to. */\nexport type PendingCallClaims = {\n runId: string;\n toolCallId: string;\n name: string;\n kind: \"approval\" | \"question\" | \"client\";\n input: unknown;\n /**\n * The chain of tool-call ids the call is nested under, outermost first.\n * Absent — or empty, which means the same thing — for a top-level call.\n *\n * A sub-agent's question reaches the user through its parent's pending list,\n * so `toolCallId` stops being an address on its own: two sub-runs under two\n * different tools can each hold a call the outer run never made. Binding the\n * path is what stops a token minted for a call nested under tool call X from\n * being replayed as a top-level call, or as one nested under Y.\n */\n path?: string[];\n};\n\nexport type SignOptions = {\n /** Overrides `process.env.SECRET`. Exists for tests; apps use the app key. */\n secret?: string;\n /**\n * Default 24 hours. An approval waits on a human, and humans go to lunch —\n * a short expiry turns \"I approved it after standup\" into an unexplained\n * failure. Long enough to survive a working day, short enough that a token\n * lifted from a log is not useful next month.\n */\n ttlMs?: number;\n /** Injected clock, so the expiry path is testable without waiting. */\n now?: number;\n};\n\nexport type VerifyOptions = {\n secret?: string;\n now?: number;\n};\n\n/**\n * A discriminated result rather than a boolean, because the two failures are\n * different events: `expired` is a sentence to show the user, `forged` is worth\n * logging and possibly alerting on. Collapsing them loses the only signal that\n * says someone is probing.\n */\nexport type VerifyResult =\n | { ok: true; runId: string; nonce: string; expiresAt: number }\n | { ok: false; reason: \"malformed\" | \"expired\" | \"forged\" };\n\nconst VERSION = \"agt1\";\nconst DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;\n\nfunction secretKey(override?: string): string {\n const secret = override ?? process.env.SECRET;\n if (!secret) {\n // Refusing is the only safe answer. A fallback constant would make every\n // approval in every deployment forgeable by anyone who read this file, and\n // it would do it silently — the feature would appear to work.\n throw new Error(\n \"Signing a pending tool call needs an app secret. Set SECRET in the environment.\",\n );\n }\n return secret;\n}\n\n/**\n * Serializes a value so that the same value always produces the same string.\n *\n * `JSON.stringify` is not enough: it preserves insertion order, so an input\n * that made a round trip through a client — parsed and re-serialized, with the\n * keys in whatever order the parser produced — would hash differently and a\n * legitimate approval would come back looking forged. Keys are sorted,\n * `undefined` members are dropped (they do not survive JSON anyway), and arrays\n * keep their order because in an array order *is* the value.\n */\nexport function canonicalize(value: unknown): string {\n if (value === null || typeof value !== \"object\") {\n return JSON.stringify(value) ?? \"null\";\n }\n if (Array.isArray(value)) {\n return `[${value.map(canonicalize).join(\",\")}]`;\n }\n const record = value as Record<string, unknown>;\n const keys = Object.keys(record)\n .filter((key) => record[key] !== undefined)\n .sort();\n return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalize(record[key])}`).join(\",\")}}`;\n}\n\n/**\n * Length-prefixed rather than delimiter-joined. A separator is a place for two\n * different claim sets to hash the same — `runId: \"a\", toolCallId: \"b|c\"` and\n * `runId: \"a|b\", toolCallId: \"c\"` — and while neither field contains the\n * separator today, that is a property of the id generator, not of this code.\n */\nfunction payload(fields: string[]): string {\n return fields.map((field) => `${field.length}:${field}`).join(\"\");\n}\n\nfunction mac(secret: string, fields: string[]): Buffer {\n return createHmac(\"sha256\", secret).update(payload(fields)).digest();\n}\n\n/**\n * The path is appended, and only when there is one.\n *\n * Byte-identical output for a call with no path is the whole requirement here:\n * every approval already in flight was minted from the eight fields below, and\n * a ninth field carrying `\"[]\"` or `\"undefined\"` would invalidate all of them\n * on deploy — the user who clicked Approve before the release would be told\n * their answer was forged. So an absent path adds nothing at all, and an empty\n * array is treated as absent because it says the same thing.\n *\n * `payload` is length-prefixed, so appending a field cannot collide with a\n * longer value in the one before it; that is why this can be an append rather\n * than a new version tag.\n */\nfunction claimFields(claims: PendingCallClaims, nonce: string, expiresAt: number): string[] {\n const fields = [\n VERSION,\n claims.runId,\n claims.toolCallId,\n claims.name,\n claims.kind,\n nonce,\n String(expiresAt),\n canonicalize(claims.input),\n ];\n if (claims.path && claims.path.length > 0) {\n fields.push(canonicalize(claims.path));\n }\n return fields;\n}\n\nconst encode = (value: string) => Buffer.from(value, \"utf8\").toString(\"base64url\");\nconst decode = (value: string) => Buffer.from(value, \"base64url\").toString(\"utf8\");\n\n/** `agt1.<runId>.<nonce>.<expiry>.<mac>`, all base64url or base36. */\nexport function signPendingCall(claims: PendingCallClaims, options: SignOptions = {}): string {\n const secret = secretKey(options.secret);\n const now = options.now ?? Date.now();\n const expiresAt = now + (options.ttlMs ?? DEFAULT_TTL_MS);\n const nonce = randomBytes(12).toString(\"base64url\");\n const signature = mac(secret, claimFields(claims, nonce, expiresAt)).toString(\"base64url\");\n return [VERSION, encode(claims.runId), nonce, expiresAt.toString(36), signature].join(\".\");\n}\n\n/**\n * The metadata a signature carries in the clear.\n *\n * `Agent` needs the issuing `runId` before it can verify anything: the call was\n * signed under the run that made it, and the turn answering it is a *new* run\n * with a new id. Reading it out of the token is safe because the token's own\n * MAC covers it — a client that edits the runId here fails verification, so\n * this is \"which run does this claim to belong to\", not \"which run does the\n * client say it belongs to\".\n */\nexport function readSignature(\n signature: string,\n): { runId: string; nonce: string; expiresAt: number } | null {\n return readToken(signature, VERSION);\n}\n\n/**\n * The version tag is checked here and nowhere else, which is what keeps the\n * two token kinds apart: a parked-run record presented where a pending call's\n * signature is expected fails as malformed before its MAC is even looked at,\n * and the other way round. Their claim sets are different lengths and would\n * not collide anyway, but a tag makes that a rule rather than an accident of\n * the field count.\n */\nfunction readToken(\n signature: string,\n version: string,\n): { runId: string; nonce: string; expiresAt: number } | null {\n const parts = signature.split(\".\");\n if (parts.length !== 5 || parts[0] !== version) {\n return null;\n }\n const expiresAt = Number.parseInt(parts[3], 36);\n if (!Number.isFinite(expiresAt)) {\n return null;\n }\n try {\n return { runId: decode(parts[1]), nonce: parts[2], expiresAt };\n } catch {\n return null;\n }\n}\n\nexport function verifyPendingCall(\n signature: string,\n claims: PendingCallClaims,\n options: VerifyOptions = {},\n): VerifyResult {\n const secret = secretKey(options.secret);\n const parsed = readSignature(signature);\n if (!parsed) {\n return { ok: false, reason: \"malformed\" };\n }\n\n const presented = Buffer.from(signature.split(\".\")[4], \"base64url\");\n const expected = mac(secret, claimFields(claims, parsed.nonce, parsed.expiresAt));\n // `timingSafeEqual` throws on a length mismatch, and a wrong length is\n // already a public fact about the token — nothing is leaked by checking it\n // first, and everything is leaked by comparing the bytes with `===`.\n if (presented.length !== expected.length || !timingSafeEqual(presented, expected)) {\n return { ok: false, reason: \"forged\" };\n }\n\n // Expiry is checked *after* the MAC on purpose: only a genuine token can be\n // \"expired\". Reporting a forgery as expired would tell the UI to say \"your\n // approval timed out\" to someone who was tampering.\n if ((options.now ?? Date.now()) > parsed.expiresAt) {\n return { ok: false, reason: \"expired\" };\n }\n\n return { ok: true, runId: parsed.runId, nonce: parsed.nonce, expiresAt: parsed.expiresAt };\n}\n\n// --- parked sub-runs -----------------------------------------------------\n\n/**\n * What a parked sub-run's record is signed over.\n *\n * `ToolCallPart.nested` is the parent's own record of where a sub-run stopped,\n * and in stateless mode it makes the same trip through the browser a pending\n * call does. The next turn *runs a tool* on the strength of that record — the\n * tool is re-entered because the record says a sub-run under it is waiting on\n * the question being answered — so an unsigned record lets the client choose\n * which tools run, with what input, before any answer is verified. A MAC over\n * what the server actually recorded is what makes the record safe to carry.\n *\n * Only a parked record is signed, because only a parked record executes\n * anything: a finished sub-run is replayed out of its transcript and spends\n * nothing, and a client that forges one has fed its own tool a made-up answer,\n * which a client-carried history already allows everywhere.\n *\n * Deliberately not signed: the transcript. The sub-run resumes from messages\n * the client carried, exactly as the parent does in stateless mode, and the\n * same argument applies — what the signature pins is that the server parked\n * *here*, on *these* calls, with *this* input, and not what was said on the\n * way.\n */\nexport type NestedRunClaims = {\n /** The root run's id, the one every pending call of the tree is minted under. */\n runId: string;\n /**\n * Tool-call ids from the root down to and including the call the record\n * hangs off. A sub-run's id is not an address on its own for the same reason\n * a nested call's is not: two sub-runs under two different tools can carry\n * the same one.\n */\n path: string[];\n /** The sub-run's own id, so a record cannot be moved between sub-runs. */\n nestedRunId: string;\n /** The tool calls the sub-run is waiting on: every call left open in its transcript. */\n open: string[];\n /**\n * The input the tool that parked was running on, as the transcript carries\n * it. Re-entry runs the tool body with the input the history holds, and the\n * history is the client's — so a record that pinned where the sub-run parked\n * but not what its tool was given would let the client keep the run and\n * rewrite the arguments to anything the schema accepts. The same bargain a\n * pending call makes: the input executed is the input signed.\n */\n input: unknown;\n};\n\nconst NESTED_VERSION = \"agn1\";\n\nfunction nestedFields(claims: NestedRunClaims, nonce: string, expiresAt: number): string[] {\n return [\n NESTED_VERSION,\n claims.runId,\n canonicalize(claims.path),\n claims.nestedRunId,\n nonce,\n String(expiresAt),\n // A set, so it is sorted: the ids are read back out of a transcript the\n // client re-serialized, and message order is not part of the claim.\n canonicalize([...claims.open].sort()),\n canonicalize(claims.input),\n ];\n}\n\n/**\n * Same shape as a pending call's token, so the same reader serves both — nonce\n * included, and the nonce is spent, by `consumeNestedRun` below. A verified\n * record is permission to run the tool it hangs off, and the tool body runs\n * before the sub-run gets to look at the answer's own nonce; a record that\n * could be presented twice would run the body twice before anything refused\n * the replay. Every park mints a fresh record, so spending one costs a\n * legitimate re-park nothing.\n */\nexport function signNestedRun(claims: NestedRunClaims, options: SignOptions = {}): string {\n const secret = secretKey(options.secret);\n const now = options.now ?? Date.now();\n const expiresAt = now + (options.ttlMs ?? DEFAULT_TTL_MS);\n const nonce = randomBytes(12).toString(\"base64url\");\n const signature = mac(secret, nestedFields(claims, nonce, expiresAt)).toString(\"base64url\");\n return [NESTED_VERSION, encode(claims.runId), nonce, expiresAt.toString(36), signature].join(\".\");\n}\n\n/**\n * The run that verifies a record is never the run that minted it — the turn\n * answering a question is a new run with a new id — so the minting run's id is\n * read out of the token rather than asked of the caller, which has no other\n * source for it. The MAC covers it, so a client that edits the id in the clear\n * fails here rather than being believed.\n */\nexport function verifyNestedRun(\n signature: string,\n claims: Omit<NestedRunClaims, \"runId\">,\n options: VerifyOptions = {},\n): VerifyResult {\n const secret = secretKey(options.secret);\n const parsed = readToken(signature, NESTED_VERSION);\n if (!parsed) {\n return { ok: false, reason: \"malformed\" };\n }\n\n const presented = Buffer.from(signature.split(\".\")[4], \"base64url\");\n const expected = mac(\n secret,\n nestedFields({ ...claims, runId: parsed.runId }, parsed.nonce, parsed.expiresAt),\n );\n if (presented.length !== expected.length || !timingSafeEqual(presented, expected)) {\n return { ok: false, reason: \"forged\" };\n }\n\n // A parked record outlives its usefulness with the answers it exists to\n // deliver: those expire on the pending call's TTL, and a record older than\n // that can route nothing that would still verify.\n if ((options.now ?? Date.now()) > parsed.expiresAt) {\n return { ok: false, reason: \"expired\" };\n }\n\n return { ok: true, runId: parsed.runId, nonce: parsed.nonce, expiresAt: parsed.expiresAt };\n}\n\n// --- single use ----------------------------------------------------------\n\n/**\n * Nonces already spent, mapped to the moment they stop mattering.\n *\n * The MAC makes a token unforgeable; it does not make it single-use. Without\n * this a captured signature approves the same call again every time it is\n * presented, because a token that carries its own `runId` is a token that\n * asserts its own binding — which is no binding at all. Verifying tells you the\n * server once asked this exact question; spending the nonce is what says nobody\n * has answered it yet.\n *\n * Deliberately in memory, and deliberately not a hard guarantee:\n *\n * bounded — an entry lives at most as long as the token's TTL, and the sweep\n * below is amortized O(1), so the map is bounded by the approvals\n * actually issued in one TTL window rather than by uptime.\n * local — one process. A second replica has never seen the nonce and will\n * accept it, so this closes the replay window rather than sealing\n * it. That is still worth having and it fails open, which is the\n * only direction a cache may fail: a lost registry costs a replay,\n * never a legitimate approval that stops working.\n *\n * The stronger guard is the app's own message store: once a call has a result\n * next to it, the call is no longer open and the answer has nothing to attach\n * to. This is what stands in for that in stateless mode, where the history the\n * client returns can be rewound to before the result existed.\n */\nconst spent = new Map<string, number>();\n\n/** Sweep when the map has grown past this, so sweeping costs O(1) per insert\n * amortized instead of walking every entry on every approval. */\nlet sweepAt = 1024;\n\nfunction sweep(now: number) {\n for (const [nonce, expiresAt] of spent) {\n if (expiresAt <= now) spent.delete(nonce);\n }\n sweepAt = Math.max(1024, spent.size * 2);\n}\n\n/**\n * Spends a signature's nonce. `false` means it was already spent — the answer\n * is a replay and must not be acted on.\n *\n * Separate from `verifyPendingCall` rather than folded into it, because verify\n * is a pure question a caller may want to ask twice (logging a forgery, say)\n * and this one is a state change that must happen exactly once per answer.\n */\nexport function consumePendingCall(signature: string, options: VerifyOptions = {}): boolean {\n return spend(readSignature(signature), options);\n}\n\n/**\n * Spends a parked-run record's nonce, on the same registry and the same terms.\n * `false` means the record has already re-entered its tool once — the turn is\n * a replay of a history from before the answer was delivered, and the body\n * must not run again on it.\n */\nexport function consumeNestedRun(signature: string, options: VerifyOptions = {}): boolean {\n return spend(readToken(signature, NESTED_VERSION), options);\n}\n\nfunction spend(\n parsed: { nonce: string; expiresAt: number } | null,\n options: VerifyOptions,\n): boolean {\n if (!parsed) return false;\n const now = options.now ?? Date.now();\n if (spent.size >= sweepAt) sweep(now);\n const spentUntil = spent.get(parsed.nonce);\n // A record past its own expiry binds nothing: the token it refers to fails\n // verification on its own, so holding the nonce would only grow the map.\n if (spentUntil !== undefined && spentUntil > now) return false;\n spent.set(parsed.nonce, parsed.expiresAt);\n return true;\n}\n",
7
+ "import type { AgentError, AgentStreamFrame } from \"../types\";\n\nconst encoder = new TextEncoder();\n\n/**\n * One frame, one SSE event.\n *\n * `id:` carries the frame's `seq`, which is what makes the browser's own\n * `Last-Event-ID` the right cursor on reconnect — the transport asks the\n * question the run already knows how to answer, and the client never has to\n * track a position of its own.\n */\nexport function encodeFrame(frame: AgentStreamFrame): string {\n return `id: ${frame.seq}\\ndata: ${JSON.stringify(frame.event)}\\n\\n`;\n}\n\n/**\n * How long a connection may sit idle before a comment line goes out.\n *\n * The nearest ceiling is not a proxy but our own server: Bun's `idleTimeout`\n * counts socket silence, a streaming body included, and gemi runs at its\n * 10-second default unless `SERVER_IDLE_TIMEOUT` says otherwise. A comment\n * line every 25 seconds was measured to lose the connection at 12; every 5\n * keeps it open, with room for a write that lands late. Azure App Service's\n * front end, at about 230 seconds, is the far ceiling, and 5 clears it by the\n * same margin. A thousand quiet streams cost two hundred thirteen-byte writes\n * a second, which is nothing. Both encoders read this one value, so the two\n * cannot drift apart.\n */\nexport const SSE_KEEPALIVE_INTERVAL_MS = 5_000;\n\n/**\n * The comment line itself. A line starting with `:` is a comment under the SSE\n * spec: every parser on our side skips it, and so does the browser's own\n * `EventSource`.\n */\nexport const SSE_KEEPALIVE = \": keepalive\\n\\n\";\n\n/**\n * Writes a keepalive whenever the stream has been silent for the interval.\n *\n * Armed on creation because the silence before the first frame is real\n * silence too — a model thinking is the common case. `touch()` after every\n * frame is what makes it measure silence rather than elapsed time; `stop()`\n * on close or cancel is what keeps a finished stream from holding a timer.\n *\n * The write is guarded because a cancel can land between the timer firing and\n * the enqueue, and a closed controller throws. There is nothing to do about\n * that except stop. `arm` checks `stopped` too, so a `touch()` that arrives\n * after `stop()` cannot hand a finished stream a timer for one more interval.\n */\nexport function sseKeepalive(\n controller: ReadableStreamDefaultController<Uint8Array>,\n intervalMs = SSE_KEEPALIVE_INTERVAL_MS,\n): { touch(): void; stop(): void } {\n let timer: ReturnType<typeof setTimeout> | null = null;\n let stopped = false;\n\n const arm = () => {\n if (stopped) return;\n if (timer !== null) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = null;\n if (stopped) return;\n try {\n controller.enqueue(encoder.encode(SSE_KEEPALIVE));\n } catch {\n stop();\n return;\n }\n arm();\n }, intervalMs);\n };\n\n const stop = () => {\n stopped = true;\n if (timer !== null) clearTimeout(timer);\n timer = null;\n };\n\n arm();\n return { touch: arm, stop };\n}\n\nexport function sseHeaders(): Record<string, string> {\n return {\n \"Content-Type\": \"text/event-stream\",\n // `no-transform` as well as `no-store`: a proxy that gzips or rechunks the\n // body is a proxy that buffers it, and a buffered token stream arrives all\n // at once, which is the same as not streaming at all.\n \"Cache-Control\": \"no-store, no-transform\",\n Connection: \"keep-alive\",\n // nginx's own name for the same thing.\n \"X-Accel-Buffering\": \"no\",\n };\n}\n\n/**\n * Encodes an async iterable of frames as an SSE response.\n *\n * Pulls one frame per `pull` rather than looping inside `start`: a `start` that\n * awaits the whole run does not resolve until the run is over, and the stream\n * is not readable until it does — which would turn every streamed answer into a\n * single delivery at the end.\n */\nexport function sseResponse(frames: AsyncIterable<AgentStreamFrame>, status = 200): Response {\n const iterator = frames[Symbol.asyncIterator]();\n let lastSeq = -1;\n let keepalive!: ReturnType<typeof sseKeepalive>;\n\n const body = new ReadableStream<Uint8Array>({\n start(controller) {\n keepalive = sseKeepalive(controller);\n },\n async pull(controller) {\n try {\n const next = await iterator.next();\n if (next.done) {\n keepalive.stop();\n controller.close();\n return;\n }\n lastSeq = next.value.seq;\n controller.enqueue(encoder.encode(encodeFrame(next.value)));\n keepalive.touch();\n } catch (err) {\n // Past the headers there is no status left to fail with, so the reason\n // goes out as the last event. Closing silently would be\n // indistinguishable from a run that finished, which is the one thing a\n // reattaching client must not be told by mistake.\n const event = { type: \"error\", error: toAgentError(err) } as const;\n keepalive.stop();\n controller.enqueue(encoder.encode(encodeFrame({ seq: lastSeq + 1, event })));\n controller.close();\n }\n },\n cancel(reason) {\n // The client went away. Let the generator unwind so its `finally` runs\n // and it stops waiting on frames nobody will read.\n keepalive.stop();\n void iterator.return?.(reason);\n },\n });\n\n return new Response(body, { status, headers: sseHeaders() });\n}\n\n// `unknown` rather than a new code: `AgentErrorCode` is the wire contract and\n// belongs to the model's failures, not to the transport's. The message names\n// the cursor, which is what a client can actually act on.\nfunction toAgentError(err: unknown): AgentError {\n return {\n code: \"unknown\",\n message: err instanceof Error ? err.message : String(err),\n retryable: false,\n };\n}\n",
8
+ "import type { HttpRequest } from \"../http\";\nimport type {\n AgentProvider,\n ProviderToolNamespace,\n ProviderToolSpec,\n} from \"./AgentProvider\";\nimport type { Infer, Schema } from \"./Schema\";\nimport {\n consumeNestedRun,\n consumePendingCall,\n readSignature,\n signNestedRun,\n signPendingCall,\n verifyNestedRun,\n verifyPendingCall,\n} from \"./signing\";\nimport { sseKeepalive } from \"./store/sse\";\nimport type {\n AgentError,\n AgentMessage,\n AgentStreamEvent,\n AgentStreamFrame,\n ClientToolResult,\n ClientTurn,\n FinishReason,\n NestedRun,\n PendingToolCall,\n ToolCallPart,\n ToolResultPart,\n ToolShapes,\n Usage,\n} from \"./types\";\n\n// --- tools ---------------------------------------------------------------\n\n/**\n * Everything a tool needs from the request it is running inside.\n *\n * Tools are created once at module scope and shared by every request, so they\n * cannot close over a user or an abort signal — and anything mutable stored on\n * the tool itself would leak across requests. That is why the run's state\n * arrives as an argument instead: the tool stays a singleton and the context is\n * per call.\n */\nexport interface ToolContext {\n req: HttpRequest<any, any>;\n runId: string;\n threadId?: string;\n toolCallId: string;\n /**\n * Aborted when the user calls `stop()`. Not when the connection drops — a run\n * outlives the request that started it so a refresh can reattach, which means\n * a disconnect is no longer a signal to stop working.\n */\n signal: AbortSignal;\n /** Which step of the tool loop this is, starting at 1. */\n step: number;\n /**\n * How deep this tool is inside nested runs: 0 at the top, 1 inside a tool of\n * an agent started by `runAgent`, and so on. Compared against `maxDepth` on\n * `Agent.create` so a cycle — agent A with a tool that runs agent A — fails\n * with a sentence to read instead of exhausting the stack.\n */\n readonly depth: number;\n /**\n * True when this tool is being re-entered after a sub-agent it started asked\n * the user something and the user answered.\n *\n * READ THE `runAgent` NOTE BEFORE USING IT. This is the flag that lets a tool\n * tell a first attempt from a replay, and it exists because there is nothing\n * to tell it otherwise: the tool body ran once already.\n */\n readonly resumed: boolean;\n /**\n * Runs another agent from inside this tool, wired into the parent run.\n *\n * A tool can already drive a sub-agent by hand — make one, iterate it, yield\n * its events as progress. What this does that hand-rolling cannot is join the\n * two runs: the sub-run inherits `ctx.signal` so the parent's `stop()` reaches\n * it; every sub-run event is re-emitted on the parent stream as\n * `nested-event`, numbered in the parent's `seq`, so `/attach` replay stays\n * correct through the nesting; the sub-run's usage rolls into the parent's;\n * its transcript is recorded on the parent's `ToolCallPart.nested`; and the\n * depth and agent-name chain travel with it, so a cycle fails fast.\n *\n * ESCALATION. If the sub-run ends `awaiting-input` — it has an approval tool,\n * or it asked a question — `onPending: \"escalate\"` (the default) throws a\n * `PendingEscalation` carrying the inner pending calls, which the parent run\n * collects exactly like pending calls of its own: the parent ends\n * `awaiting-input` with the sub-agent's questions in its list, and the client\n * answers them with the same `approve()` / `answer()` it uses for any other.\n * `onPending: \"deny\"` refuses them instead and lets the sub-run finish.\n *\n * THE COST, WHICH IS REAL AND WHICH YOU MUST DESIGN AROUND. A JS async\n * generator cannot be suspended across a turn boundary: `awaiting-input` is\n * terminal for the stream, the next turn re-enters the loop at the top and\n * rebuilds its state from the message history, and a paused generator is not\n * in that history and cannot be put there. So an escalating tool is\n * RE-ENTERED FROM THE TOP on the next turn, with `ctx.resumed === true`, and\n * `runAgent` is memoized by call index within the tool call: the Nth\n * `runAgent` of a tool call that already completed on an earlier turn returns\n * its persisted result immediately, calling no provider and running no\n * sub-tool, and only the sub-run that escalated actually continues.\n *\n * The index is the only key there is, so a body whose `runAgent` calls sit in\n * a branch or a loop can produce a different sequence on the replay and make\n * index N mean two different things. That is checked, not trusted: a mismatch\n * fails the tool call with a sentence naming both sub-runs, because pairing a\n * user's answer with a sub-run they never saw would be invisible.\n *\n * Which means: CODE BEFORE AN ESCALATING `runAgent` RUNS AGAIN ON RESUME.\n * Side effects there are repeated. Put your side effects after the\n * `runAgent`, or make them idempotent, or branch on `ctx.resumed`. This is\n * inherent to replay and it is the same bargain the outer tool loop already\n * makes; it is written here in plain words rather than solved with a\n * checkpoint API, because that is a much larger feature than this one.\n */\n runAgent<A extends AnyAgent>(\n agent: A,\n params?: RunAgentParams,\n ): Promise<NestedRunResult>;\n}\n\n/** What `ctx.runAgent` is given. `messages` and `prompt` are alternatives. */\nexport interface RunAgentParams {\n /** Prior turns for the sub-agent. Starts empty when omitted. */\n messages?: AgentMessage[];\n /** Sugar for a single user turn — the common case, and the whole message\n * list when there is no sub-conversation to continue. */\n prompt?: string;\n /** Appended to the sub-agent's own `instructions`, for this run only. */\n instructions?: string;\n /** Shown on the nested transcript, e.g. \"researching pricing\". */\n label?: string;\n /**\n * What to do when the sub-run ends `awaiting-input`. `\"escalate\"` (the\n * default) throws `PendingEscalation` so the question reaches the user;\n * `\"deny\"` refuses every pending call and lets the sub-run finish, which is\n * what a tool wants when the sub-agent is meant to be autonomous.\n *\n * `\"deny\"` is refused *in place*, inside the sub-run's own loop, so the\n * sub-agent is told it cannot ask and takes another step rather than ending\n * parked — and it is inherited by everything below, so a grandchild asking to\n * escalate is overruled too. A promise that nothing from this subtree reaches\n * the user is only worth making if the whole subtree keeps it.\n */\n onPending?: \"escalate\" | \"deny\";\n}\n\n/**\n * What a completed sub-run gives back.\n *\n * `nested` is the transcript as it is recorded on the parent's tool-call part,\n * so a tool that wants to summarize what its sub-agent did reads the same\n * object the UI renders rather than a second representation of it.\n */\nexport interface NestedRunResult<O = unknown> {\n runId: string;\n /** The sub-agent's name — carried so a caller that fans out over several\n * agents can tell the results apart without tracking the order. */\n agent: string;\n messages: AgentMessage[];\n finishReason: FinishReason;\n usage: Usage;\n /** Set when the sub-agent declares an `output` schema and the run finished. */\n output?: O;\n /** The record written to the parent's `ToolCallPart.nested`. */\n nested: NestedRun;\n}\n\n/**\n * Thrown by `ctx.runAgent` when a sub-run ends `awaiting-input`.\n *\n * An exception rather than a return value because it must not be mistaken for\n * an answer: a tool that ignored an `{ escalated: true }` field would return a\n * result to the model as if the sub-agent had finished, and the model would act\n * on an answer nobody gave. `executeTool` lets this one propagate instead of\n * turning it into a `tool_error`, and the step loop collects `pending` exactly\n * like the pending calls it produced itself.\n *\n * `path` is the chain of tool-call ids down to the escalating call; each entry\n * of `pending` already carries its own full path, and this is the prefix they\n * share.\n */\nexport class PendingEscalation extends Error {\n readonly pending: PendingToolCall[];\n readonly path: string[];\n /** The sub-run that parked, so the parent can record its transcript before\n * ending the turn — an escalation is a pause, not a lost run. */\n readonly nested: NestedRun;\n\n constructor(params: { pending: PendingToolCall[]; path: string[]; nested: NestedRun }) {\n super(\n `A nested agent run is waiting on the user for ${params.pending.length} tool call(s).`,\n );\n this.name = \"PendingEscalation\";\n this.pending = params.pending;\n this.path = params.path;\n this.nested = params.nested;\n }\n}\n\n/**\n * A tool either resolves once, or yields progress and then returns.\n *\n * The generator form exists because a tool that takes twenty seconds is the\n * normal case, not the exotic one, and a chat UI that shows nothing for twenty\n * seconds looks broken. Yields become `tool-progress` events; the return value\n * is the result the model sees.\n */\nexport type ToolExecute<Input, Output, Progress = unknown> = (\n input: Input,\n ctx: ToolContext,\n) => Promise<Output> | AsyncGenerator<Progress, Output, void>;\n\ntype ToolDefinitionBase<Name extends string, Input, Output> = {\n name: Name;\n /** The model's only description of when to reach for this. */\n description: string;\n inputSchema: Schema<Input>;\n /**\n * Optional for a server tool, required for a client one — there it is what\n * the answer is validated against before the model sees it, and what types\n * the value the browser has to produce.\n */\n outputSchema?: Schema<Output>;\n /**\n * Withholds this tool's parameter schema from the request: the model is shown\n * only the name and description, and pulls the rest in with the provider's\n * `tool_search` when it decides it wants the tool (`defer_loading` on the\n * wire).\n *\n * It says nothing about who runs the tool or when — it is a statement about\n * the prompt, not about execution. What it buys is context: an agent with\n * forty tools spends most of its prompt on schemas for tools it will not\n * call, and deferred ones load at the end of the window, so adding one\n * mid-conversation does not invalidate the cache.\n *\n * Purely an optimization, and gemi treats it as one: a provider that cannot\n * do tool search is sent the schemas inline, and the agent behaves the same.\n * So it is safe to set on a model that does not support it, and worth setting\n * only for tools that are large, numerous, or rarely reached.\n */\n deferred?: boolean;\n};\n\n/**\n * Two ways a tool's result comes to exist, and neither changes the shape of the\n * conversation.\n *\n * `execute` — the server runs it.\n * `answeredBy: \"client\"` — the browser produces the result: a question for the\n * user, or something only the page can do. The stream ends `awaiting-input`\n * and the answer arrives as an ordinary turn.\n *\n * `requiresApproval` applies to the first: the server can run the tool, but\n * asks first. That, too, ends the stream `awaiting-input`, which is the whole\n * reason there is no second endpoint — an approval is a question whose answer\n * happens to be yes or no.\n */\nexport type ToolDefinition<Name extends string, Input, Output, Progress = never> =\n | (ToolDefinitionBase<Name, Input, Output> & {\n answeredBy?: \"server\";\n execute: ToolExecute<Input, Output, Progress>;\n requiresApproval?: boolean;\n })\n | (ToolDefinitionBase<Name, Input, Output> & {\n answeredBy: \"client\";\n outputSchema: Schema<Output>;\n execute?: never;\n /** Meaningless here: the client answering *is* the approval. */\n requiresApproval?: never;\n });\n\n/**\n * `Progress` is inferred, never written down.\n *\n * It comes from the yield type of an `execute` that is an async generator, and\n * from nothing else — a tool that returns a promise gets `never`, which is the\n * honest statement that it cannot yield and is what makes\n * `ToolShapesOf`'s `progress` member safe to emit unconditionally. It is\n * carried as a fourth parameter rather than derived on demand because it has to\n * survive the trip through `ToolNamespace`, `FlattenTools` and `ToolShapesOf`\n * into the browser, and only a type argument does that.\n *\n * Structurally it lives on `execute`, which is optional, and which is also why\n * `AnyAgentTool` must pass `any` here: `Progress` sits covariantly inside\n * `AsyncGenerator<Progress, …>`, so a bound of `never` would make every\n * yielding tool fail the `Extract` in `ToolShapesOf` and silently vanish from\n * the shapes.\n */\nexport class AgentTool<\n Name extends string = string,\n Input = unknown,\n Output = unknown,\n Progress = never,\n> {\n readonly name: Name;\n readonly description: string;\n readonly inputSchema: Schema<Input>;\n readonly outputSchema?: Schema<Output>;\n readonly requiresApproval: boolean;\n readonly deferred: boolean;\n readonly answeredBy: \"server\" | \"client\";\n /**\n * There is deliberately no `namespace` here. A tool is a module-scope\n * singleton, so a field naming its group would hold whichever agent\n * constructed its namespace last and report that to every other one — the\n * same global-effect-from-a-local-declaration that `ToolNamespace.deferred`\n * avoids. Where a tool sits is a property of the agent, and it lives on the\n * agent's `ResolvedTool`.\n */\n readonly execute?: ToolExecute<Input, Output, Progress>;\n\n private constructor(params: ToolDefinition<Name, Input, Output, Progress>) {\n this.name = params.name;\n this.description = params.description;\n this.inputSchema = params.inputSchema;\n this.outputSchema = params.outputSchema;\n this.requiresApproval = params.requiresApproval === true;\n this.deferred = params.deferred === true;\n this.answeredBy = params.answeredBy === \"client\" ? \"client\" : \"server\";\n this.execute = params.execute ?? undefined;\n }\n\n /**\n * `const` on the params is what preserves `name` as a literal, which is what\n * lets the browser discriminate a tool part by name.\n */\n static create<const Name extends string, Input, Output, Progress = never>(\n params: ToolDefinition<Name, Input, Output, Progress>,\n ): AgentTool<Name, Input, Output, Progress> {\n return new AgentTool(params);\n }\n\n /**\n * Sugar for the common client tool: the agent asks the user something and\n * waits. Equivalent to `answeredBy: \"client\"` with an input schema of one\n * prompt field.\n */\n static ask<const Name extends string, Output>(params: {\n name: Name;\n description: string;\n outputSchema: Schema<Output>;\n }): AgentTool<Name, { question: string }, Output> {\n return AgentTool.create({\n name: params.name,\n description: params.description,\n inputSchema: questionSchema,\n outputSchema: params.outputSchema,\n answeredBy: \"client\",\n });\n }\n}\n\n/**\n * The one schema this module owns, rather than one built with `s`.\n *\n * `Schema<T>` carries a phantom property keyed by a symbol `Schema.ts` does not\n * export, so nothing outside that file can produce one without a cast — and\n * reaching for `s` here would make the agent runtime depend on the schema\n * builder for a single hard-coded object. One field, no `describe`, no\n * optionality: the cast is cheaper than the coupling.\n */\nconst questionSchema = {\n toJSONSchema: () => ({\n type: \"object\",\n properties: { question: { type: \"string\", description: \"What to ask the user\" } },\n required: [\"question\"],\n additionalProperties: false as const,\n }),\n parse(value: unknown) {\n const result = questionSchema.safeParse(value);\n if (result.ok === false) throw new Error(result.errors.join(\", \"));\n return result.value;\n },\n safeParse(value: unknown) {\n if (typeof value !== \"object\" || value === null || typeof (value as any).question !== \"string\") {\n return { ok: false as const, errors: [\"question: expected a string\"] };\n }\n return { ok: true as const, value: { question: (value as any).question } };\n },\n} as unknown as Schema<{ question: string }>;\n\nexport type AnyAgentTool = AgentTool<string, any, any, any>;\n\n/**\n * A group of tools the model can search as a unit.\n *\n * The provider's tool search works over namespaces, and the guidance is fewer\n * than ten functions in each — the model looks at a namespace's description to\n * decide whether anything inside is worth loading, so the grouping is part of\n * the prompt, not bookkeeping. A namespace is also the only place a\n * *collection* of tools can be described; on a flat list that sentence has\n * nowhere to go.\n *\n * Tool names stay globally unique within an agent, so the browser still\n * discriminates on `name` alone and the namespace never leaks into the client's\n * types.\n */\nexport class ToolNamespace<\n Name extends string = string,\n T extends readonly AnyAgentTool[] = readonly AnyAgentTool[],\n> {\n readonly name: Name;\n readonly description: string;\n readonly tools: T;\n /**\n * Kept here rather than pushed onto each tool. A tool is a module-scope\n * singleton and may be listed bare as well as inside a group; writing the\n * group's `deferred` onto it would defer it everywhere, which is a global\n * effect from a local declaration.\n */\n readonly deferred: boolean;\n\n private constructor(params: {\n name: Name;\n description: string;\n tools: T;\n deferred?: boolean;\n }) {\n this.name = params.name;\n this.description = params.description;\n this.tools = params.tools;\n this.deferred = params.deferred === true;\n }\n\n static create<const Name extends string, const T extends readonly AnyAgentTool[]>(params: {\n name: Name;\n /** What the model reads when deciding whether to search inside. */\n description: string;\n tools: T;\n /** Defers every tool in the group, so the whole namespace costs its own\n * description plus one line per tool until something is loaded. */\n deferred?: boolean;\n }): ToolNamespace<Name, T> {\n return new ToolNamespace(params);\n }\n}\n\n/** What an agent's `tools` may hold: tools, or namespaces of them. */\nexport type ToolEntry = AnyAgentTool | ToolNamespace<string, readonly AnyAgentTool[]>;\n\ntype FlattenTools<T extends readonly ToolEntry[]> = T[number] extends infer E\n ? E extends ToolNamespace<any, infer NT>\n ? NT[number]\n : E\n : never;\n\n/**\n * The tool tuple, erased to the payload types the client is allowed to see.\n *\n * `progress` is emitted for every tool, `never` included, rather than only for\n * the ones that can yield. A conditional that dropped the member would make\n * `T[K][\"progress\"]` in `types.ts` resolve differently per tool, and this\n * package compiles with `strict: false` — where `undefined extends T` is true\n * of everything and an optional member is indistinguishable from a required\n * one. Two inference bugs in this module already came from testing a shape\n * under those options and believing the answer (see `OptionalSchema` in\n * `Schema.ts`); an unconditional member has nothing to get wrong.\n */\nexport type ToolShapesOf<T extends readonly ToolEntry[]> = {\n [K in Extract<FlattenTools<T>, AnyAgentTool> as K[\"name\"]]: K extends AgentTool<\n any,\n infer I,\n infer O,\n infer P\n >\n ? { input: I; output: O; progress: P }\n : never;\n};\n\n// --- skills --------------------------------------------------------------\n\n/**\n * A skill is instructions the model can go and fetch.\n *\n * Inlining every skill into the system prompt costs its tokens on every request\n * and gets worse with each skill added. So a skill is lowered to a tool: one\n * zero-parameter function per skill, in a reserved `skills` namespace, whose\n * description is the skill's and whose result is `instructions` plus any\n * `files`. Only those descriptions are prompted, and a skill the model never\n * reaches for costs a line of text.\n *\n * Lowering to a tool rather than to a synthetic `load_skill(name)` dispatcher\n * is the whole trick: discovery is then the same mechanism as everything else\n * the model chooses between, which means it runs on the provider's own\n * tool-selection machinery instead of on a string argument gemi would have to\n * validate, and a skill that is never loaded is a namespace entry rather than a\n * branch in our code. It is also why `deferred` applies here unchanged — with\n * tool search the namespace is searched, and without it the same tools are\n * listed inline, which for zero-parameter functions costs almost nothing.\n */\nexport interface SkillDefinition<Name extends string = string> {\n name: Name;\n /** Read on every request — this is what the model decides to load from. */\n description: string;\n /** A thunk so a large body stays off the startup path and out of memory. */\n instructions: string | (() => string | Promise<string>);\n /** Paths resolved relative to the app root, appended after `instructions`. */\n files?: string[];\n}\n\nexport class Skill<Name extends string = string> {\n readonly name: Name;\n readonly description: string;\n readonly instructions: string | (() => string | Promise<string>);\n readonly files?: string[];\n\n private constructor(params: SkillDefinition<Name>) {\n this.name = params.name;\n this.description = params.description;\n this.instructions = params.instructions;\n this.files = params.files;\n }\n\n static create<const Name extends string>(params: SkillDefinition<Name>): Skill<Name> {\n return new Skill(params);\n }\n}\n\n/** Reserved: a skill is lowered into a namespace of exactly this name. */\nexport const SKILLS_NAMESPACE = \"skills\";\n\nconst SKILLS_NAMESPACE_DESCRIPTION =\n \"Instructions this agent can load on demand. Load the relevant one before acting in the area it covers.\";\n\nconst EMPTY_PARAMETERS = {\n type: \"object\",\n properties: {},\n required: [] as string[],\n additionalProperties: false as const,\n};\n\n// --- agent ---------------------------------------------------------------\n\nexport type ReasoningEffort = \"minimal\" | \"low\" | \"medium\" | \"high\";\n\nexport interface CreateAgentParams<\n T extends readonly ToolEntry[],\n S extends readonly Skill[],\n O extends Schema<any> | undefined,\n> {\n name: string;\n /** The system prompt. Per-request additions belong on the controller, which\n * has the request; this is the part that is the same for everyone. */\n instructions?: string;\n provider: AgentProvider;\n tools?: T;\n /** Lowered into the reserved `skills` namespace — see `Skill`. The name is\n * reserved, so a namespace of your own cannot be called `skills`. */\n skills?: S;\n /**\n * Makes the final assistant turn strict JSON instead of prose. Tool turns are\n * unaffected — only the answer is constrained, which is the only place a\n * schema can apply once there is a tool loop.\n */\n output?: O;\n /** Ends the run with `finishReason: \"max-steps\"` rather than throwing: an\n * agent that loops is a bug to show, not an exception to swallow. */\n maxSteps?: number;\n /**\n * How far `ctx.runAgent` may nest below this agent. Default 3.\n *\n * It is a limit on the *tree*, taken from the run at the root, so raising it\n * on a sub-agent cannot deepen a run it did not start. A cycle is caught by\n * the agent-name chain before this is reached — this is for the mutually\n * recursive shape a name check cannot see, and for the merely runaway one.\n */\n maxDepth?: number;\n reasoning?: ReasoningEffort;\n}\n\n/**\n * One call per client turn — a first message and an answer to a pending\n * approval take the same path, because they are the same thing: the next turn\n * of a conversation.\n */\nexport interface AgentStreamParams {\n /** Prior turns. The controller loads these from its store, or takes what the\n * client sent when running stateless. */\n messages: AgentMessage[];\n /** The client's turn: text, answers to pending calls, or both. */\n turn?: ClientTurn;\n req: HttpRequest<any, any>;\n /** Aborted by an explicit `stop`, not by a disconnect. */\n signal?: AbortSignal;\n runId?: string;\n threadId?: string;\n /** Appended to the agent's own `instructions` for this request only. */\n instructions?: string;\n /** Per-request model choice, e.g. letting a user pick. */\n provider?: AgentProvider;\n maxSteps?: number;\n reasoning?: ReasoningEffort;\n /**\n * Fires once for every message this run completes — the user's turn, each\n * assistant turn, and any earlier message this turn amended by resolving a\n * pending call. It is the controller's persistence point, and it fires\n * whether or not anyone is still reading the stream, which is what makes a\n * run that outlives its request useful.\n *\n * A message may be reported twice across runs under the same id when a\n * pending call is resolved later; a store keyed by id should upsert.\n */\n onMessage?: (message: AgentMessage) => void | Promise<void>;\n /**\n * Set by `ctx.runAgent` and by nothing else.\n *\n * It rides on the public params rather than on a back door because\n * `Agent.stream` is the only way to start a run and a sub-run is a run —\n * giving nesting its own construction path would mean two places where a run\n * is set up, and the second one would drift. Omitted, a run is a root: depth\n * 0, no path, signatures over its own id.\n */\n nesting?: NestedContext;\n}\n\n/**\n * Where a run sits inside a tree of runs. Carried down by `ctx.runAgent`.\n *\n * `signingRunId` and `signingPath` are the reason this is threaded rather than\n * recomputed: a pending call a sub-agent raises is answered by the *client*,\n * which only ever sees the root run, so the token has to be minted under the\n * root's id and the sub-run's path from the start. Re-signing the token at each\n * level on the way up would work too, and would throw away every signature but\n * the outermost one — this way the run that asks the question is also the run\n * that can check the answer, which is where the tool, its schema and its `kind`\n * all already are.\n */\nexport type NestedContext = {\n /** 0 at the root; `ctx.depth` inside a tool of this run. */\n depth: number;\n /** The `maxDepth` of the run at the root of the tree. */\n maxDepth: number;\n /** Agent names from the root down to and including this one, so a cycle can\n * be reported as the chain that caused it. */\n chain: string[];\n /** The root run's id: what a pending call raised here is signed under. */\n signingRunId: string;\n /** Tool-call ids from the root down to the call that started this run. */\n signingPath: string[];\n /**\n * Inherited, and once it is `\"deny\"` it stays `\"deny\"` all the way down. A\n * caller that asked for an autonomous sub-agent must not have a question\n * surface from three levels below it, and the only way to promise that is to\n * make the whole subtree refuse rather than to check at the top.\n */\n onPending: \"escalate\" | \"deny\";\n};\n\nexport type AgentRunResult<T extends ToolShapes, O> = {\n runId: string;\n /** Everything produced this run — the controller persists these. */\n messages: AgentMessage<T, O>[];\n finishReason: FinishReason;\n usage: Usage;\n /** Set when the agent declares an `output` schema and the run finished. */\n output?: O;\n};\n\n/**\n * A run is an async iterable of events, and the SSE encoding is a method on it\n * rather than a separate helper — so the same object serves a controller\n * returning a `Response` and a server-side caller that just wants to await the\n * result.\n *\n * A run keeps going when its request ends. That is what makes reattaching after\n * a refresh possible, and it is why `stop()` is an explicit call rather than the\n * client closing a socket.\n */\nexport interface AgentRun<T extends ToolShapes = ToolShapes, O = unknown> extends AsyncIterable<\n AgentStreamEvent<T, O>\n> {\n readonly runId: string;\n /** Numbered events, replayable from a cursor. `toResponse` is this, encoded. */\n frames(from?: number): AsyncIterable<AgentStreamFrame<T, O>>;\n toResponse(params?: { from?: number }): Response;\n result(): Promise<AgentRunResult<T, O>>;\n /**\n * Cancels the run and closes the conversation behind it: every tool call\n * still in flight gets a `denied` result with `cause: \"stopped\"`, the\n * assistant message is finalized with `finishReason: \"aborted\"`, and both go\n * through `onMessage` like any other message.\n *\n * That last part is the point. A cancel that merely stops emitting leaves a\n * history the provider will reject on the next turn, so the run's last act is\n * to make the transcript valid — which is also what lets the user carry on\n * talking instead of starting over.\n */\n stop(params?: { reason?: string }): void;\n}\n\n/** A tool plus where it sits in the prompt. Fixed for the life of the agent. */\ntype ResolvedTool = {\n tool: AnyAgentTool;\n namespace?: string;\n deferred: boolean;\n};\n\n/** What a run needs from its agent, resolved once at `Agent.create`. */\ntype RunConfig = {\n name: string;\n instructions?: string;\n provider: AgentProvider;\n registry: Map<string, ResolvedTool>;\n providerTools: (ProviderToolSpec | ProviderToolNamespace)[];\n output?: Schema<any>;\n maxSteps: number;\n maxDepth: number;\n reasoning?: ReasoningEffort;\n};\n\nconst DEFAULT_MAX_STEPS = 8;\n/** Three is enough for \"agent, sub-agent, specialist\" and small enough that a\n * runaway tree is a readable error rather than a stack trace. */\nconst DEFAULT_MAX_DEPTH = 3;\n\nexport class Agent<\n T extends readonly ToolEntry[] = readonly ToolEntry[],\n S extends readonly Skill[] = readonly Skill[],\n O extends Schema<any> | undefined = undefined,\n> {\n readonly name: string;\n readonly tools: T;\n readonly skills: S;\n readonly provider: AgentProvider;\n readonly output: O;\n readonly instructions?: string;\n readonly maxSteps: number;\n readonly maxDepth: number;\n readonly reasoning?: ReasoningEffort;\n\n private readonly config: RunConfig;\n\n private constructor(params: CreateAgentParams<T, S, O>) {\n this.name = params.name;\n this.instructions = params.instructions;\n this.provider = params.provider;\n this.tools = (params.tools ?? ([] as unknown as T)) as T;\n this.skills = (params.skills ?? ([] as unknown as S)) as S;\n this.output = params.output as O;\n this.maxSteps = params.maxSteps ?? DEFAULT_MAX_STEPS;\n this.maxDepth = params.maxDepth ?? DEFAULT_MAX_DEPTH;\n this.reasoning = params.reasoning;\n\n const { registry, providerTools } = lowerTools(this.tools, this.skills);\n this.config = {\n name: this.name,\n instructions: this.instructions,\n provider: this.provider,\n registry,\n providerTools,\n output: params.output as Schema<any> | undefined,\n maxSteps: this.maxSteps,\n maxDepth: this.maxDepth,\n reasoning: this.reasoning,\n };\n }\n\n static create<\n const T extends readonly ToolEntry[],\n const S extends readonly Skill[],\n O extends Schema<any> | undefined = undefined,\n >(params: CreateAgentParams<T, S, O>): Agent<T, S, O> {\n return new Agent(params);\n }\n\n stream(params: AgentStreamParams): AgentRun<ToolShapesOf<T>, OutputOf<O>> {\n const config: RunConfig = {\n ...this.config,\n provider: params.provider ?? this.config.provider,\n maxSteps: params.maxSteps ?? this.config.maxSteps,\n reasoning: params.reasoning ?? this.config.reasoning,\n };\n return new AgentRunImpl(config, params) as unknown as AgentRun<\n ToolShapesOf<T>,\n OutputOf<O>\n >;\n }\n}\n\nexport type OutputOf<O> = O extends Schema<any> ? Infer<O> : never;\n\nexport type AnyAgent = Agent<any, any, any>;\n\n// --- lowering ------------------------------------------------------------\n\nfunction toolSpec(resolved: ResolvedTool): ProviderToolSpec {\n return {\n name: resolved.tool.name,\n description: resolved.tool.description,\n parameters: resolved.tool.inputSchema.toJSONSchema(),\n strict: true,\n deferred: resolved.deferred,\n };\n}\n\n/**\n * Flattens the declared tuple into the registry the loop dispatches on, and the\n * shape the provider is shown.\n *\n * Both are built once, at `Agent.create`, because neither depends on the\n * request: a tool is a singleton and a namespace is a static grouping. Building\n * them per run would be work repeated on every turn for an answer that cannot\n * change — and it would move the name-collision errors below out of startup and\n * into the first user's first message.\n */\nfunction lowerTools(\n entries: readonly ToolEntry[],\n skills: readonly Skill[],\n): { registry: Map<string, ResolvedTool>; providerTools: (ProviderToolSpec | ProviderToolNamespace)[] } {\n const registry = new Map<string, ResolvedTool>();\n const providerTools: (ProviderToolSpec | ProviderToolNamespace)[] = [];\n\n const register = (resolved: ResolvedTool) => {\n if (registry.has(resolved.tool.name)) {\n throw new Error(\n `Two tools are named \"${resolved.tool.name}\". Tool names are global within an agent — the client discriminates a tool part by name alone.`,\n );\n }\n registry.set(resolved.tool.name, resolved);\n };\n\n for (const entry of entries) {\n if (entry instanceof ToolNamespace) {\n if (entry.name === SKILLS_NAMESPACE) {\n throw new Error(\n `\"${SKILLS_NAMESPACE}\" is reserved for the namespace skills are lowered into. Rename the namespace — silently shadowing it would make every skill unreachable with no error to read.`,\n );\n }\n const members: ProviderToolSpec[] = [];\n for (const tool of entry.tools) {\n const resolved = { tool, namespace: entry.name, deferred: entry.deferred || tool.deferred };\n register(resolved);\n members.push(toolSpec(resolved));\n }\n providerTools.push({ name: entry.name, description: entry.description, tools: members });\n continue;\n }\n const resolved = { tool: entry, deferred: entry.deferred };\n register(resolved);\n providerTools.push(toolSpec(resolved));\n }\n\n if (skills.length > 0) {\n const members: ProviderToolSpec[] = [];\n for (const skill of skills) {\n const tool = skillTool(skill);\n register({ tool, namespace: SKILLS_NAMESPACE, deferred: false });\n members.push({\n name: skill.name,\n description: skill.description,\n parameters: EMPTY_PARAMETERS,\n strict: true,\n // Not deferred: the whole cost of a skill in the prompt is its name and\n // description, and those are exactly what deferral keeps. Withholding\n // an empty parameter object saves nothing and adds a round trip.\n deferred: false,\n });\n }\n providerTools.push({\n name: SKILLS_NAMESPACE,\n description: SKILLS_NAMESPACE_DESCRIPTION,\n tools: members,\n });\n }\n\n return { registry, providerTools };\n}\n\n/** The zero-parameter tool a skill becomes. */\nfunction skillTool(skill: Skill): AnyAgentTool {\n return AgentTool.create({\n name: skill.name,\n description: skill.description,\n inputSchema: {\n toJSONSchema: () => EMPTY_PARAMETERS,\n parse: () => ({}),\n safeParse: () => ({ ok: true as const, value: {} }),\n } as unknown as Schema<Record<string, never>>,\n // The thunk is called here, on load, and not at startup: a skill body can\n // be a megabyte of markdown, and an agent that declares twelve of them\n // should not read twelve files to answer \"hello\".\n execute: async () => {\n const body =\n typeof skill.instructions === \"function\"\n ? await skill.instructions()\n : skill.instructions;\n const sections = [body];\n for (const file of skill.files ?? []) {\n sections.push(`--- ${file} ---\\n${await readSkillFile(file)}`);\n }\n return sections.join(\"\\n\\n\");\n },\n }) as unknown as AnyAgentTool;\n}\n\nasync function readSkillFile(file: string): Promise<string> {\n try {\n return await Bun.file(file).text();\n } catch (error) {\n // A missing file is told to the model rather than thrown: the rest of the\n // skill is still worth having, and a run should not die because one of\n // several appendices moved.\n return `(could not be read: ${(error as Error).message})`;\n }\n}\n\n// --- the run -------------------------------------------------------------\n\nclass RunAborted extends Error {\n constructor() {\n super(\"The run was stopped\");\n this.name = \"RunAborted\";\n }\n}\n\nfunction raceAbort<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) {\n return Promise.reject(new RunAborted());\n }\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(new RunAborted());\n signal.addEventListener(\"abort\", onAbort, { once: true });\n promise.then(resolve, reject).finally(() => signal.removeEventListener(\"abort\", onAbort));\n });\n}\n\nfunction emptyUsage(): Usage {\n return { inputTokens: 0, outputTokens: 0, totalTokens: 0 };\n}\n\nfunction addUsage(total: Usage, next: Usage | undefined): Usage {\n if (!next) return total;\n const merged: Usage = {\n inputTokens: total.inputTokens + (next.inputTokens ?? 0),\n outputTokens: total.outputTokens + (next.outputTokens ?? 0),\n totalTokens: total.totalTokens + (next.totalTokens ?? 0),\n };\n if (next.reasoningTokens !== undefined || total.reasoningTokens !== undefined) {\n merged.reasoningTokens = (total.reasoningTokens ?? 0) + (next.reasoningTokens ?? 0);\n }\n if (next.cachedInputTokens !== undefined || total.cachedInputTokens !== undefined) {\n merged.cachedInputTokens = (total.cachedInputTokens ?? 0) + (next.cachedInputTokens ?? 0);\n }\n return merged;\n}\n\nfunction isAsyncGenerator(value: unknown): value is AsyncGenerator<unknown, unknown, void> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as AsyncGenerator).next === \"function\" &&\n Symbol.asyncIterator in (value as object)\n );\n}\n\n/**\n * The best parse of a JSON document that is still arriving.\n *\n * Exists so a UI can bind fields before the object closes. It closes whatever\n * brackets are open and drops a trailing key with no value; when even that does\n * not parse it gives up and returns an empty object rather than throwing,\n * because a snapshot is a convenience and a run must not die for one.\n */\nfunction bestEffortParse(text: string): any {\n if (!text.trim()) return {};\n try {\n return JSON.parse(text);\n } catch {\n // fall through to repair\n }\n const closers: string[] = [];\n let inString = false;\n let escaped = false;\n for (const char of text) {\n if (inString) {\n if (escaped) escaped = false;\n else if (char === \"\\\\\") escaped = true;\n else if (char === '\"') inString = false;\n continue;\n }\n if (char === '\"') inString = true;\n else if (char === \"{\") closers.push(\"}\");\n else if (char === \"[\") closers.push(\"]\");\n else if (char === \"}\" || char === \"]\") closers.pop();\n }\n let repaired = text;\n if (inString) repaired += '\"';\n repaired = repaired.replace(/[,:]\\s*$/, \"\");\n const suffix = closers.reverse().join(\"\");\n try {\n return JSON.parse(repaired + suffix);\n } catch {\n // A trailing `\"key\":` leaves a property with no value; drop the key too.\n try {\n return JSON.parse(repaired.replace(/,?\\s*\"[^\"]*\"\\s*$/, \"\") + suffix);\n } catch {\n return {};\n }\n }\n}\n\ntype StepOutcome = {\n reason: FinishReason;\n error?: AgentError;\n};\n\n/**\n * The prior transcript plus what a later run produced, upserted by id.\n *\n * A run only reports the messages it *made*, so a resumed sub-run's\n * `result().messages` is the tail and not the whole thing — and a message it\n * amended (the one holding the call that was finally answered) comes back under\n * an id the prior transcript already has. Appending would duplicate it and\n * replacing the array would lose everything before the resume, so the record on\n * `ToolCallPart.nested` is rebuilt by upsert, which is the same rule a store\n * keyed by message id follows.\n */\nfunction mergeMessages(prior: AgentMessage[], produced: AgentMessage[]): AgentMessage[] {\n const merged = [...prior];\n const index = new Map(merged.map((message, at) => [message.id, at]));\n for (const message of produced) {\n const at = index.get(message.id);\n if (at === undefined) {\n index.set(message.id, merged.length);\n merged.push(message);\n } else {\n merged[at] = message;\n }\n }\n return merged;\n}\n\n/** Tool calls in a transcript with no result anywhere in it. */\nfunction openCallIds(messages: AgentMessage[]): Set<string> {\n const resolved = new Set<string>();\n for (const message of messages) {\n for (const part of message.content) {\n if (part.type === \"tool-result\") resolved.add(part.toolCallId);\n }\n }\n const open = new Set<string>();\n for (const message of messages) {\n for (const part of message.content) {\n if (part.type === \"tool-call\" && !resolved.has(part.toolCallId)) open.add(part.toolCallId);\n }\n }\n return open;\n}\n\n/**\n * A sub-agent's structured answer, read back out of its transcript.\n *\n * `NestedRun` has nowhere to put an `output` — it is a transcript, and the\n * output part is already in it — so a memoized run recovers the value the same\n * way a client would. That keeps the memo honest: what a replay returns is\n * derived from what was persisted, not from a second copy that could disagree\n * with it.\n */\nfunction outputOf(messages: AgentMessage[]): unknown {\n for (let i = messages.length - 1; i >= 0; i--) {\n const content = messages[i].content;\n for (let j = content.length - 1; j >= 0; j--) {\n const part = content[j];\n if (part.type === \"output\" && part.partial !== true) return part.value;\n }\n }\n return undefined;\n}\n\n/** For the replay-mismatch message, where the label is what tells two runs of\n * the same agent apart. */\nfunction describeRun(agent: string, label: string | undefined): string {\n return label === undefined ? `\"${agent}\"` : `\"${agent}\" labelled \"${label}\"`;\n}\n\n/** A message flattened to text, for comparing one turn's seed against another's. */\nfunction textOfMessage(message: AgentMessage): string {\n return message.content\n .map((part) => (part.type === \"text\" ? part.text : `<${part.type}>`))\n .join(\"\");\n}\n\n/**\n * What a `runAgent` call would start its sub-run from, as a comparable string.\n *\n * `null` when the call names no seed at all — `runAgent(agent, {})` — which is\n * the one shape with nothing to compare against, since the record's first\n * message would then be something the sub-agent said rather than something it\n * was told.\n */\nfunction seedOf(params: RunAgentParams): string | null {\n if (params.prompt !== undefined) return `user:${params.prompt}`;\n const first = params.messages?.[0];\n return first ? `${first.role}:${textOfMessage(first)}` : null;\n}\n\n/**\n * Why the Nth sub-run of a replayed tool body is not the Nth sub-run of the\n * turn that escalated, or `null` when it is.\n *\n * Agent and label catch the branchy shape. THE SEED IS WHAT CATCHES THE SHAPE\n * THE DOC COMMENT NAMES FIRST: `runAgent` in a loop, the same agent every time,\n * no label — the default and the common case — over a list that came back in a\n * different order, from a `Set`, a re-sorted query, or a second read of a\n * mutable column. Agent and label match for every element of such a loop, so\n * without this the user's answer to the second question is folded into the run\n * the tool now believes is the first, and the model is told the crossed pair as\n * fact. Nothing in the transcript, the stream or the store shows it happened.\n *\n * The record's first message is the seed because `runNested` records it that\n * way — the user turn built from `prompt`, or the first of `params.messages`.\n * `instructions` is not compared: it never enters the transcript, and\n * `NestedRun` has nowhere to keep it.\n */\nfunction replayMismatch(\n recorded: NestedRun,\n agent: AnyAgent,\n params: RunAgentParams,\n): string | null {\n if (recorded.agent !== agent.name || recorded.label !== params.label) {\n return (\n `was ${describeRun(recorded.agent, recorded.label)} on the turn that escalated ` +\n `and is ${describeRun(agent.name, params.label)} on the replay`\n );\n }\n const seed = seedOf(params);\n const first = recorded.messages[0];\n const was = first ? `${first.role}:${textOfMessage(first)}` : null;\n if (seed !== null && was !== null && seed !== was) {\n return (\n `was started with ${JSON.stringify(was)} on the turn that escalated ` +\n `and with ${JSON.stringify(seed)} on the replay`\n );\n }\n return null;\n}\n\n/**\n * What is left of an answer's path once this run's own prefix is removed.\n *\n * `null` means the answer is not addressed to this run at all, which is a\n * client error rather than a routing decision — an empty remainder means \"a\n * call this run made itself\", and a non-empty one names the tool call to\n * re-enter.\n */\nfunction pathBelow(path: string[] | undefined, prefix: string[]): string[] | null {\n const full = path ?? [];\n if (full.length < prefix.length) return null;\n for (let i = 0; i < prefix.length; i++) {\n if (full[i] !== prefix[i]) return null;\n }\n return full.slice(prefix.length);\n}\n\nclass AgentRunImpl implements AgentRun<ToolShapes, unknown> {\n readonly runId: string;\n\n private readonly config: RunConfig;\n private readonly params: AgentStreamParams;\n private readonly controller = new AbortController();\n\n private readonly buffer: AgentStreamFrame<ToolShapes, unknown>[] = [];\n private readonly waiters = new Set<() => void>();\n private seq = 0;\n private ended = false;\n\n /** The working history handed to the provider, and what this run produced. */\n private history: AgentMessage[] = [];\n private produced: AgentMessage[] = [];\n private current: AgentMessage | null = null;\n\n /** Messages from an earlier run this one has amended, by id. Cloned once and\n * reused, so two results for the same message do not fork it. */\n private readonly amended = new Map<string, AgentMessage>();\n /** Amended messages that have not yet gone through `onMessage`. */\n private readonly unreported = new Set<AgentMessage>();\n\n private usage: Usage = emptyUsage();\n private finishReason: FinishReason = \"stop\";\n private output: unknown;\n private stopReason: string | undefined;\n\n private readonly settled: Promise<AgentRunResult<ToolShapes, unknown>>;\n\n /**\n * Where this run sits in a tree of runs, all of it constant for the run.\n *\n * `signingRunId` is the *root's* id rather than this one's: the client only\n * ever sees the root run, so a question a sub-agent asks has to travel under\n * an id the client can hand back. `pathPrefix` is the chain of tool calls\n * above this run, and it is both what a pending call raised here is signed\n * over and what an answer coming back is matched against.\n */\n private readonly depth: number;\n private readonly maxDepth: number;\n private readonly chain: string[];\n private readonly signingRunId: string;\n private readonly pathPrefix: string[];\n private readonly onPending: \"escalate\" | \"deny\";\n /**\n * Sub-runs that have not yet written their transcript to the tool call.\n *\n * The abort path waits on these. A `stop()` reaches a sub-run through the\n * shared signal, so it is already closing — but `raceAbort` in `runTools`\n * returns the moment the signal fires, which would finalize and persist the\n * parent's message before the sub-run had recorded what it managed to do.\n * The work would be on the stream and missing from the store.\n */\n private readonly nestedSettling = new Set<Promise<unknown>>();\n\n constructor(config: RunConfig, params: AgentStreamParams) {\n this.config = config;\n this.params = params;\n this.runId = params.runId ?? `run_${crypto.randomUUID()}`;\n this.history = [...params.messages];\n\n const nesting = params.nesting;\n this.depth = nesting?.depth ?? 0;\n this.maxDepth = nesting?.maxDepth ?? config.maxDepth;\n this.chain = nesting?.chain ?? [config.name];\n this.signingRunId = nesting?.signingRunId ?? this.runId;\n this.pathPrefix = nesting?.signingPath ?? [];\n this.onPending = nesting?.onPending ?? \"escalate\";\n\n if (params.signal) {\n if (params.signal.aborted) this.controller.abort();\n else params.signal.addEventListener(\"abort\", () => this.stop(), { once: true });\n }\n\n // Started here, not on first read. A run outlives the request that began\n // it, so nothing may depend on someone being attached — a client that\n // never reads still gets its tools run and its messages persisted.\n this.settled = this.execute();\n }\n\n // --- event plumbing ----------------------------------------------------\n\n private emit(event: AgentStreamEvent<ToolShapes, unknown>) {\n if (this.ended) return;\n this.buffer.push({ seq: ++this.seq, event });\n this.wake();\n }\n\n private wake() {\n const pending = [...this.waiters];\n this.waiters.clear();\n for (const resolve of pending) resolve();\n }\n\n private nextFrame(): Promise<void> {\n return new Promise<void>((resolve) => this.waiters.add(resolve));\n }\n\n /**\n * Replays from the buffer, then follows the run live.\n *\n * The whole run is buffered rather than a sliding window: a run is bounded by\n * `maxSteps`, and a client that reconnects two steps late wanting frame 42\n * must get frame 42 and not \"the oldest I still have\". Bounding it is the\n * live-run registry's job, where the policy question is how long a *finished*\n * run is kept.\n */\n async *frames(from = 0): AsyncIterable<AgentStreamFrame<ToolShapes, unknown>> {\n let index = from > 0 ? from - 1 : 0;\n for (;;) {\n while (index < this.buffer.length) {\n yield this.buffer[index++];\n }\n if (this.ended) return;\n await this.nextFrame();\n }\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<AgentStreamEvent<ToolShapes, unknown>> {\n for await (const frame of this.frames()) {\n yield frame.event;\n }\n }\n\n toResponse(params?: { from?: number }): Response {\n const frames = this.frames(params?.from);\n const encoder = new TextEncoder();\n let cancelled = false;\n\n let keepalive!: ReturnType<typeof sseKeepalive>;\n\n const body = new ReadableStream<Uint8Array>({\n start: async (controller) => {\n // A slow tool or a thinking sub-agent can leave the connection silent\n // for longer than a proxy's idle timeout, and a proxy that closes it\n // looks to the client exactly like a run that finished.\n keepalive = sseKeepalive(controller);\n try {\n for await (const frame of frames) {\n if (cancelled) break;\n // `id:` carries the cursor so a browser reconnecting with\n // `Last-Event-ID` is already asking the right question.\n controller.enqueue(\n encoder.encode(`id: ${frame.seq}\\ndata: ${JSON.stringify(frame.event)}\\n\\n`),\n );\n keepalive.touch();\n }\n } catch {\n // A stream that cannot be written to is a dead reader, not a dead\n // run. Nothing to report and nothing to stop.\n }\n keepalive.stop();\n try {\n controller.close();\n } catch {\n // already closed by a cancel\n }\n },\n cancel: () => {\n // Deliberately does not touch the run. A disconnect is a reader\n // leaving; `stop()` is the only thing that cancels work, because the\n // tool loop is here and a closed tab has not stopped step four from\n // charging a card.\n cancelled = true;\n keepalive.stop();\n },\n });\n\n return new Response(body, {\n headers: {\n \"Content-Type\": \"text/event-stream; charset=utf-8\",\n \"Cache-Control\": \"no-cache, no-transform\",\n Connection: \"keep-alive\",\n // Tells nginx not to buffer, which would otherwise hold every frame\n // until the response ended and make a stream look like a long pause.\n \"X-Accel-Buffering\": \"no\",\n },\n });\n }\n\n result(): Promise<AgentRunResult<ToolShapes, unknown>> {\n return this.settled;\n }\n\n stop(params?: { reason?: string }): void {\n if (this.ended || this.controller.signal.aborted) return;\n this.stopReason = params?.reason;\n this.controller.abort();\n }\n\n // --- the loop ----------------------------------------------------------\n\n private async execute(): Promise<AgentRunResult<ToolShapes, unknown>> {\n this.emit({ type: \"run-start\", runId: this.runId, threadId: this.params.threadId });\n\n try {\n // A turn that answers a sub-agent's question re-enters the tool that\n // asked it, and that tool may ask again — so the run can be finished\n // before it has taken a single model step. Going on to `loop()` here\n // would step the model with a tool call still open, which is exactly the\n // history the provider rejects.\n const escalated = await this.ingestTurn();\n if (escalated.length > 0) {\n this.finishReason = \"awaiting-input\";\n this.emit({ type: \"awaiting-input\", runId: this.runId, pending: escalated });\n } else {\n await this.loop();\n }\n } catch (error) {\n if (error instanceof RunAborted || this.controller.signal.aborted) {\n await this.finalizeAborted();\n } else {\n const normalized = this.config.provider.normalizeError(error);\n this.emit({ type: \"error\", error: normalized });\n await this.finalizeMessage(\"error\");\n this.finishReason = \"error\";\n }\n }\n\n this.emit({ type: \"usage\", usage: this.usage });\n this.emit({ type: \"run-end\", runId: this.runId, finishReason: this.finishReason });\n this.ended = true;\n this.wake();\n\n return {\n runId: this.runId,\n messages: this.produced as AgentMessage<ToolShapes, unknown>[],\n finishReason: this.finishReason,\n usage: this.usage,\n output: this.output,\n };\n }\n\n private async loop(): Promise<void> {\n const maxSteps = Math.max(1, this.config.maxSteps);\n\n for (let step = 1; step <= maxSteps; step++) {\n const message = this.startMessage();\n const outcome = await this.runStep(message);\n\n if (outcome.error) {\n this.emit({ type: \"error\", error: outcome.error });\n await this.finalizeMessage(\"error\");\n this.finishReason = \"error\";\n return;\n }\n\n const calls = message.content.filter(\n (part): part is ToolCallPart => part.type === \"tool-call\",\n );\n\n if (calls.length === 0) {\n this.finishReason = outcome.reason;\n await this.finalizeMessage(outcome.reason);\n return;\n }\n\n const pending = await this.runTools(message, calls, step);\n\n if (pending.length > 0) {\n // The message closes first, then the run says what it is waiting for:\n // `awaiting-input` is terminal, and everything needed to answer it has\n // to already be on the stream when it arrives.\n this.finishReason = \"awaiting-input\";\n await this.finalizeMessage(\"awaiting-input\");\n this.emit({ type: \"awaiting-input\", runId: this.runId, pending });\n return;\n }\n\n if (step === maxSteps) {\n // Not an exception. An agent that will not stop calling tools is a bug\n // the app has to be able to see and show, and a throw here would put it\n // in a log instead of in the transcript.\n this.finishReason = \"max-steps\";\n await this.finalizeMessage(\"max-steps\");\n return;\n }\n\n await this.finalizeMessage(outcome.reason);\n }\n }\n\n private startMessage(): AgentMessage {\n const message: AgentMessage = {\n id: `msg_${crypto.randomUUID()}`,\n role: \"assistant\",\n content: [],\n createdAt: new Date().toISOString(),\n };\n this.current = message;\n this.history.push(message);\n this.produced.push(message);\n this.emit({ type: \"message-start\", messageId: message.id, role: \"assistant\" });\n return message;\n }\n\n private async finalizeMessage(reason: FinishReason): Promise<void> {\n const message = this.current;\n if (!message) return;\n this.current = null;\n message.finishReason = reason;\n // Before the message is handed to `onMessage` to be persisted and before it\n // reaches `result()` — the two places it stops being written and starts\n // being kept. Every exit lands here, aborted and errored runs included.\n for (const part of message.content) {\n if (part.type === \"text\" || part.type === \"reasoning\") {\n if (typeof part.text === \"string\") part.text = resolveRope(part.text);\n }\n }\n this.emit({ type: \"message-end\", messageId: message.id, finishReason: reason });\n await this.report(message);\n }\n\n private async report(message: AgentMessage): Promise<void> {\n if (!this.params.onMessage) return;\n try {\n await this.params.onMessage(message);\n } catch {\n // Persistence failing must not take the transcript with it: the messages\n // are still on the stream and still in `result()`.\n }\n }\n\n // --- one model call ----------------------------------------------------\n\n private async runStep(message: AgentMessage): Promise<StepOutcome> {\n const signal = this.controller.signal;\n const provider = this.config.provider;\n\n let outcome: StepOutcome = { reason: \"stop\" };\n const partialArgs = new Map<string, { name: string; args: string }>();\n let outputText = \"\";\n\n const stream = provider.stream({\n messages: this.history.filter((m) => m !== message),\n systemPrompt: await this.systemPrompt(),\n tools: this.config.providerTools.length > 0 ? this.config.providerTools : undefined,\n output: this.config.output\n ? { name: \"output\", schema: this.config.output.toJSONSchema() }\n : undefined,\n reasoning: this.config.reasoning,\n signal,\n });\n\n const iterator = stream[Symbol.asyncIterator]();\n for (;;) {\n const next = await raceAbort(Promise.resolve(iterator.next()), signal);\n if (next.done) break;\n const event = next.value;\n\n switch (event.type) {\n case \"text-delta\": {\n appendText(message, \"text\", event.delta);\n this.emit({ type: \"text-delta\", messageId: message.id, delta: event.delta });\n break;\n }\n case \"reasoning-delta\": {\n appendReasoning(message, event.id, event.delta);\n this.emit({ type: \"reasoning-delta\", messageId: message.id, delta: event.delta, id: event.id });\n break;\n }\n case \"output-delta\": {\n outputText += event.delta;\n this.emit({\n type: \"output-delta\",\n messageId: message.id,\n delta: event.delta,\n snapshot: bestEffortParse(outputText),\n });\n break;\n }\n case \"tool-search\": {\n this.emit({ type: \"tool-search\", loaded: event.loaded });\n break;\n }\n case \"tool-call-delta\": {\n const held = partialArgs.get(event.toolCallId) ?? { name: event.name, args: \"\" };\n held.args += event.argsDelta;\n held.name = event.name || held.name;\n partialArgs.set(event.toolCallId, held);\n this.emit({\n type: \"tool-call\",\n messageId: message.id,\n part: {\n type: \"tool-call\",\n toolCallId: event.toolCallId,\n name: held.name,\n input: bestEffortParse(held.args),\n partial: true,\n },\n });\n break;\n }\n case \"tool-call\": {\n partialArgs.delete(event.toolCallId);\n const part: ToolCallPart = {\n type: \"tool-call\",\n toolCallId: event.toolCallId,\n name: event.name,\n // A raw string when the model produced something that is not JSON.\n // Keeping it is what makes the `invalid_tool_input` result below\n // readable instead of an empty object nobody can explain.\n input: parseArgs(event.args),\n };\n message.content.push(part);\n this.emit({ type: \"tool-call\", messageId: message.id, part });\n break;\n }\n case \"finish\": {\n this.usage = addUsage(this.usage, event.usage);\n // The usage is taken either way, the reason only if nothing has\n // already failed. A provider is allowed to report an error and then\n // close the call with a finish frame — a content filter does exactly\n // that, and it still bills for the tokens — and letting the closing\n // frame overwrite the outcome would turn \"blocked\" into an empty\n // answer with no explanation anywhere.\n if (!outcome.error) outcome = { reason: event.reason };\n break;\n }\n case \"error\": {\n outcome = { reason: \"error\", error: event.error };\n break;\n }\n }\n }\n\n // A tool call whose arguments never finished arriving. It is still a call\n // the model made, so it gets a part and, below, an `invalid_tool_input`\n // result — dropping it would leave the model unable to see what went wrong.\n for (const [toolCallId, held] of partialArgs) {\n const part: ToolCallPart = {\n type: \"tool-call\",\n toolCallId,\n name: held.name,\n input: parseArgs(held.args),\n };\n message.content.push(part);\n this.emit({ type: \"tool-call\", messageId: message.id, part });\n }\n\n if (this.config.output && outputText && !outcome.error) {\n const parsed = this.config.output.safeParse(bestEffortParse(outputText));\n if (parsed.ok === true) {\n this.output = parsed.value;\n message.content.push({ type: \"output\", value: parsed.value });\n } else {\n this.emit({\n type: \"error\",\n error: {\n code: \"unknown\",\n message: `The model's structured answer did not match the output schema: ${parsed.errors.join(\", \")}`,\n retryable: true,\n },\n });\n }\n }\n\n return outcome;\n }\n\n private async systemPrompt(): Promise<string | undefined> {\n const parts = [this.config.instructions, this.params.instructions].filter(\n (part): part is string => Boolean(part && part.trim()),\n );\n return parts.length > 0 ? parts.join(\"\\n\\n\") : undefined;\n }\n\n // --- tools -------------------------------------------------------------\n\n private async runTools(\n message: AgentMessage,\n calls: ToolCallPart[],\n step: number,\n ): Promise<PendingToolCall[]> {\n const pending: PendingToolCall[] = [];\n const running: Promise<void>[] = [];\n\n for (const call of calls) {\n const resolved = this.config.registry.get(String(call.name));\n\n if (!resolved) {\n this.addResult(message, {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"error\",\n error: {\n code: \"tool_error\",\n message: `There is no tool named \"${String(call.name)}\".`,\n toolCallId: call.toolCallId,\n retryable: true,\n },\n });\n continue;\n }\n\n const parsed = resolved.tool.inputSchema.safeParse(call.input);\n if (parsed.ok === false) {\n // Back to the model, not up the stack. A model that mis-typed one\n // argument can usually fix it on the next step, and throwing turns a\n // recoverable mistake into a dead run.\n this.addResult(message, {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"error\",\n error: {\n code: \"invalid_tool_input\",\n message: `Invalid arguments for \"${String(call.name)}\": ${parsed.errors.join(\", \")}`,\n toolCallId: call.toolCallId,\n retryable: true,\n },\n });\n continue;\n }\n\n // The parsed value replaces the raw arguments on the part, and from here\n // on it is the only input this call has.\n //\n // A schema normalizes — it fills defaults, coerces, and drops the `null`s\n // that strict mode forces a model to send for an omitted optional. So\n // `safeParse(input)` and `input` are different values, and a pending call\n // has to be signed over, shown as, verified against and executed with the\n // *same* one. Keeping the raw value in the transcript and signing the\n // parsed one meant the MACs could not match on the way back: every\n // approval of a tool with an optional field came back looking forged, and\n // the user who clicked Approve was told they had refused.\n //\n // Writing it here rather than re-parsing on the way back also avoids\n // assuming `safeParse` is idempotent — the history now carries the value\n // the signature covers, so verification is a comparison and not a second\n // guess at what the first parse produced.\n call.input = parsed.value;\n\n const kind = pendingKind(resolved.tool);\n if (kind) {\n if (this.onPending === \"deny\") {\n this.addResult(message, this.deniedByPolicy(call));\n continue;\n }\n pending.push({\n toolCallId: call.toolCallId,\n name: call.name,\n input: parsed.value,\n kind,\n signature: signPendingCall(this.claimsFor(call.toolCallId, String(call.name), kind, parsed.value)),\n ...(this.pathPrefix.length > 0 ? { path: [...this.pathPrefix] } : {}),\n });\n continue;\n }\n\n running.push(\n this.executeTool(resolved, message.id, call, parsed.value, step)\n .then((result) => this.addResult(message, result))\n .catch((error) => {\n if (error instanceof PendingEscalation) {\n if (this.onPending === \"deny\") {\n this.addResult(message, this.deniedByPolicy(call));\n return;\n }\n // Collected exactly like a pending call this run made itself, and\n // deliberately without a result on `call`: the tool did not\n // finish, so its call stays open and the next turn re-enters it.\n // Siblings are untouched — `Promise.all` below still waits for\n // them, and one that completes keeps its result rather than being\n // thrown away because a different tool asked a question.\n pending.push(...error.pending);\n return;\n }\n // Only `RunAborted` reaches here, and the abort path denies every\n // unresolved call at once — swallowing it keeps a stopped run from\n // also raising an unhandled rejection.\n }),\n );\n }\n\n await raceAbort(Promise.all(running).then(() => undefined), this.controller.signal);\n return pending;\n }\n\n /**\n * What a pending call is signed over.\n *\n * `signingRunId` is the root run's, not this one's: the client only ever sees\n * the root, so a sub-agent's question has to be minted under an id the client\n * can hand back and this run can still recognise on the way in.\n */\n private claimsFor(\n toolCallId: string,\n name: string,\n kind: \"approval\" | \"question\" | \"client\",\n input: unknown,\n ) {\n return {\n runId: this.signingRunId,\n toolCallId,\n name,\n kind,\n input,\n // Absent rather than empty at the top level, so the signature a root run\n // mints is byte-for-byte the one it minted before nesting existed.\n path: this.pathPrefix.length > 0 ? [...this.pathPrefix] : undefined,\n };\n }\n\n /**\n * The refusal a sub-run running under `onPending: \"deny\"` gives itself.\n *\n * Told to the model rather than dropped, like every other denial: the\n * sub-agent asked for something it cannot have here, and the next step goes\n * better for knowing that than for finding a hole where a result should be.\n */\n private deniedByPolicy(call: ToolCallPart): ToolResultPart {\n return {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"denied\",\n cause: \"refused\",\n reason: `\"${String(call.name)}\" needs the user, and this run was started with onPending: \"deny\". Answer from what you already have.`,\n };\n }\n\n private async executeTool(\n resolved: ResolvedTool,\n messageId: string,\n call: ToolCallPart,\n input: unknown,\n step: number,\n resume?: { answers: ClientToolResult[] },\n ): Promise<ToolResultPart> {\n const ctx: ToolContext = {\n req: this.params.req,\n runId: this.runId,\n threadId: this.params.threadId,\n toolCallId: call.toolCallId,\n signal: this.controller.signal,\n step,\n depth: this.depth,\n resumed: resume !== undefined,\n runAgent: this.nestedRunner(messageId, call, resume),\n };\n\n try {\n const started = resolved.tool.execute!(input as any, ctx);\n let output: unknown;\n if (isAsyncGenerator(started)) {\n let next = await started.next();\n while (!next.done) {\n this.emit({ type: \"tool-progress\", toolCallId: call.toolCallId, data: next.value });\n next = await started.next();\n }\n output = next.value;\n } else {\n output = await started;\n }\n return {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"ok\",\n output,\n };\n } catch (error) {\n if (error instanceof RunAborted || this.controller.signal.aborted) {\n // Left to the abort path, which denies every unresolved call at once.\n throw new RunAborted();\n }\n if (error instanceof PendingEscalation) {\n // The one throw that is not a failure. Turning it into a `tool_error`\n // here would tell the model the tool broke and tell the user nothing,\n // and the question the sub-agent asked would be lost with no trace of\n // where it went — which is precisely the silent failure this branch\n // exists to prevent.\n throw error;\n }\n // A throwing tool is a result, not an exception out of the run: the model\n // is told the call failed and can try something else, which is what a\n // person would do.\n return {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"error\",\n error: {\n code: \"tool_error\",\n message: error instanceof Error ? error.message : String(error),\n toolCallId: call.toolCallId,\n retryable: true,\n },\n };\n }\n }\n\n // --- nested runs -------------------------------------------------------\n\n /**\n * The `ctx.runAgent` given to one tool call, with its own memo.\n *\n * MEMOIZATION IS BY CALL INDEX, and the index is the only key there is. A\n * paused async generator cannot be put into a message history, so an\n * escalating tool is re-entered from the top rather than resumed in place,\n * and the Nth `runAgent` of the re-entered body has to be paired with the Nth\n * sub-run of the previous attempt. `ToolCallPart.nested` is that record, which\n * is also why it lives on the message: it is exactly the history the next turn\n * loads anyway, from the store or from the client.\n *\n * A tool whose `runAgent` calls sit inside a branch or a loop can produce a\n * different sequence on replay, and then index N means two different things.\n * That is checked below rather than trusted — pairing a user's answer with the\n * wrong sub-run is the failure this whole mechanism exists to avoid, and it\n * would be invisible.\n */\n private nestedRunner(\n messageId: string,\n call: ToolCallPart,\n resume?: { answers: ClientToolResult[] },\n ): ToolContext[\"runAgent\"] {\n // Snapshotted before the tool body runs: everything already here came from\n // an earlier turn and is replayable, everything appended past this point is\n // running for the first time.\n const replayable = call.nested?.length ?? 0;\n let index = 0;\n // Created on the first `runAgent` and not before, so a tool that never\n // nests does not put an empty array on every tool call it makes — the part\n // is on the wire and in the store, and an always-present `nested: []` would\n // be a shape change paid for by every app that has no sub-agents.\n const memoize = (): NestedRun[] => call.nested ?? (call.nested = []);\n\n return async (agent: AnyAgent, params: RunAgentParams = {}): Promise<NestedRunResult> => {\n const at = index++;\n const memo = memoize();\n const recorded = at < replayable ? memo[at] : undefined;\n\n if (recorded) {\n const mismatch = replayMismatch(recorded, agent, params);\n if (mismatch) {\n throw new Error(\n `Nested run ${at} of \"${String(call.name)}\" ${mismatch}. ` +\n `runAgent is memoized by call index, so a body whose runAgent calls depend on a condition that changed between turns cannot be resumed — the answer would be paired with a different sub-run. ` +\n `Make the sequence of runAgent calls, and what each one is asked, the same every time this tool runs, or branch on ctx.resumed.`,\n );\n }\n if (recorded.finishReason !== \"awaiting-input\") {\n // The whole point of the memo: no provider is called, no sub-tool\n // runs, and no usage is counted a second time — this turn did not\n // spend it, an earlier one did.\n return {\n runId: recorded.runId,\n agent: recorded.agent,\n messages: recorded.messages,\n finishReason: recorded.finishReason ?? \"stop\",\n usage: recorded.usage ?? emptyUsage(),\n output: outputOf(recorded.messages),\n nested: recorded,\n };\n }\n }\n\n return this.runNested(\n messageId,\n call,\n agent,\n params,\n at,\n memo,\n recorded,\n resume?.answers ?? [],\n );\n };\n }\n\n /**\n * Starts, or continues, one sub-run and joins it to this one.\n *\n * Joining is the only reason this exists — a tool can already make an agent\n * and iterate it. What it cannot do by hand is put the sub-run's events on\n * this run's stream in this run's `seq`, roll its usage up, record its\n * transcript where the next turn will look for it, and carry the depth and\n * the name chain so a cycle is a sentence rather than a stack overflow.\n */\n private async runNested(\n messageId: string,\n call: ToolCallPart,\n agent: AnyAgent,\n params: RunAgentParams,\n at: number,\n memo: NestedRun[],\n recorded: NestedRun | undefined,\n answers: ClientToolResult[],\n ): Promise<NestedRunResult> {\n // Both checks before anything starts, so the failure is a tool result the\n // model can read rather than a partly-run tree. The name chain catches the\n // common cycle (A runs A, A runs B runs A) exactly; the depth limit catches\n // the shapes a name cannot see, such as the same agent under two names.\n const chain = [...this.chain, agent.name];\n if (this.chain.includes(agent.name)) {\n throw new Error(\n `\"${agent.name}\" is already running further up this chain: ${chain.join(\" -> \")}. An agent cannot run itself, directly or through another agent.`,\n );\n }\n const depth = this.depth + 1;\n if (depth > this.maxDepth) {\n throw new Error(\n `Nested agent runs are ${this.maxDepth} deep at most and this one would be ${depth}: ${chain.join(\" -> \")}. Raise maxDepth on the agent at the root of the run if the tree is meant to be this deep.`,\n );\n }\n\n const label = params.label;\n const signingPath = [...this.pathPrefix, call.toolCallId];\n // Inherited downwards and never relaxed: a caller that asked for an\n // autonomous sub-agent must not have a question surface from two levels\n // below it, and only the subtree refusing can promise that.\n const onPending = this.onPending === \"deny\" ? \"deny\" : (params.onPending ?? \"escalate\");\n\n const resuming = recorded !== undefined;\n const open = resuming ? openCallIds(recorded.messages) : new Set<string>();\n // Only the answers this sub-run can actually attach to a call of its own,\n // or route further down. Handing it the rest would make it report a result\n // for a call nobody made.\n const mine = resuming\n ? answers.filter((answer) => {\n const below = pathBelow(answer.path, signingPath);\n if (below === null) return false;\n return open.has(below.length > 0 ? below[0] : answer.toolCallId);\n })\n : [];\n\n const sub = agent.stream({\n // A resume starts from what was persisted, not from what the tool passed\n // this time: the body ran again from the top and rebuilt its `prompt`,\n // and honouring it would replay a first turn the sub-agent has already\n // had. The persisted transcript already contains it.\n messages: resuming ? recorded.messages : (params.messages ?? []),\n turn: resuming\n ? { toolResults: mine }\n : params.prompt\n ? { text: params.prompt }\n : undefined,\n req: this.params.req,\n // Inherited, not new: this is what makes the parent's `stop()` reach a\n // sub-run three levels down without anything in between forwarding it.\n signal: this.controller.signal,\n threadId: this.params.threadId,\n instructions: params.instructions,\n // Kept across turns so the transcript the client already has keeps its\n // identity when the run continues.\n runId: resuming ? recorded.runId : undefined,\n nesting: {\n depth,\n maxDepth: this.maxDepth,\n chain,\n signingRunId: this.signingRunId,\n signingPath,\n onPending,\n },\n }) as AgentRun;\n\n let asked: PendingToolCall[] = [];\n const forwarding: Promise<void> = (async () => {\n for await (const event of sub as AsyncIterable<AgentStreamEvent>) {\n if (event.type === \"awaiting-input\") asked = event.pending;\n this.emit({\n type: \"nested-event\",\n toolCallId: call.toolCallId,\n runId: sub.runId,\n agent: agent.name,\n label,\n event,\n });\n }\n })();\n\n // Recording is its own promise so that the abort path can wait for exactly\n // this — the transcript reaching the tool call — rather than for the whole\n // tool, which may be ignoring the signal.\n const recording = (async () => {\n const result = await sub.result();\n await forwarding;\n // The seed leads, because a run only reports the messages it *made* and\n // `params.messages` is not one of them. Recording the transcript without\n // its opening is two bugs: a resume re-enters the sub-agent with the\n // conversation it was started from missing, and the replay check below\n // has nothing to fingerprint the seed against. Upserted rather than\n // concatenated because the sub-run may have amended one of these on its\n // way through.\n const messages = resuming\n ? mergeMessages(recorded.messages, result.messages)\n : mergeMessages(params.messages ?? [], result.messages);\n const record: NestedRun = {\n runId: sub.runId,\n agent: agent.name,\n label,\n messages,\n finishReason: result.finishReason,\n usage: resuming ? addUsage(recorded.usage ?? emptyUsage(), result.usage) : result.usage,\n // A parked record is what the next turn re-enters the tool on, and in\n // stateless mode it comes back from the browser. Signed here, by the\n // run that knows it is true, over where the sub-run parked, what it is\n // waiting on and the input the tool was running with — `parkedBelow`\n // will not act on a record without it. `call.input` is the parsed\n // value by now, on every path that reaches here, so the transcript\n // carries exactly what was signed.\n ...(result.finishReason === \"awaiting-input\"\n ? {\n signature: signNestedRun({\n runId: this.signingRunId,\n path: signingPath,\n nestedRunId: sub.runId,\n open: [...openCallIds(messages)],\n input: call.input,\n }),\n }\n : {}),\n };\n // Written before anything below can throw. An escalation is a pause, not\n // a lost run, and a cancelled sub-run is still work the user should be\n // able to read — both of those depend on the transcript already being on\n // the part when the throw happens.\n memo[at] = record;\n // Only what this turn actually spent. A memoized sub-run adds nothing,\n // above, because the turn that ran it already counted it.\n this.usage = addUsage(this.usage, result.usage);\n return { result, record };\n })();\n\n const settling = recording.then(\n () => undefined,\n () => undefined,\n );\n this.nestedSettling.add(settling);\n let result: AgentRunResult<ToolShapes, unknown>;\n let record: NestedRun;\n try {\n ({ result, record } = await recording);\n } finally {\n this.nestedSettling.delete(settling);\n }\n\n if (this.controller.signal.aborted) {\n // The sub-run was cancelled by the parent's `stop()`. Failing the tool\n // rather than returning an aborted result is what stops the tool body\n // from carrying on with half an answer while the run around it is dying.\n throw new RunAborted();\n }\n\n if (result.finishReason === \"awaiting-input\") {\n if (asked.length === 0) {\n // Nothing to ask means nothing the client could answer, and escalating\n // an empty list would end the parent awaiting-input with a tool call\n // that can never be resolved.\n throw new Error(\n `\"${agent.name}\" ended awaiting input but asked nothing, so there is no question to escalate.`,\n );\n }\n // The signature is on the server's copy of the record, and a stateless\n // client has built its own from the forwarded events. Re-sending the\n // call is what puts the server's copy in the client's hands to carry\n // back: the reducer takes a re-sent `nested` as authoritative, so this\n // replaces what the client accumulated rather than adding to it. Marked\n // `resent` because it is not a call: the model made this one earlier —\n // in this run or, on a re-park, in a previous one — and a hook that\n // counts calls has already seen it.\n this.emit({ type: \"tool-call\", messageId, part: call, resent: true });\n throw new PendingEscalation({ pending: asked, path: signingPath, nested: record });\n }\n\n return {\n runId: record.runId,\n agent: agent.name,\n messages: record.messages,\n finishReason: result.finishReason,\n usage: record.usage ?? emptyUsage(),\n output: result.output ?? outputOf(record.messages),\n nested: record,\n };\n }\n\n private addResult(message: AgentMessage, part: ToolResultPart) {\n message.content.push(part);\n this.emit({ type: \"tool-result\", messageId: message.id, part });\n }\n\n // --- the client's turn -------------------------------------------------\n\n /**\n * Resolves what the client sent back, then adds its words.\n *\n * Every pending call has to come out of this with a result — signed, refused\n * or implicitly denied. The provider rejects a history holding a tool call\n * with no result, so leaving one open would break not this turn but the next\n * one, at a point where the cause is no longer visible.\n */\n private async ingestTurn(): Promise<PendingToolCall[]> {\n const turn = this.params.turn;\n const open = this.openCalls();\n /** Questions a re-entered tool asked again. The run ends on these. */\n const escalated: PendingToolCall[] = [];\n\n if (open.length > 0) {\n const answered = new Set<string>();\n const seen = new Set<string>();\n /** Answers addressed *below* one of this run's tool calls, grouped by the\n * call that has to be re-entered to deliver them. */\n const reentry = new Map<string, ClientToolResult[]>();\n\n for (const answer of turn?.toolResults ?? []) {\n // One answer per call, first one wins. A turn carrying the same entry\n // twice is a retried submit or a double-clicked form, and without this\n // it ran the approved tool twice and left two results for one\n // toolCallId — a history the provider rejects, arrived at by exactly\n // the machinery that exists to keep the history well formed.\n //\n // Keyed by path *and* id, because a tool-call id is only unique within\n // one run: two sub-agents under two different tools each number their\n // calls from their own provider, and dropping the second as a duplicate\n // would strand the tool that was waiting on it. For a top-level answer\n // the key is the id, exactly as before.\n const key = `${(answer.path ?? []).join(\"/\")}#${answer.toolCallId}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n const reject = (message: string) =>\n this.emit({\n type: \"error\",\n error: {\n code: \"invalid_tool_result\",\n message,\n toolCallId: answer.toolCallId,\n retryable: false,\n },\n });\n\n // The path says which run the answer belongs to; `toolCallId` only says\n // which call *within* that run. Both are covered by the signature, so a\n // client that moves an answer to another tool's sub-run does not\n // redirect anything — it routes the answer somewhere the MAC no longer\n // verifies, which is the property that makes carrying the path safe.\n const below = pathBelow(answer.path, this.pathPrefix);\n if (below === null) {\n reject(\n `The answer for \"${answer.toolCallId}\" is addressed to a tool call this run is not inside.`,\n );\n continue;\n }\n\n if (below.length > 0) {\n const host = below[0];\n const hosting = open.find((entry) => entry.call.toolCallId === host);\n if (!hosting) {\n reject(`No pending tool call with id \"${host}\" to deliver a nested answer to.`);\n continue;\n }\n // THE ONE CHECK THAT MAKES RE-ENTRY SAFE, and the reason it is here\n // rather than in `reenter`.\n //\n // Re-entry runs the tool. Everything else in this method verifies a\n // signature first, but a path cannot be verified here — the claims\n // are the *inner* call's, and only the run that minted them knows its\n // tool, its `kind` and its input, which is why `resolveAnswer` runs\n // down there and not up here. So the decision to execute has to be\n // gated on something the server derived instead: there must be a\n // sub-run parked on this exact call, and it must be waiting on the\n // exact question the answer names. Without this, a turn that posts\n // `{ path: [<any open call>], signature: \"\" }` re-enters a tool that\n // is merely awaiting an *approval* — running, unapproved, a call the\n // user was shown and never said yes to, with its input taken from a\n // client-carried history. Content is still checked below, in the\n // sub-run; this is what stops an unsigned request from choosing to\n // execute at all.\n const parked = this.parkedBelow(hosting.call, below, answer.toolCallId);\n if (parked.ok === false) {\n const under = `The answer for \"${answer.toolCallId}\" is addressed under \"${host}\", which`;\n reject(\n parked.reason === \"unparked\"\n ? `${under} has no sub-agent run waiting on that question.`\n : parked.reason === \"expired\"\n ? `${under} parked a sub-agent run that has since expired. Ask again.`\n : `${under} carries a record of a parked sub-agent run the server did not sign.`,\n );\n continue;\n }\n let group = reentry.get(host);\n if (!group) {\n // Spent here, ahead of the body, for the reason the record is\n // signed at all: re-entry runs the tool before the sub-run gets to\n // refuse a spent answer, so a history rewound to before the result\n // would run it once per replay. Once per record per turn — the\n // sub-run may have asked two things at once, and every answer to\n // it re-enters the same tool a single time.\n if (!consumeNestedRun(parked.signature)) {\n reject(\n `The answer for \"${answer.toolCallId}\" is addressed under \"${host}\", which has already been re-entered on that record. Ask again.`,\n );\n continue;\n }\n group = [];\n reentry.set(host, group);\n // Marked answered so the refusal pass below leaves it alone: the\n // tool is about to be re-entered and will produce the real result.\n answered.add(host);\n }\n group.push(answer);\n continue;\n }\n\n const target = open.find((entry) => entry.call.toolCallId === answer.toolCallId);\n if (!target) {\n // Nothing to attach it to, so it cannot be told to the model even as\n // an error part — a result for a call that was never made.\n reject(`No pending tool call with id \"${answer.toolCallId}\".`);\n continue;\n }\n\n const result = await this.resolveAnswer(target, answer, escalated);\n if (result === null) continue;\n answered.add(answer.toolCallId);\n // `\"open\"` is an approved tool whose own sub-agent asked something on\n // the way through: answered, so the refusal pass leaves it alone, but\n // no result attaches — the call stays open and the next turn re-enters\n // it, exactly as an escalation from the step loop does.\n if (result !== \"open\") this.attachToHistory(target, result);\n }\n\n for (const [host, answers] of reentry) {\n const entry = open.find((item) => item.call.toolCallId === host)!;\n const result = await this.reenter(entry, answers, escalated);\n if (result) this.attachToHistory(entry, result);\n }\n\n for (const entry of open) {\n if (answered.has(entry.call.toolCallId)) continue;\n // The turn said something else. That is a refusal — the honest reading,\n // and the only one that cannot strand the thread. A tool whose\n // sub-agent asked a question and did not get an answer is refused here\n // like any other: the sub-run is abandoned with its transcript intact,\n // and the call gets a result rather than dangling into the next turn.\n this.attachToHistory(entry, {\n type: \"tool-result\",\n toolCallId: entry.call.toolCallId,\n name: entry.call.name,\n status: \"denied\",\n cause: \"refused\",\n });\n }\n\n await this.reportAmended();\n }\n\n if (turn && (turn.text || (turn.files && turn.files.length > 0))) {\n const message: AgentMessage = {\n id: `msg_${crypto.randomUUID()}`,\n role: \"user\",\n content: [\n ...(turn.text ? [{ type: \"text\" as const, text: turn.text }] : []),\n ...(turn.files ?? []).map((file) => ({\n type: \"file\" as const,\n fileId: file.fileId,\n name: file.name,\n mimeType: file.mimeType,\n })),\n ],\n createdAt: new Date().toISOString(),\n finishReason: \"stop\",\n };\n this.history.push(message);\n this.produced.push(message);\n await this.report(message);\n }\n\n return escalated;\n }\n\n /**\n * Whether a sub-run under `call` is actually parked on the question named.\n *\n * The transcript is the server's own record of where the run stopped:\n * `nested` is written from the sub-run's result before the escalation throws,\n * so a call that has never nested has no `nested` at all, and one whose\n * sub-runs all finished has none with `awaiting-input`. In stateless mode\n * that record arrives from the client and could say anything, and what\n * saying it buys is not small: the tool body runs — from the top, with the\n * input the history carries — before the sub-run gets to verify the answer,\n * so everything the body does ahead of its first `runAgent` happens on the\n * client's say-so. Which is why the record has to carry the server's\n * signature over the sub-run it parked, the calls it left open and the\n * input the tool was given, and why a record without one, or with one that\n * does not match what it now says, is not a parked run at all.\n *\n * The failure says which of those it was. \"Expired\" is an ordinary outcome\n * in threaded mode — a question answered a day late — and telling that\n * user the run never parked would send them looking for a bug that is not\n * there; a record that fails its MAC is the other thing entirely, and the\n * two are kept apart for the same reason `resolveAnswer` keeps them apart.\n *\n * `below` is the answer's path with this run's prefix already removed, so\n * `below[0]` is `call` itself and `below[1]`, when there is one, names the\n * call to re-enter one level further down.\n */\n private parkedBelow(\n call: ToolCallPart,\n below: string[],\n toolCallId: string,\n ): { ok: true; signature: string } | { ok: false; reason: \"unparked\" | \"unsigned\" | \"expired\" } {\n const wanted = below.length > 1 ? below[1] : toolCallId;\n const path = [...this.pathPrefix, call.toolCallId];\n const parked = (call.nested ?? []).find(\n (run) => run.finishReason === \"awaiting-input\" && openCallIds(run.messages).has(wanted),\n );\n if (!parked) return { ok: false, reason: \"unparked\" };\n if (typeof parked.signature !== \"string\") return { ok: false, reason: \"unsigned\" };\n const verified = verifyNestedRun(parked.signature, {\n path,\n nestedRunId: parked.runId,\n open: [...openCallIds(parked.messages)],\n input: call.input,\n });\n if (verified.ok === false) {\n return { ok: false, reason: verified.reason === \"expired\" ? \"expired\" : \"unsigned\" };\n }\n return { ok: true, signature: parked.signature };\n }\n\n /**\n * Re-enters a tool whose sub-agent asked the user something.\n *\n * From the top, with `ctx.resumed === true` — there is no other way. A JS\n * async generator cannot be suspended across a turn boundary, so the body\n * runs again and `runAgent` replays its finished sub-runs out of\n * `ToolCallPart.nested` instead of re-running them. Which means the code\n * *before* the escalating `runAgent` runs twice; that bargain is documented on\n * `ToolContext.runAgent` and it is the price of not needing a checkpoint API.\n */\n private async reenter(\n entry: { message: AgentMessage; call: ToolCallPart },\n answers: ClientToolResult[],\n escalated: PendingToolCall[],\n ): Promise<ToolResultPart | null> {\n const name = String(entry.call.name);\n const resolved = this.config.registry.get(name);\n if (!resolved || !resolved.tool.execute) {\n return {\n type: \"tool-result\",\n toolCallId: entry.call.toolCallId,\n name: entry.call.name,\n status: \"error\",\n error: {\n code: \"invalid_tool_result\",\n message: `The tool \"${name}\" no longer exists, so the sub-agent's question cannot be delivered.`,\n toolCallId: entry.call.toolCallId,\n retryable: false,\n },\n };\n }\n\n // Checked the way `runTools` checked the model's arguments. The record's\n // signature has already said this is the input the tool parked on, so what\n // this catches is the tool itself having moved: a schema that changed\n // between the turn that parked and the turn that answers. The tool's typed\n // input is a contract with the tool as it is now, and a value the schema\n // rejects must not reach it — the failure is a result the model can read,\n // exactly like a mis-typed argument on the way in.\n const parsed = resolved.tool.inputSchema.safeParse(entry.call.input);\n if (parsed.ok === false) {\n return {\n type: \"tool-result\",\n toolCallId: entry.call.toolCallId,\n name: entry.call.name,\n status: \"error\",\n error: {\n code: \"invalid_tool_input\",\n message: `Invalid arguments for \"${name}\": ${parsed.errors.join(\", \")}`,\n toolCallId: entry.call.toolCallId,\n retryable: true,\n },\n };\n }\n\n const call = this.amendCall(entry);\n // The parsed value is the only input the call has from here on, as in\n // `runTools` — the clone carries what the tool was actually given.\n call.input = parsed.value;\n try {\n // Step 0, like an approval executed on the way in: this belongs to the\n // turn, not to a step of the loop that has not started yet.\n return await raceAbort(\n this.executeTool(resolved, entry.message.id, call, parsed.value, 0, { answers }),\n this.controller.signal,\n );\n } catch (error) {\n if (error instanceof PendingEscalation) {\n // Asked again. No result attaches, so the call stays open and the next\n // turn re-enters it exactly as this one did.\n escalated.push(...error.pending);\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Clones the tool-call part before a replay writes to its `nested`.\n *\n * The message holding it came from an earlier run and belongs to the caller's\n * `messages` array; the run must not reach back into its own input and change\n * it under a controller that has already persisted it. Cloning the part into\n * the amended copy is also what makes the updated sub-run transcript\n * something `onMessage` can report — see `reportAmended`, which is why the\n * message is marked unreported here even though no result may ever attach.\n */\n private amendCall(entry: { message: AgentMessage; call: ToolCallPart }): ToolCallPart {\n const message = this.amend(entry.message);\n const at = message.content.indexOf(entry.call);\n const call: ToolCallPart = {\n ...entry.call,\n nested: (entry.call.nested ?? []).map((run) => ({ ...run })),\n };\n if (at >= 0) message.content[at] = call;\n this.unreported.add(message);\n return call;\n }\n\n /** Tool calls in the history with no result anywhere after them. */\n private openCalls(): { message: AgentMessage; call: ToolCallPart }[] {\n const resolvedIds = new Set<string>();\n for (const message of this.history) {\n for (const part of message.content) {\n if (part.type === \"tool-result\") resolvedIds.add(part.toolCallId);\n }\n }\n const open: { message: AgentMessage; call: ToolCallPart }[] = [];\n for (const message of this.history) {\n for (const part of message.content) {\n if (part.type === \"tool-call\" && !resolvedIds.has(part.toolCallId)) {\n open.push({ message, call: part });\n }\n }\n }\n return open;\n }\n\n /**\n * Verifies one answer and turns it into a result part, or reports why not.\n *\n * `null` means the call stays unanswered and falls through to the implicit\n * denial above — which is the right outcome for a bad signature: the model\n * must not see a result the server cannot vouch for. `\"open\"` means the\n * opposite: the answer was good, the tool ran, and it is now waiting on a\n * question of its own, so the call must stay open *without* being denied.\n */\n private async resolveAnswer(\n entry: { message: AgentMessage; call: ToolCallPart },\n answer: ClientToolResult,\n escalated: PendingToolCall[],\n ): Promise<ToolResultPart | \"open\" | null> {\n const call = entry.call;\n const name = String(call.name);\n const resolved = this.config.registry.get(name);\n const reject = (message: string) => {\n this.emit({\n type: \"error\",\n error: {\n code: \"invalid_tool_result\",\n message,\n toolCallId: call.toolCallId,\n retryable: false,\n },\n });\n return null;\n };\n\n if (!resolved) {\n return reject(`The tool \"${name}\" no longer exists, so its answer cannot be checked.`);\n }\n const kind = pendingKind(resolved.tool);\n if (!kind) {\n return reject(`\"${name}\" is a server tool with no pending question.`);\n }\n if (typeof answer.signature !== \"string\" || answer.signature.length === 0) {\n return reject(`The answer for \"${name}\" carried no signature.`);\n }\n\n // The issuing run, read out of the token. The turn answering a pending call\n // is a *new* run with a new id, so the id the signature was made under has\n // to travel with the signature — and it is covered by the MAC, so a client\n // that edits it fails below rather than being believed.\n const issued = readSignature(answer.signature);\n if (!issued) {\n return reject(`The signature for \"${name}\" is malformed.`);\n }\n\n // The path is this run's own, not the one the client sent. The client's\n // copy was used to route the answer here and nothing else; recomputing the\n // MAC over what the server issued is what makes a moved answer fail instead\n // of being believed.\n const verified = verifyPendingCall(answer.signature, {\n ...this.claimsFor(call.toolCallId, name, kind, call.input),\n runId: issued.runId,\n });\n\n if (verified.ok === false) {\n return reject(\n verified.reason === \"expired\"\n ? `The approval for \"${name}\" has expired. Ask again.`\n : `The answer for \"${name}\" does not match the call the server made.`,\n );\n }\n\n // Verifying says the server once asked this exact question; spending the\n // nonce says nobody has answered it yet. Without this step a captured token\n // approves the same call every time it is presented — the client rewinds to\n // the history from before the result existed and replays, and the human who\n // approved once has approved forever.\n if (!consumePendingCall(answer.signature)) {\n return reject(`The answer for \"${name}\" has already been used. Ask again.`);\n }\n\n if (\"approve\" in answer) {\n if (kind !== \"approval\") {\n return reject(`\"${name}\" is answered by the client, not approved.`);\n }\n if (answer.approve === true) {\n // Raced against the abort signal exactly as `runTools` does. A tool\n // that does not honour `ctx.signal` must not be able to hold the run\n // open, and this is the one execution outside the loop — a `stop()`\n // landing here used to hang the run forever, which is precisely the\n // dangling state `stop()` exists to prevent.\n //\n // Step 0: the approval landed before this run took its first model\n // step, so it belongs to no step of this loop. `call.input` is the\n // value the signature covers — see `runTools`.\n //\n // Cloned first, for the same reason `reenter` clones: an approved tool\n // may nest, and `nestedRunner` writes `nested` onto the part it is\n // given. That part belongs to the caller's `messages` array, which is\n // an input and not scratch space — and the clone is what makes the\n // sub-run transcript something `onMessage` can report.\n const executing = this.amendCall(entry);\n try {\n return await raceAbort(\n this.executeTool(resolved, entry.message.id, executing, executing.input, 0),\n this.controller.signal,\n );\n } catch (error) {\n if (error instanceof PendingEscalation) {\n // An approval whose tool asked the user something of its own. The\n // step loop and `reenter` both collect this; without the same catch\n // here the rejection left `ingestTurn` and was normalized into a\n // `provider_error`, which ended the run with the sub-agent's\n // question thrown away and the approval's nonce already spent.\n escalated.push(...error.pending);\n return \"open\";\n }\n throw error;\n }\n }\n return {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"denied\",\n cause: \"refused\",\n reason: answer.reason,\n };\n }\n\n if (\"output\" in answer) {\n if (kind === \"approval\") {\n // An approval is a tool the *server* runs. A client handing back its\n // output would be fabricating a result, not approving one.\n return reject(`\"${name}\" is approved, not answered: the server produces its result.`);\n }\n const schema = resolved.tool.outputSchema;\n const parsed = schema ? schema.safeParse(answer.output) : { ok: true as const, value: answer.output };\n if (parsed.ok === false) {\n return {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"error\",\n error: {\n code: \"invalid_tool_result\",\n message: `The answer for \"${name}\" did not match its output schema: ${parsed.errors.join(\", \")}`,\n toolCallId: call.toolCallId,\n retryable: true,\n },\n };\n }\n return {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"ok\",\n output: parsed.value,\n };\n }\n\n return reject(`The answer for \"${name}\" carried neither an approval nor an output.`);\n }\n\n /**\n * Puts the result next to the call that asked for it.\n *\n * The message being amended came from an earlier run, so it is cloned before\n * it is touched — the caller's `messages` array is an input, not scratch\n * space, and a controller that persisted it would otherwise see it change\n * under it. The clone is reported through `onMessage` and returned in\n * `result()`, which is why a store keyed by message id has to upsert.\n */\n private attachToHistory(\n entry: { message: AgentMessage; call: ToolCallPart },\n result: ToolResultPart,\n ) {\n const message = this.amend(entry.message);\n message.content.push(result);\n this.unreported.add(message);\n this.emit({ type: \"tool-result\", messageId: message.id, part: result });\n }\n\n /** The clone of an earlier run's message that this run may write to. One per\n * message id, so two results for the same message do not fork it. */\n private amend(original: AgentMessage): AgentMessage {\n const existing = this.amended.get(original.id);\n if (existing) return existing;\n const message: AgentMessage = { ...original, content: [...original.content] };\n const index = this.history.indexOf(original);\n if (index >= 0) this.history[index] = message;\n this.produced.push(message);\n this.amended.set(original.id, message);\n return message;\n }\n\n /**\n * Persists the messages this run amended, once each.\n *\n * Called both at the end of `ingestTurn` and from the abort path, because a\n * stop that lands while an approved tool is running has to persist the\n * results that *did* attach this turn — otherwise the work is done, the\n * transcript on the stream shows it, and the store never hears about it.\n */\n private async reportAmended(): Promise<void> {\n const pending = [...this.unreported];\n this.unreported.clear();\n for (const message of pending) await this.report(message);\n }\n\n // --- stopping ----------------------------------------------------------\n\n /**\n * The run's last act: leave a transcript the next turn can be built on.\n *\n * Everything the model asked for and did not get becomes a `denied` result\n * with `cause: \"stopped\"`, and the interrupted message is finalized as\n * `aborted` keeping whatever text it had produced. Both go out on the stream\n * and through `onMessage`. A cancel that merely stopped emitting would leave\n * a dangling tool call, and the provider would reject the history on the very\n * next message the user sent.\n */\n private async finalizeAborted(): Promise<void> {\n // Sub-runs first. They share this run's signal so they are already closing;\n // what is being waited for is the moment each writes its transcript onto\n // its tool call, because everything below this line persists messages.\n if (this.nestedSettling.size > 0) {\n await Promise.all([...this.nestedSettling]);\n }\n // Calls left open anywhere in the history, not just on the message this run\n // was building. A stop that lands while an approval this turn is executing\n // has no current message at all — the call belongs to an *earlier* turn's\n // message — and denying only `this.current` would leave that one dangling\n // in the very transcript this method exists to keep valid.\n for (const entry of this.openCalls()) {\n if (entry.message === this.current) continue;\n this.attachToHistory(entry, {\n type: \"tool-result\",\n toolCallId: entry.call.toolCallId,\n name: entry.call.name,\n status: \"denied\",\n cause: \"stopped\",\n reason: this.stopReason,\n });\n }\n // Results that did attach this turn have not been persisted yet: the report\n // pass at the end of `ingestTurn` is one of the things the abort skipped.\n await this.reportAmended();\n\n const message = this.current;\n if (message) {\n const answered = new Set(\n message.content\n .filter((part): part is ToolResultPart => part.type === \"tool-result\")\n .map((part) => part.toolCallId),\n );\n for (const part of [...message.content]) {\n if (part.type !== \"tool-call\" || answered.has(part.toolCallId)) continue;\n // A call whose arguments were still arriving is finalized too: the\n // client has already been shown it, and an unresolved part is exactly\n // what this method exists to prevent.\n delete part.partial;\n this.addResult(message, {\n type: \"tool-result\",\n toolCallId: part.toolCallId,\n name: part.name,\n status: \"denied\",\n cause: \"stopped\",\n reason: this.stopReason,\n });\n }\n }\n this.finishReason = \"aborted\";\n await this.finalizeMessage(\"aborted\");\n }\n}\n\nfunction pendingKind(tool: AnyAgentTool): \"approval\" | \"question\" | \"client\" | null {\n if (tool.answeredBy === \"client\") {\n // A question is a client tool whose input is the prompt itself. The\n // distinction is for the UI — one renders a dialog, the other runs code —\n // and it costs nothing to carry.\n return tool.inputSchema === questionSchema ? \"question\" : \"client\";\n }\n return tool.requiresApproval ? \"approval\" : null;\n}\n\nfunction parseArgs(args: string): any {\n if (!args || !args.trim()) return {};\n try {\n return JSON.parse(args);\n } catch {\n return args;\n }\n}\n\n/**\n * Resolves a string built by repeated concatenation, in place.\n *\n * `text = text + delta`, run once per streamed token, does not build a string —\n * it builds a rope: a tree of pointers to every fragment, which the engine\n * flattens only when something needs the characters contiguously. A message\n * that nothing reads before it is persisted therefore keeps all of its\n * fragments alive, and the tree costs several times the text.\n *\n * Measured on Bun 1.x, 600 deltas of six characters (a ~450-token answer, 3.5 KB\n * of ASCII): held as a rope, 18.7 KB. Resolved, 3.5 KB — half the UTF-16 size,\n * because a flat ASCII string is stored one byte per character and a rope\n * cannot be. That is 5.3x, and it is paid by every message a store keeps and\n * every run the live registry holds.\n *\n * Indexing is what forces the resolution: `text[0]` cannot be answered without\n * the characters, so the engine collapses the tree and drops the fragments.\n * Nothing is allocated and nothing is copied, which is why this is not\n * `split(\"\").join(\"\")` — that measures the same but allocates one string per\n * character to get there.\n *\n * DO NOT DELETE THIS AS A NO-OP. It reads like one and it is not; the value is\n * the side effect on the receiver. If a future engine does not resolve on\n * index, this silently becomes a real no-op and memory returns to what it is\n * today — a safe failure, which is why it is written as a hint rather than as a\n * round trip through an encoder that would also mangle a lone surrogate.\n */\nfunction resolveRope(text: string): string {\n if (text.length > 0) void text[0];\n return text;\n}\n\nfunction appendText(message: AgentMessage, type: \"text\" | \"reasoning\", delta: string) {\n const last = message.content[message.content.length - 1];\n if (last && last.type === type) {\n (last as { text?: string }).text = ((last as { text?: string }).text ?? \"\") + delta;\n return;\n }\n message.content.push(\n type === \"text\" ? { type: \"text\", text: delta } : { type: \"reasoning\", text: delta },\n );\n}\n\n/**\n * Reasoning is accumulated per ITEM, not per message, and the item's id is kept.\n *\n * This used to go through `appendText`, which merges on the part *type* alone\n * and has nowhere to put an id. Both halves of that were wrong and neither was\n * visible in the transcript:\n *\n * - `request.ts` drops a reasoning item with no id, deliberately — the id is\n * the API's handle on the stored reasoning and a fabricated one would look\n * like continuity that is not there. So an id dropped here meant reasoning\n * was never sent back at all: on a two-step run the model re-derived its\n * own argument from nothing, and the prompt cache (which keys on the\n * literal item) missed every time. Measured against the live Responses API\n * in `live/live.test.ts`: the second call's input carried zero reasoning\n * items.\n * - a step that produces two reasoning items was flattening them into one\n * part, so even with an id there would have been one id for two items'\n * text.\n *\n * A part with no id is still appended rather than dropped: the text is what a\n * UI renders, and a provider that reports no item id (Azure does not always)\n * should still show its thinking. It just cannot be echoed back, which is the\n * bargain `reasoningItem` already documents.\n */\nfunction appendReasoning(message: AgentMessage, id: string | undefined, delta: string) {\n const last = message.content[message.content.length - 1];\n if (last && last.type === \"reasoning\" && last.id === id) {\n last.text = (last.text ?? \"\") + delta;\n return;\n }\n message.content.push(id ? { type: \"reasoning\", id, text: delta } : { type: \"reasoning\", text: delta });\n}\n",
9
+ "import type { AgentError } from \"../types\";\n\n/**\n * A non-2xx response, carried as an exception so the retry loop and\n * `normalizeError` can both read it.\n *\n * The body is kept parsed-if-possible and raw-if-not: OpenAI and Azure both\n * answer `{ error: { message, type, code } }` on a good day, and an HTML error\n * page from a proxy on a bad one, and the bad day is exactly when the text\n * matters.\n */\nexport class ProviderHttpError extends Error {\n readonly status: number;\n readonly body: unknown;\n readonly requestId?: string;\n\n constructor(status: number, body: unknown, requestId?: string) {\n super(`Provider request failed with status ${status}: ${describeBody(body)}`);\n this.name = \"ProviderHttpError\";\n this.status = status;\n this.body = body;\n this.requestId = requestId;\n }\n}\n\n/**\n * The request ran out of time. Its own class because it must not read as a\n * user abort: `stop()` means the person is done, and a timeout means the\n * network was, and only one of those is worth trying again.\n */\nexport class ProviderTimeoutError extends Error {\n readonly timeoutMs: number;\n\n constructor(timeoutMs: number) {\n super(`Provider request timed out after ${timeoutMs}ms`);\n this.name = \"ProviderTimeoutError\";\n this.timeoutMs = timeoutMs;\n }\n}\n\nfunction describeBody(body: unknown): string {\n const detail = errorBody(body);\n if (detail?.message) return detail.message;\n if (typeof body === \"string\") return body.slice(0, 500);\n return \"no error body\";\n}\n\ntype OpenAIErrorBody = { message?: string; type?: string; code?: string; param?: string };\n\nfunction errorBody(body: unknown): OpenAIErrorBody | null {\n if (!body || typeof body !== \"object\") return null;\n const wrapper = body as { error?: unknown };\n const inner = wrapper.error && typeof wrapper.error === \"object\" ? wrapper.error : body;\n const e = inner as OpenAIErrorBody & { innererror?: { code?: string } };\n if (typeof e.message !== \"string\" && typeof e.code !== \"string\" && typeof e.type !== \"string\") {\n return null;\n }\n // Azure hides the interesting code one level down when its content filter\n // fires, and the outer code is the useless `content_filter`.\n const code = e.innererror?.code ?? e.code;\n return { message: e.message, type: e.type, code, param: e.param };\n}\n\n/**\n * Provider failures onto `AgentErrorCode`.\n *\n * The contract an app is buying here is that it can branch on `rate_limited`\n * without knowing whose rate limit it was, and on `retryable` without knowing\n * which of the two APIs answered. So `retryable` is set from what is actually\n * true of the failure — a 429 from a spent quota is not retryable no matter\n * what its status code says, and neither is a request that will be too long\n * again next time.\n */\nexport function normalizeProviderError(error: unknown): AgentError {\n if (error instanceof ProviderTimeoutError) {\n return { code: \"provider_error\", message: error.message, retryable: true };\n }\n\n if (isAbort(error)) {\n return { code: \"aborted\", message: \"The request was aborted.\", retryable: false };\n }\n\n if (error instanceof ProviderHttpError) {\n return fromStatus(error.status, errorBody(error.body), error.message);\n }\n\n // `fetch` rejects with a TypeError for DNS failures, refused connections and\n // dropped sockets. Every one of those is worth another attempt.\n if (error instanceof TypeError) {\n return {\n code: \"provider_error\",\n message: `Could not reach the provider: ${error.message}`,\n retryable: true,\n };\n }\n\n if (error instanceof Error) {\n return { code: \"provider_error\", message: error.message, retryable: false };\n }\n\n return { code: \"unknown\", message: String(error), retryable: false };\n}\n\nfunction fromStatus(\n status: number,\n body: OpenAIErrorBody | null,\n fallbackMessage: string,\n): AgentError {\n const message = body?.message ?? fallbackMessage;\n const code = (body?.code ?? \"\").toLowerCase();\n const type = (body?.type ?? \"\").toLowerCase();\n const haystack = `${code} ${type} ${message}`.toLowerCase();\n\n if (status === 429) {\n // A spent quota answers 429 and will answer 429 for the rest of the month.\n // Retrying it is how a run turns one billing problem into `maxRetries`\n // billing problems and a much later error message.\n const outOfCredit = code === \"insufficient_quota\" || haystack.includes(\"quota\");\n return { code: \"rate_limited\", message, retryable: !outOfCredit };\n }\n\n if (status >= 500 || status === 408 || status === 409) {\n return { code: \"provider_error\", message, retryable: true };\n }\n\n if (isContextLength(haystack)) {\n return { code: \"context_length_exceeded\", message, retryable: false };\n }\n\n if (isContentFilter(haystack)) {\n return { code: \"content_filtered\", message, retryable: false };\n }\n\n // A schema the API refused. It is our request that is wrong, so the run\n // should surface it as a tool problem rather than a generic outage.\n if (body?.param?.startsWith(\"tools\") || haystack.includes(\"invalid schema for function\")) {\n return { code: \"invalid_tool_input\", message, retryable: false };\n }\n\n return { code: \"provider_error\", message, retryable: false };\n}\n\nfunction isContextLength(haystack: string): boolean {\n return (\n haystack.includes(\"context_length_exceeded\") ||\n haystack.includes(\"maximum context length\") ||\n haystack.includes(\"context window\") ||\n haystack.includes(\"reduce the length\")\n );\n}\n\nfunction isContentFilter(haystack: string): boolean {\n return (\n haystack.includes(\"content_filter\") ||\n haystack.includes(\"content_policy_violation\") ||\n haystack.includes(\"responsibleaipolicyviolation\") ||\n haystack.includes(\"content management policy\")\n );\n}\n\nfunction isAbort(error: unknown): boolean {\n if (!error || typeof error !== \"object\") return false;\n const e = error as { name?: string; code?: string };\n return e.name === \"AbortError\" || e.code === \"ABORT_ERR\";\n}\n",
10
+ "import { normalizeProviderError, ProviderHttpError, ProviderTimeoutError } from \"./errors\";\n\nexport type FetchLike = (input: string, init: RequestInit) => Promise<Response>;\n\nexport type RequestOptions = {\n maxRetries: number;\n timeoutMs: number;\n signal?: AbortSignal;\n /** Injected by the tests. Nothing here should ever need a real socket to be\n * exercised, and a retry policy that is only tested against a live API is\n * one that gets tested during an outage. */\n fetchImpl?: FetchLike;\n /** Takes the caller's signal so the default can clear its timer rather than\n * hold the process open for a backoff nobody is waiting for any more. An\n * injected sleep may ignore it: the wait is raced against the abort either\n * way. */\n sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;\n random?: () => number;\n now?: () => number;\n};\n\n/** The floor of the backoff. Doubling from here gives 0.5s, 1s, 2s, 4s — long\n * enough to outlast a rate-limit window, short enough that a user watching a\n * stream does not assume it died. */\nconst BASE_DELAY_MS = 500;\nexport const MAX_DELAY_MS = 20_000;\n\n/**\n * `Retry-After` in either of its two legal forms: seconds, or an HTTP date.\n *\n * Honoured rather than ignored because the server knows when its window\n * reopens and we are guessing. A value in the past clamps to zero; a garbage\n * value falls back to the computed backoff, since a header we cannot read is\n * not a reason to give up on the request.\n *\n * Parsed here, bounded at the call site: this returns what the server said.\n */\nexport function parseRetryAfter(value: string | null | undefined, now: number): number | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n if (/^\\d+(\\.\\d+)?$/.test(trimmed)) return Math.max(0, Number(trimmed) * 1000);\n const date = Date.parse(trimmed);\n if (Number.isNaN(date)) return undefined;\n return Math.max(0, date - now);\n}\n\n/**\n * Exponential backoff with full jitter. The jitter is the point: without it,\n * every request that got rate limited at the same moment retries at the same\n * moment, and the second wave is the same size as the first.\n */\nexport function backoffDelayMs(attempt: number, random: () => number): number {\n const ceiling = Math.min(MAX_DELAY_MS, BASE_DELAY_MS * 2 ** attempt);\n return Math.round(ceiling * (0.5 + random() * 0.5));\n}\n\nfunction isRetryableStatus(status: number): boolean {\n // 429 and the 5xx range. 409 is in here because OpenAI answers it for a\n // request that raced with something on their side, and it succeeds on the\n // second try.\n return status === 429 || status === 408 || status === 409 || status >= 500;\n}\n\n/**\n * One retry policy, not two.\n *\n * The status table alone cannot answer this: a 429 from a spent quota is a 429\n * every time for the rest of the month, and retrying it turns one billing\n * problem into `maxRetries` of them and a much later error message. Only the\n * body says which 429 this is, and `normalizeProviderError` is where that is\n * already read — so it is asked here rather than left to disagree with a table\n * after the retries have happened.\n *\n * It is a veto, not a second opinion: the table decides which statuses are\n * worth another attempt and the normalized verdict can only take one away.\n * That way a future change to the error mapping cannot start retrying 400s.\n */\nfunction shouldRetry(status: number, error: ProviderHttpError): boolean {\n return isRetryableStatus(status) && normalizeProviderError(error).retryable;\n}\n\nfunction abortReason(signal: AbortSignal): unknown {\n return signal.reason ?? new DOMException(\"The operation was aborted.\", \"AbortError\");\n}\n\nfunction defaultSleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(resolve, ms);\n signal?.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n reject(abortReason(signal));\n },\n { once: true },\n );\n });\n}\n\n/**\n * One HTTP call, retried.\n *\n * The timeout covers getting a response, not consuming one. A streamed answer\n * legitimately takes minutes, and a timeout that kept running would cut off\n * long completions at exactly the point where they were most expensive to\n * abandon — so the timer is cleared once the headers land, and only the\n * caller's own signal can end the body.\n */\nexport async function requestWithRetry(\n url: string,\n init: RequestInit,\n options: RequestOptions,\n): Promise<Response> {\n const doFetch = options.fetchImpl ?? ((u: string, i: RequestInit) => fetch(u, i));\n const sleep = options.sleep ?? defaultSleep;\n const random = options.random ?? Math.random;\n const now = options.now ?? Date.now;\n const maxRetries = Math.max(0, options.maxRetries);\n\n /**\n * A backoff nobody can interrupt is a `stop()` that does not stop.\n *\n * The wait is where a retrying request spends nearly all of its time — up to\n * 20 seconds of it — and noticing the abort only at the top of the next\n * iteration means the run holds its state, and the user watches a cancelled\n * stream, for the rest of the window. So the sleep loses a race with the\n * signal, and the abort propagates like any other.\n */\n const wait = async (ms: number): Promise<void> => {\n const signal = options.signal;\n if (!signal) return await sleep(ms);\n signal.throwIfAborted();\n let onAbort: (() => void) | undefined;\n try {\n await Promise.race([\n sleep(ms, signal),\n new Promise<never>((_resolve, reject) => {\n onAbort = () => reject(abortReason(signal));\n signal.addEventListener(\"abort\", onAbort, { once: true });\n }),\n ]);\n } finally {\n if (onAbort) signal.removeEventListener(\"abort\", onAbort);\n }\n };\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n options.signal?.throwIfAborted();\n\n const controller = new AbortController();\n const abortOuter = () => controller.abort(options.signal?.reason);\n options.signal?.addEventListener(\"abort\", abortOuter, { once: true });\n\n let timedOut = false;\n const timer =\n options.timeoutMs > 0\n ? setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, options.timeoutMs)\n : undefined;\n\n let response: Response;\n try {\n response = await doFetch(url, { ...init, signal: controller.signal });\n } catch (error) {\n if (timer !== undefined) clearTimeout(timer);\n options.signal?.removeEventListener(\"abort\", abortOuter);\n // The caller's abort wins outright — `stop()` means stop, not \"stop and\n // try three more times\".\n if (options.signal?.aborted) throw error;\n lastError = timedOut ? new ProviderTimeoutError(options.timeoutMs) : error;\n if (attempt === maxRetries) throw lastError;\n await wait(backoffDelayMs(attempt, random));\n continue;\n }\n\n if (timer !== undefined) clearTimeout(timer);\n\n if (response.ok) {\n // Deliberately left attached: the caller is about to read a stream, and\n // its own signal has to keep reaching it.\n return response;\n }\n\n options.signal?.removeEventListener(\"abort\", abortOuter);\n const body = await readErrorBody(response);\n const error = new ProviderHttpError(\n response.status,\n body,\n response.headers.get(\"x-request-id\") ?? undefined,\n );\n\n if (attempt === maxRetries || !shouldRetry(response.status, error)) throw error;\n\n // Bounded, because `Retry-After` is a number the server chooses and a daily\n // quota answers it in hours. Sleeping through that holds the run open for\n // the whole window; waking early costs one request that gets the same 429\n // and a longer, still-bounded backoff after it.\n const retryAfter = parseRetryAfter(response.headers.get(\"retry-after\"), now());\n await wait(\n retryAfter === undefined\n ? backoffDelayMs(attempt, random)\n : Math.min(retryAfter, MAX_DELAY_MS),\n );\n lastError = error;\n }\n\n // Unreachable: the loop either returns or throws. Kept honest rather than\n // asserted away.\n throw lastError ?? new Error(\"Provider request failed with no response.\");\n}\n\nasync function readErrorBody(response: Response): Promise<unknown> {\n let text: string;\n try {\n text = await response.text();\n } catch {\n return null;\n }\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n",
11
+ "import type { ProviderEvent } from \"../AgentProvider\";\nimport type { Usage } from \"../types\";\n\n/**\n * The Responses SSE stream to `ProviderEvent`.\n *\n * Also a pure function over chunks, for the same reason the request builder is:\n * everything that breaks here breaks on a byte boundary or a malformed frame,\n * and neither needs a network to reproduce. The tests drive it with recorded\n * fixture strings, including one fed a byte at a time.\n */\n\nexport type SSEMessage = { event: string; data: string; id?: string };\n\n/**\n * Chunks to SSE messages.\n *\n * Written out rather than reached for as a one-liner because every shortcut\n * here is a bug that only shows up under load. A frame split across two chunks\n * is the normal case, not the edge case — TCP has no idea what an event is.\n * Multi-line `data:` is spec, comment lines beginning with `:` are what\n * keepalives look like, and a `\\r\\n` stream is what you get through some\n * proxies.\n */\nexport async function* sseMessages(\n chunks: AsyncIterable<string> | Iterable<string>,\n): AsyncGenerator<SSEMessage> {\n let buffer = \"\";\n let event = \"\";\n let data: string[] = [];\n let id: string | undefined;\n\n const dispatch = (): SSEMessage | null => {\n if (data.length === 0 && !event) return null;\n const message: SSEMessage = { event, data: data.join(\"\\n\"), id };\n event = \"\";\n data = [];\n id = undefined;\n // A frame with a name but no data is legal and carries nothing we want.\n return message.data ? message : null;\n };\n\n const handleLine = (rawLine: string): SSEMessage | null => {\n // Trailing CR from a `\\r\\n` stream. Stripping it here rather than\n // normalizing the whole buffer keeps a CR that lands on a chunk boundary\n // from being counted as a line ending of its own.\n const line = rawLine.endsWith(\"\\r\") ? rawLine.slice(0, -1) : rawLine;\n if (line === \"\") return dispatch();\n // Keepalive. Servers send these so idle connections survive proxies, and a\n // parser that treats one as data corrupts the next real frame.\n if (line.startsWith(\":\")) return null;\n\n const colon = line.indexOf(\":\");\n const field = colon === -1 ? line : line.slice(0, colon);\n let value = colon === -1 ? \"\" : line.slice(colon + 1);\n if (value.startsWith(\" \")) value = value.slice(1);\n\n if (field === \"event\") event = value;\n else if (field === \"data\") data.push(value);\n else if (field === \"id\") id = value;\n return null;\n };\n\n for await (const chunk of chunks as AsyncIterable<string>) {\n buffer += chunk;\n let newline = buffer.indexOf(\"\\n\");\n while (newline !== -1) {\n const line = buffer.slice(0, newline);\n buffer = buffer.slice(newline + 1);\n const message = handleLine(line);\n if (message) yield message;\n newline = buffer.indexOf(\"\\n\");\n }\n }\n\n // A stream that ends without its final blank line still has one frame in it.\n if (buffer.length > 0) {\n const message = handleLine(buffer);\n if (message) yield message;\n }\n const last = dispatch();\n if (last) yield last;\n}\n\ntype ParseOptions = {\n /**\n * Set when the agent declared an `output` schema. The same\n * `response.output_text.delta` carries prose in one case and the JSON of the\n * final answer in the other, and only the caller knows which it asked for.\n */\n structuredOutput?: boolean;\n};\n\ntype PendingCall = { callId: string; name: string; namespace?: string; done: boolean };\n\nexport async function* parseResponsesStream(\n chunks: AsyncIterable<string> | Iterable<string>,\n options: ParseOptions = {},\n): AsyncGenerator<ProviderEvent> {\n // Keyed by `item_id`, because the argument deltas name the item and not the\n // call, and the call id is what the rest of gemi pairs results on.\n const calls = new Map<string, PendingCall>();\n const searchesReported = new Set<string>();\n let finished = false;\n\n for await (const message of sseMessages(chunks)) {\n if (message.data === \"[DONE]\") break;\n\n let payload: Record<string, any>;\n try {\n payload = JSON.parse(message.data);\n } catch {\n // A frame we cannot read is not a reason to abandon a stream that is\n // otherwise fine; the terminal event is what decides how this ended.\n continue;\n }\n\n // The event name is duplicated in the payload's own `type`. Preferring the\n // payload means a gateway that drops the `event:` line still parses, and\n // the two never disagree in practice.\n const type: string = typeof payload.type === \"string\" ? payload.type : message.event;\n\n switch (type) {\n case \"response.output_text.delta\": {\n const delta = String(payload.delta ?? \"\");\n if (!delta) break;\n yield options.structuredOutput\n ? { type: \"output-delta\", delta }\n : { type: \"text-delta\", delta };\n break;\n }\n\n // Two names for the same thing across model generations: the summary\n // stream and, on models that expose it, the reasoning text itself.\n case \"response.reasoning_summary_text.delta\":\n case \"response.reasoning_text.delta\": {\n const delta = String(payload.delta ?? \"\");\n if (!delta) break;\n yield { type: \"reasoning-delta\", delta, id: payload.item_id };\n break;\n }\n\n case \"response.output_item.added\": {\n const item = payload.item as Record<string, any> | undefined;\n if (!item) break;\n if (item.type === \"function_call\") {\n const itemId = String(item.id ?? payload.item_id ?? item.call_id ?? \"\");\n calls.set(itemId, {\n callId: String(item.call_id ?? itemId),\n // FLAT, and pinned by a test against the recorded stream. A call to\n // a function inside a namespace comes back as\n // `{name:\"getOrder\", namespace:\"crm\"}` — not `\"crm.getOrder\"` — so\n // the name is already the registry key `Agent` looks tools up by,\n // and qualifying it here would break every lookup. The namespace is\n // carried alongside rather than folded in, because a name that is\n // sometimes qualified is a name nothing can match on.\n name: String(item.name ?? \"\"),\n namespace: typeof item.namespace === \"string\" && item.namespace\n ? item.namespace\n : undefined,\n done: false,\n });\n }\n break;\n }\n\n case \"response.function_call_arguments.delta\": {\n const call = calls.get(String(payload.item_id ?? \"\"));\n if (!call) break;\n const argsDelta = String(payload.delta ?? \"\");\n if (!argsDelta) break;\n yield {\n type: \"tool-call-delta\",\n toolCallId: call.callId,\n name: call.name,\n argsDelta,\n // Spread rather than `namespace: call.namespace`: a flat tool has no\n // namespace, and an explicit `undefined` is a key a consumer has to\n // remember to check for.\n ...(call.namespace ? { namespace: call.namespace } : {}),\n };\n break;\n }\n\n case \"response.function_call_arguments.done\": {\n const itemId = String(payload.item_id ?? \"\");\n const call = calls.get(itemId);\n if (!call) break;\n call.done = true;\n yield {\n type: \"tool-call\",\n toolCallId: call.callId,\n name: call.name,\n args: String(payload.arguments ?? \"\"),\n ...(call.namespace ? { namespace: call.namespace } : {}),\n };\n break;\n }\n\n case \"response.output_item.done\": {\n const item = payload.item as Record<string, any> | undefined;\n if (!item) break;\n\n if (item.type === \"function_call\") {\n const itemId = String(item.id ?? payload.item_id ?? item.call_id ?? \"\");\n const call = calls.get(itemId);\n // Belt and braces: a call whose arguments never got a `done` event\n // still has to reach the agent, or the loop waits for a step that\n // will not arrive.\n if (call?.done) break;\n const namespace =\n (typeof item.namespace === \"string\" ? item.namespace : \"\") || call?.namespace;\n yield {\n type: \"tool-call\",\n toolCallId: String(item.call_id ?? itemId),\n name: String(item.name ?? call?.name ?? \"\"),\n args: String(item.arguments ?? \"\"),\n ...(namespace ? { namespace } : {}),\n };\n if (call) call.done = true;\n break;\n }\n\n if (item.type === \"tool_search_call\" || item.type === \"tool_search_output\") {\n // The call and its output are one thing to a user — \"went looking,\n // found these\" — so they collapse into one event. Two mechanisms do\n // that, and which one fires depends on what the server sent:\n //\n // 1. THE PAIR IS LINKED. The documented shape puts\n // `tool_search_call_id` on the output item, naming the call item's\n // id, so both sides key the same and the second one is dropped.\n //\n // 2. THE PAIR IS NOT LINKED, which is what the live API actually\n // sends. In `__fixtures__/openai-tool-search.sse` the call is\n // `tsc_08945…`, the output is `tso_08945…`, `call_id` is null on\n // both and neither carries `tool_search_call_id` — so there is\n // nothing to pair them on. What collapses them there is the\n // `found` check below: only the OUTPUT item carries a `tools`\n // array, and the call item carries the query it ran\n // (`arguments.paths`), which is not a result and is not reported\n // as one.\n //\n // That second one used to be load-bearing and unwritten — the dedup\n // key was doing nothing and the length check was doing all the work\n // by accident. Both are tested now: \"the tool_search call and its\n // output collapse into one event\" in `stream.test.ts` covers (1), and\n // \"nothing in the recording links the search call to its output\"\n // plus \"reports one event from the real stream, despite that\" in\n // `recordings.test.ts` cover (2).\n const found = toolSearchReport(item);\n if (found.loaded.length === 0 && found.namespaces.length === 0) break;\n const key = String(item.tool_search_call_id ?? item.id ?? \"\");\n if (searchesReported.has(key)) break;\n searchesReported.add(key);\n yield { type: \"tool-search\", ...found };\n }\n break;\n }\n\n // A refusal is the model declining, and it arrives as its own item rather\n // than as an HTTP status. Reporting it as text would put the refusal in\n // the transcript as if it were an answer.\n case \"response.refusal.done\": {\n yield {\n type: \"error\",\n error: {\n code: \"content_filtered\",\n message: String(payload.refusal ?? \"The model refused to answer.\"),\n retryable: false,\n },\n };\n break;\n }\n\n case \"response.completed\": {\n finished = true;\n yield { type: \"finish\", reason: \"stop\", usage: toUsage(payload.response?.usage) };\n break;\n }\n\n /**\n * Two very different endings share this frame, and the old code called\n * both of them \"stop\".\n *\n * `max_output_tokens` is a truncated answer. `content_filter` is Azure\n * blocking the request — verified against\n * `__fixtures__/azure-content-filtered.sse`, where a prompt that trips\n * the filter answers HTTP 200, streams a polite refusal, and ends\n * `response.incomplete` with `incomplete_details.reason` of\n * `content_filter`. Reporting that as a clean stop tells the agent the\n * model finished talking, which is exactly the mistake `content_filtered`\n * exists to prevent: the run reads as a normal answer, the loop takes\n * another step, and nothing anywhere says the content was blocked.\n *\n * The detail comes off Azure's `content_filters` array rather than off\n * the frame, because `incomplete_details` carries the word\n * `content_filter` and nothing else — no category, no severity.\n */\n case \"response.incomplete\": {\n finished = true;\n const usage = toUsage(payload.response?.usage);\n const reason = payload.response?.incomplete_details?.reason;\n if (reason === \"content_filter\") {\n yield {\n type: \"error\",\n error: {\n code: \"content_filtered\",\n message: describeContentFilters(payload.response?.content_filters),\n retryable: false,\n },\n };\n yield { type: \"finish\", reason: \"error\", usage };\n break;\n }\n yield {\n type: \"finish\",\n reason: reason === \"max_output_tokens\" ? \"length\" : \"stop\",\n usage,\n };\n break;\n }\n\n case \"response.failed\":\n case \"error\": {\n finished = true;\n const raw = payload.response?.error ?? payload.error ?? payload;\n yield { type: \"error\", error: normalizeStreamError(raw) };\n yield { type: \"finish\", reason: \"error\", usage: toUsage(payload.response?.usage) };\n break;\n }\n }\n\n if (finished) return;\n }\n\n // The connection closed with no terminal event: a dropped socket, a proxy\n // timing out, a process going away mid-answer. Reporting it as a clean stop\n // would tell the agent the model finished talking, and it did not — so this\n // is an error, and a retryable one, because the same request usually works.\n if (!finished) {\n yield {\n type: \"error\",\n error: {\n code: \"provider_error\",\n message: \"The provider stream ended without a terminal event.\",\n retryable: true,\n },\n };\n yield { type: \"finish\", reason: \"error\", usage: emptyUsage() };\n }\n}\n\n/**\n * What a tool search actually pulled in.\n *\n * The entries of `tool_search_output.tools` are NAMESPACES, not functions:\n *\n * [{type:\"namespace\", name:\"crm\", tools:[{type:\"function\", name:\"listOrders\"},\n * {type:\"function\", name:\"getOrder\"}]}]\n *\n * — verified against `__fixtures__/openai-tool-search.sse`. Reading `name` off\n * the top level, which is what this did, reported `loaded: [\"crm\"]` for a\n * search that loaded `listOrders` and `getOrder`. The names it reported were\n * not names of tools, and nothing downstream could tell, because a namespace\n * name is a plausible tool name.\n *\n * BOTH HALVES ARE REPORTED. \"Searched crm, loaded getOrder\" is the sentence a\n * UI wants, and neither field can be recovered from the other: flattening to\n * `crm.getOrder` would invent a name the model never used (calls come back with\n * a flat `name` — see the `function_call` branch above), and dropping the\n * namespace throws away the only description of the *group*, which is the thing\n * the model actually chose between.\n *\n * The shape is read structurally rather than off `type === \"namespace\"`: an\n * entry with a `tools` array is a group whatever it calls itself, and the\n * hand-written fixtures that predate the recording use `results:[{name}]` with\n * no `type` at all.\n */\ntype ToolSearchReport = { loaded: string[]; namespaces: string[] };\n\nfunction toolSearchReport(item: Record<string, any>): ToolSearchReport {\n const loaded: string[] = [];\n const namespaces: string[] = [];\n collectToolNames(item.results ?? item.tools ?? item.loaded ?? item.output, loaded, namespaces, 0);\n return { loaded: unique(loaded), namespaces: unique(namespaces) };\n}\n\nfunction collectToolNames(\n raw: unknown,\n loaded: string[],\n namespaces: string[],\n depth: number,\n): void {\n // Nesting is one level deep today and a namespace of namespaces is not a\n // thing. The cap is here so a payload that disagrees costs a truncated event\n // rather than a blown stack in the middle of someone's stream.\n if (!Array.isArray(raw) || depth > 4) return;\n for (const entry of raw) {\n if (typeof entry === \"string\") {\n loaded.push(entry);\n continue;\n }\n if (!entry || typeof entry !== \"object\") continue;\n const e = entry as Record<string, any>;\n const name =\n typeof e.name === \"string\" ? e.name : typeof e.tool_name === \"string\" ? e.tool_name : \"\";\n const children = e.tools ?? e.functions;\n if (Array.isArray(children)) {\n if (name) namespaces.push(name);\n collectToolNames(children, loaded, namespaces, depth + 1);\n continue;\n }\n if (name) loaded.push(name);\n }\n}\n\nfunction unique(names: string[]): string[] {\n return names.filter((name, index) => names.indexOf(name) === index);\n}\n\n/**\n * Azure's `content_filters`, read only where it means something.\n *\n * IT DOES NOT MAP ONTO `content_filtered` ON ITS OWN, and that is the decision\n * worth writing down: the array is on EVERY Azure response — `azure-text.sse`,\n * a recording of \"say hi\", carries it on `response.created`,\n * `response.in_progress` and `response.completed`, with `blocked:false` and\n * every category `severity:\"safe\"`. Treating its presence as a filter hit would\n * report every single Azure call as content-filtered, and treating any\n * `filtered:true` inside it as one would report a *warning* as a block. What is\n * authoritative about the outcome is `incomplete_details.reason`; this array is\n * authoritative only about the DETAIL, which is why it is read for a message\n * and for nothing else.\n *\n * OpenAI sends no such array. It signals a block by refusing in-band\n * (`response.refusal.done`, handled above) or by rejecting the request, so\n * nothing here needs a provider flag — an absent array just yields the generic\n * sentence.\n */\nfunction describeContentFilters(raw: unknown): string {\n const generic = \"The provider's content filter blocked this request.\";\n if (!Array.isArray(raw)) return generic;\n const hits: string[] = [];\n for (const entry of raw) {\n if (!entry || typeof entry !== \"object\") continue;\n const e = entry as Record<string, any>;\n const results = e.content_filter_results;\n if (!results || typeof results !== \"object\") continue;\n for (const [category, detail] of Object.entries(results as Record<string, any>)) {\n if (detail && typeof detail === \"object\" && detail.filtered === true) {\n // The source matters as much as the category: a `prompt` hit means the\n // user's own words were blocked and rewording works, a `completion` hit\n // means the model's answer was, and retrying the same prompt will not.\n hits.push(`${category} (${String(e.source_type ?? \"unknown\")})`);\n }\n }\n }\n return hits.length === 0 ? generic : `${generic} Categories: ${unique(hits).join(\", \")}.`;\n}\n\nfunction normalizeStreamError(raw: any) {\n const message = typeof raw?.message === \"string\" ? raw.message : \"The provider stream failed.\";\n const code = String(raw?.code ?? \"\").toLowerCase();\n if (code === \"rate_limit_exceeded\") {\n return { code: \"rate_limited\" as const, message, retryable: true };\n }\n if (code === \"context_length_exceeded\") {\n return { code: \"context_length_exceeded\" as const, message, retryable: false };\n }\n if (code.includes(\"content_filter\")) {\n return { code: \"content_filtered\" as const, message, retryable: false };\n }\n // Mid-stream failures are overwhelmingly transient — the request was accepted,\n // so it was not malformed.\n return { code: \"provider_error\" as const, message, retryable: true };\n}\n\nexport function emptyUsage(): Usage {\n return { inputTokens: 0, outputTokens: 0, totalTokens: 0 };\n}\n\nexport function toUsage(raw: any): Usage {\n if (!raw) return emptyUsage();\n const inputTokens = Number(raw.input_tokens ?? 0);\n const outputTokens = Number(raw.output_tokens ?? 0);\n const usage: Usage = {\n inputTokens,\n outputTokens,\n totalTokens: Number(raw.total_tokens ?? inputTokens + outputTokens),\n };\n const reasoning = raw.output_tokens_details?.reasoning_tokens;\n if (typeof reasoning === \"number\") usage.reasoningTokens = reasoning;\n const cached = raw.input_tokens_details?.cached_tokens;\n if (typeof cached === \"number\") usage.cachedInputTokens = cached;\n return usage;\n}\n\n/** A `ReadableStream` of bytes to the string chunks the parser wants. Split out\n * so the parser never has to know it came from a socket. */\nexport async function* decodeChunks(\n body: ReadableStream<Uint8Array> | null,\n): AsyncGenerator<string> {\n if (!body) return;\n const reader = body.getReader();\n const decoder = new TextDecoder();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n // `stream: true` matters: a multi-byte character can land across two\n // reads, and decoding each read on its own turns it into two U+FFFDs.\n if (value) yield decoder.decode(value, { stream: true });\n }\n const tail = decoder.decode();\n if (tail) yield tail;\n } finally {\n reader.releaseLock();\n }\n}\n",
12
+ "import type { ProviderEvent } from \"../AgentProvider\";\nimport { normalizeProviderError } from \"./errors\";\nimport { requestWithRetry, type FetchLike } from \"./http\";\nimport type { ResponsesRequest } from \"./request\";\nimport { decodeChunks, emptyUsage, parseResponsesStream } from \"./stream\";\n\n/**\n * The parts of a call that differ between OpenAI and Azure, and nothing else.\n *\n * Two classes, one request path: the differences are a URL, a header and when\n * the credential is read, so those are what gets passed in. Everything below\n * this line — retries, decoding, event translation, what an error looks like —\n * is identical, and duplicating it into the Azure class is how the two would\n * start behaving differently by accident.\n */\nexport type ResponsesEndpoint = {\n responsesUrl: string;\n filesUrl: string;\n /** Async because Entra tokens expire mid-conversation, so the credential has\n * to be read per request rather than per provider. */\n headers: () => Promise<Record<string, string>>;\n timeoutMs: number;\n maxRetries: number;\n fetchImpl?: FetchLike;\n};\n\n/**\n * Errors reach the consumer as events, not exceptions.\n *\n * A `ProviderStream` that threw would make every caller wrap its `for await`,\n * and would lose the deltas already yielded — the agent needs the text it got\n * before the socket died, because the user has already read it.\n */\nexport async function* streamResponses(\n endpoint: ResponsesEndpoint,\n body: ResponsesRequest,\n params: { signal?: AbortSignal; structuredOutput: boolean },\n): AsyncGenerator<ProviderEvent> {\n let response: Response;\n try {\n response = await requestWithRetry(\n endpoint.responsesUrl,\n {\n method: \"POST\",\n headers: { ...(await endpoint.headers()), \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n },\n {\n maxRetries: endpoint.maxRetries,\n timeoutMs: endpoint.timeoutMs,\n signal: params.signal,\n fetchImpl: endpoint.fetchImpl,\n },\n );\n } catch (error) {\n const normalized = normalizeProviderError(error);\n // An abort is not a failure to report: the run was stopped on purpose, and\n // `Agent` is already writing the ending. Saying so twice would put an error\n // in a transcript the user closed themselves.\n if (normalized.code !== \"aborted\") yield { type: \"error\", error: normalized };\n yield {\n type: \"finish\",\n reason: normalized.code === \"aborted\" ? \"aborted\" : \"error\",\n usage: emptyUsage(),\n };\n return;\n }\n\n try {\n yield* parseResponsesStream(decodeChunks(response.body), {\n structuredOutput: params.structuredOutput,\n });\n } catch (error) {\n const normalized = normalizeProviderError(error);\n if (normalized.code === \"aborted\") {\n yield { type: \"finish\", reason: \"aborted\", usage: emptyUsage() };\n return;\n }\n yield { type: \"error\", error: normalized };\n yield { type: \"finish\", reason: \"error\", usage: emptyUsage() };\n }\n}\n\n/**\n * Uploads an attachment and returns the id a `FilePart` carries.\n *\n * `user_data` rather than `assistants`: this is a file a person attached to a\n * message, not a corpus for a retrieval store, and the purpose is what decides\n * which of the two the file can be used for.\n */\nexport async function uploadFile(endpoint: ResponsesEndpoint, file: File): Promise<string> {\n const form = new FormData();\n form.set(\"purpose\", \"user_data\");\n form.set(\"file\", file);\n\n const response = await requestWithRetry(\n endpoint.filesUrl,\n {\n method: \"POST\",\n // No content-type: the boundary is generated with the body, and setting\n // the header by hand is how multipart uploads fail with a parser error\n // that names nothing useful.\n headers: await endpoint.headers(),\n body: form,\n },\n {\n maxRetries: endpoint.maxRetries,\n timeoutMs: endpoint.timeoutMs,\n fetchImpl: endpoint.fetchImpl,\n },\n );\n\n const json = (await response.json()) as { id?: string };\n if (!json?.id) throw new Error(\"The provider accepted the upload but returned no file id.\");\n return json.id;\n}\n",
13
+ "import type { ProviderCapabilities } from \"../AgentProvider\";\n\n/**\n * What a model can do, read off its id.\n *\n * Hardcoding `true` was never an option — `reasoning: { effort }` is a 400 on\n * gpt-4o, and `defer_loading` is a 400 on anything that predates tool search —\n * but neither is a table lookup that only answers for ids we shipped knowing\n * about.\n *\n * SO AN UNKNOWN ID GETS EVERY CAPABILITY. That is the whole point: a model\n * released next Tuesday must be usable by writing its name, not by waiting for\n * a gemi release. The default is chosen for how it fails, not for how often it\n * is right. Guessing high fails loudly and once — the API rejects the request\n * and names the parameter it disliked, and the fix is one line of config.\n * Guessing low fails silently and forever: reasoning is dropped, every deferred\n * schema is inlined, and the only symptom is a bigger bill and a worse answer.\n * Unknown ids also skew new rather than old, because nobody invents the name of\n * a model that already shipped.\n *\n * The named families below exist to make the *known-old* cases right, which is\n * the only place a guess can be wrong in the quiet direction.\n *\n * Note what an answer of `false` does and does not buy. `reasoning: false` and\n * `toolSearch: false` change the request, because both are optimizations and\n * the run is identical without them. `structuredOutput: false` does not: it is\n * reported honestly for a caller that wants to branch on it, but the request\n * builder still sends the schema, because an agent that declared an `output`\n * has an app waiting on a typed result and dropping the parameter would answer\n * prose forever with nothing to branch on. See `request.ts`.\n */\nexport function capabilitiesForModel(model: string): ProviderCapabilities {\n const id = normalizeModelId(model);\n\n // Everything before the tool-era models. Listed by prefix because these names\n // are closed sets now — nothing new will be called `gpt-3.5-*`.\n if (id.startsWith(\"gpt-3.5\") || id.startsWith(\"text-\") || id.startsWith(\"davinci\")) {\n return {\n reasoning: false,\n structuredOutput: false,\n fileInput: false,\n parallelToolCalls: true,\n toolSearch: false,\n };\n }\n\n const family = parseFamily(id);\n\n // o1 reasons but takes its tool calls one at a time; o3/o4 do not have that\n // restriction. Both predate tool search.\n if (family?.kind === \"o\") {\n return {\n reasoning: true,\n structuredOutput: true,\n fileInput: true,\n parallelToolCalls: family.major > 1,\n toolSearch: supportsToolSearch(family),\n };\n }\n\n if (family?.kind === \"gpt\") {\n return {\n // gpt-4 and gpt-4o are strong models with no reasoning parameter at all.\n reasoning: family.major >= 5,\n // Strict `json_schema` landed with gpt-4o; plain gpt-4 only has json_object.\n structuredOutput: family.major > 4 || id.startsWith(\"gpt-4o\") || id.startsWith(\"gpt-4.1\"),\n fileInput: family.major > 4 || id.startsWith(\"gpt-4o\") || id.startsWith(\"gpt-4.1\"),\n parallelToolCalls: true,\n toolSearch: supportsToolSearch(family),\n };\n }\n\n return {\n reasoning: true,\n structuredOutput: true,\n fileInput: true,\n parallelToolCalls: true,\n toolSearch: true,\n };\n}\n\n/**\n * Tool search, by generation.\n *\n * MEASURED, not read off a changelog. Every id below was sent a request\n * carrying `{type:\"tool_search\"}` plus one `namespace` of deferred functions,\n * against `https://api.openai.com/v1/responses`:\n *\n * accepted (200): gpt-5.6-terra, gpt-5.5, gpt-5.4, gpt-5.4-mini,\n * gpt-5.3-codex, gpt-5.2\n * rejected (400): gpt-5.1, gpt-5, gpt-5-mini, gpt-4.1, gpt-4o, o4-mini, o3\n *\n * with the rejection reading, verbatim,\n * `Tool 'tool_search' is not supported with gpt-5.1.` — recorded as\n * `__fixtures__/openai-error-tool-search-unsupported.json`.\n *\n * So the boundary is the *minor* number, and the whole-major rule this used to\n * carry (`major >= 5`) was wrong in the expensive direction for four shipped\n * models: gpt-5, gpt-5-mini and gpt-5.1 would have had `defer_loading` and a\n * `tool_search` tool put in every request and answered 400 on all of them.\n * Reading the minor is the only way to be right here, because gpt-5 and gpt-5.4\n * differ by a decimal point and by this capability.\n *\n * The o-series keeps its `major >= 5` guard rather than being hardcoded false:\n * o1 through o4 are all measured rejections above, and an o5 that does not\n * exist gets the same benefit-of-the-doubt an unknown id gets, for the reason\n * in the module comment.\n */\nfunction supportsToolSearch(family: Family): boolean {\n if (family.kind === \"o\") return family.major >= 5;\n return family.major > 5 || (family.major === 5 && family.minor >= 2);\n}\n\n/**\n * Azure deployment names are chosen by whoever ran the ARM template, so half of\n * them look nothing like a model id. That is not a special case here: an\n * unrecognizable deployment name lands on the same all-true default as an\n * unrecognized model, for the same reason.\n */\nfunction normalizeModelId(model: string): string {\n return model.trim().toLowerCase();\n}\n\nexport type Family = { kind: \"gpt\" | \"o\"; major: number; minor: number };\n\n/**\n * Reads the generation out of `gpt-5.4-mini-2025-01-01` or `o3-mini`.\n *\n * The minor number is read as well as the major, and it is load-bearing: tool\n * search arrived at gpt-5.2, so `gpt-5` and `gpt-5.4` are two different answers\n * to the same question and a major-only reading gets one of them wrong. An id\n * with no minor — `gpt-5`, `gpt-4o`, `o3` — is minor 0, which is what it is.\n *\n * Exported for its own test: the classification is what the guards below are\n * really about, and it is the only place they are observable — two ids can\n * classify differently and still land on the same capability answer today.\n */\nexport function parseFamily(id: string): Family | null {\n const gpt = /^gpt-(\\d+)(?:\\.(\\d+))?/.exec(id);\n if (gpt?.[1]) return { kind: \"gpt\", major: Number(gpt[1]), minor: Number(gpt[2] ?? 0) };\n // `o1`, `o3-mini`, `o4-mini`. The boundary is what keeps an id whose leading\n // digits are not a generation out of this family — `o200k-base` is a\n // tokenizer, not an o-series model, and `/^o(\\d+)/` alone reads it as\n // generation 200. (`omni-moderation` never gets this far: `m` is not a\n // digit.) Both land on the unknown default today, so the boundary is only\n // visible in the classification — which is where a future rule keyed on\n // `major` would read it.\n const o = /^o(\\d+)(?:[-.]|$)/.exec(id);\n // The o-series never had a minor: `o3-mini` is a size, not a point release.\n if (o?.[1]) return { kind: \"o\", major: Number(o[1]), minor: 0 };\n return null;\n}\n",
14
+ "import type {\n ProviderCapabilities,\n ProviderStreamParams,\n ProviderToolNamespace,\n ProviderToolSpec,\n} from \"../AgentProvider\";\nimport type { AgentMessage, ToolResultPart } from \"../types\";\n\n/**\n * Building the request body is a pure function, on purpose.\n *\n * Everything hard about this provider is in here — item ordering, tool-call\n * pairing, what a denied call looks like on the wire — and none of it needs a\n * socket to be wrong. So it is separated from the class that posts it, and the\n * tests assert the object rather than mocking `fetch` and reading a string.\n */\n\n// The wire shapes, typed loosely on purpose: these mirror OpenAI's schema, and\n// a precise mirror is a second thing to keep in sync for no checking we would\n// actually get — the API is the authority and it answers in HTTP.\nexport type ResponsesInputItem = Record<string, unknown>;\nexport type ResponsesTool = Record<string, unknown>;\n\nexport type ResponsesRequest = {\n model: string;\n input: ResponsesInputItem[];\n stream: true;\n instructions?: string;\n tools?: ResponsesTool[];\n parallel_tool_calls?: boolean;\n text?: { format: Record<string, unknown> };\n reasoning?: { effort: string; summary: \"auto\" };\n temperature?: number;\n max_output_tokens?: number;\n};\n\nexport function buildResponsesRequest(\n params: ProviderStreamParams,\n ctx: { model: string; capabilities: ProviderCapabilities },\n): ResponsesRequest {\n const { capabilities } = ctx;\n\n const body: ResponsesRequest = {\n model: ctx.model,\n input: toResponsesInput(params.messages, capabilities),\n stream: true,\n };\n\n if (params.systemPrompt) body.instructions = params.systemPrompt;\n\n const tools = toResponsesTools(params.tools, capabilities);\n if (tools.length > 0) {\n body.tools = tools;\n if (!capabilities.parallelToolCalls) body.parallel_tool_calls = false;\n }\n\n // Deliberately NOT gated on `capabilities.structuredOutput`. An agent that\n // declares `output` has a typed result its app is going to read, and dropping\n // the parameter does not degrade that gracefully — it produces prose, which\n // arrives as `text-delta`, so the app sees no output part, no error and\n // nothing to branch on. That is the silent-forever failure `capabilities.ts`\n // argues against: send it and let the API answer 400, which is loud, happens\n // once, and names the parameter it disliked. `reasoning` is dropped below\n // because it is an optimization; an output schema is the answer's shape.\n if (params.output) {\n body.text = {\n format: {\n type: \"json_schema\",\n name: params.output.name,\n schema: params.output.schema,\n strict: true,\n },\n };\n }\n\n // Dropped rather than refused: a model that cannot reason should still answer\n // an agent that asked it to, because `reasoning` is the agent's preference\n // and the provider is where preferences meet reality.\n if (params.reasoning && capabilities.reasoning) {\n // `summary: \"auto\"` is not decoration — without it the stream carries no\n // reasoning text at all, and `ReasoningPart` would have nothing to hold.\n body.reasoning = { effort: params.reasoning, summary: \"auto\" };\n }\n\n if (typeof params.temperature === \"number\") body.temperature = params.temperature;\n if (typeof params.maxOutputTokens === \"number\") body.max_output_tokens = params.maxOutputTokens;\n\n return body;\n}\n\n// --- messages ------------------------------------------------------------\n\n/**\n * `AgentMessage[]` to Responses input items.\n *\n * Order is preserved *within* a message, not just between messages: a message\n * that holds reasoning, then a tool call, then its result has to arrive in that\n * order, because the API validates the pairing positionally. So text and file\n * parts are buffered into one message item and that buffer is flushed the\n * moment a non-message item appears, rather than emitting all the text first\n * and all the calls after.\n */\nexport function toResponsesInput(\n messages: AgentMessage[],\n capabilities: ProviderCapabilities,\n): ResponsesInputItem[] {\n const items: ResponsesInputItem[] = [];\n\n for (const message of messages) {\n const role = message.role;\n let buffer: Record<string, unknown>[] = [];\n\n const flush = () => {\n if (buffer.length === 0) return;\n items.push({ type: \"message\", role, content: buffer });\n buffer = [];\n };\n\n for (const part of message.content ?? []) {\n switch (part.type) {\n case \"text\": {\n if (!part.text) break;\n buffer.push(textContent(role, part.text));\n break;\n }\n case \"output\": {\n // A structured answer is still the assistant's text as far as the\n // history is concerned; re-serializing it is what lets a follow-up\n // turn refer to what was decided.\n if (part.partial) break;\n buffer.push(textContent(role, JSON.stringify(part.value)));\n break;\n }\n case \"file\": {\n // `input_file` is only legal on an input role. An assistant message\n // holding a file is a bug upstream, and sending it anyway turns that\n // bug into a 400 halfway through a conversation.\n if (!capabilities.fileInput || role === \"assistant\") break;\n buffer.push({ type: \"input_file\", file_id: part.fileId });\n break;\n }\n case \"reasoning\": {\n flush();\n const item = reasoningItem(part);\n if (item) items.push(item);\n break;\n }\n case \"tool-call\": {\n // A partial call is UI state — the arguments were still streaming\n // when this was written down, so what it holds is not what the model\n // asked for. Sending it would create the dangling call the API\n // rejects. If it did acquire a result (a stop landing mid-arguments\n // does exactly that), `reconcileToolPairs` drops that half too.\n if (part.partial) break;\n flush();\n items.push({\n type: \"function_call\",\n call_id: part.toolCallId,\n name: String(part.name),\n arguments: JSON.stringify(part.input ?? {}),\n });\n break;\n }\n case \"tool-result\": {\n flush();\n items.push({\n type: \"function_call_output\",\n call_id: part.toolCallId,\n output: toolResultOutput(part),\n });\n break;\n }\n }\n }\n\n flush();\n }\n\n return reconcileToolPairs(items);\n}\n\n/** What is sent for a call whose result never made it into the history. */\nconst NO_RESULT_RECORDED = \"No result was recorded for this tool call. Assume it did not complete.\";\n\n/**\n * Every `function_call` has exactly one `function_call_output`, and no output\n * stands alone.\n *\n * The loop above skips a `tool-call` marked `partial` — its arguments were\n * still streaming, so it is UI state rather than something the model did — but\n * a partial call can still acquire a result: `stop()` gives every call in\n * flight a `denied`/`stopped` result, and a call whose arguments were mid-flight\n * is exactly the one carrying `partial`. Emitting that result on its own is a\n * 400 (\"no tool call found for function call output\"), and because the history\n * is persisted it is a 400 on every subsequent turn — the thread is bricked,\n * which is the failure `denied` exists to prevent.\n *\n * So the invariant is enforced here rather than assumed part-by-part: an\n * unpartnered output is dropped, a repeated one is dropped, and a call left\n * dangling by a crash between the call and its result gets a synthetic output\n * saying so. Fabricating that line is the lesser evil — it is true, the model\n * can read it, and the alternative is a conversation that can never be\n * continued.\n *\n * A repeated *call* is dropped for the same reason in the other direction. The\n * API happens to accept two `function_call`s under one id, so this is not a\n * 400 — it is the model reading the same call twice, on every turn, for the\n * rest of the conversation. The way it arises is a store that appended the\n * amended copy of a message instead of replacing it; the store contract now\n * says upsert, and this is the guard for a store that did not read it.\n */\nfunction reconcileToolPairs(items: ResponsesInputItem[]): ResponsesInputItem[] {\n const called = new Set<string>();\n const answered = new Set<string>();\n const kept: ResponsesInputItem[] = [];\n\n for (const item of items) {\n if (item.type === \"function_call\") {\n const callId = String(item.call_id);\n if (called.has(callId)) continue;\n called.add(callId);\n } else if (item.type === \"function_call_output\") {\n const callId = String(item.call_id);\n // Positional: the output has to come *after* its call, which is what the\n // API checks, so a call seen later in the history does not rescue it.\n if (!called.has(callId) || answered.has(callId)) continue;\n answered.add(callId);\n }\n kept.push(item);\n }\n\n if (answered.size === called.size) return kept;\n\n const out: ResponsesInputItem[] = [];\n for (const item of kept) {\n out.push(item);\n if (item.type !== \"function_call\") continue;\n const callId = String(item.call_id);\n if (answered.has(callId)) continue;\n answered.add(callId);\n out.push({ type: \"function_call_output\", call_id: callId, output: NO_RESULT_RECORDED });\n }\n return out;\n}\n\nfunction textContent(role: AgentMessage[\"role\"], text: string): Record<string, unknown> {\n return { type: role === \"assistant\" ? \"output_text\" : \"input_text\", text };\n}\n\n/**\n * Reasoning goes back exactly as it came.\n *\n * Reshaping it — flattening the summary into text, renaming the item, dropping\n * the id — costs two things that are hard to see and expensive to have lost:\n * the prompt cache, which keys on the literal item, and on a reasoning model\n * the thread of the model's own argument across turns.\n *\n * An item with no id is dropped instead. The id is the API's handle on stored\n * reasoning, and an item without one is not a reasoning item the API can\n * resolve — sending a summary under a fabricated id would be worse than\n * sending nothing, because it would look like continuity that is not there.\n */\nfunction reasoningItem(part: { id?: string; text?: string }): ResponsesInputItem | null {\n if (!part.id) return null;\n const item: ResponsesInputItem = { type: \"reasoning\", id: part.id };\n item.summary = part.text ? [{ type: \"summary_text\", text: part.text }] : [];\n return item;\n}\n\n/**\n * Every tool call gets an output, including the ones that never ran.\n *\n * The API rejects a history containing a `function_call` with no matching\n * `function_call_output`, so a denial cannot be expressed by omission — and a\n * conversation where the user said no has to stay continuable, which is the\n * whole reason `denied` exists in the first place.\n *\n * What is sent is prose rather than a status enum, because the reader is a\n * language model: it has to be able to tell \"the user refused this\" from \"this\n * blew up\", and those two lead to genuinely different next moves — apologize\n * and ask, versus try another way.\n */\nexport function toolResultOutput(part: ToolResultPart): string {\n if (part.status === \"ok\") {\n return typeof part.output === \"string\" ? part.output : JSON.stringify(part.output ?? null);\n }\n\n if (part.status === \"denied\") {\n const reason = part.reason ? ` Reason given: ${part.reason}` : \"\";\n if (part.cause === \"stopped\") {\n return `The run was stopped before this tool call could complete, so it did not run.${reason}`;\n }\n return `The user declined this tool call, so it did not run.${reason}`;\n }\n\n return `The tool call failed and produced no result. Error (${part.error?.code ?? \"unknown\"}): ${\n part.error?.message ?? \"no message\"\n }`;\n}\n\n// --- tools ---------------------------------------------------------------\n\nfunction isNamespace(\n entry: ProviderToolSpec | ProviderToolNamespace,\n): entry is ProviderToolNamespace {\n return Array.isArray((entry as ProviderToolNamespace).tools);\n}\n\n/**\n * Tools and namespaces onto the Responses `tools` array.\n *\n * Without tool search the grouping has nothing to do — a namespace exists to be\n * searched — so it is flattened away and every schema is sent inline with\n * `deferred` ignored. That is the promise `capabilities.toolSearch` makes:\n * deferral is a token optimization, and an optimization that changed which\n * tools the model can reach would not be one.\n */\nexport function toResponsesTools(\n tools: (ProviderToolSpec | ProviderToolNamespace)[] | undefined,\n capabilities: ProviderCapabilities,\n): ResponsesTool[] {\n if (!tools || tools.length === 0) return [];\n\n if (!capabilities.toolSearch) {\n const flat: ResponsesTool[] = [];\n for (const entry of tools) {\n if (isNamespace(entry)) {\n for (const tool of entry.tools) flat.push(functionTool(tool, false));\n } else {\n flat.push(functionTool(entry, false));\n }\n }\n return flat;\n }\n\n const out: ResponsesTool[] = [];\n let anyDeferred = false;\n\n for (const entry of tools) {\n if (isNamespace(entry)) {\n const inner = entry.tools.map((tool) => {\n if (tool.deferred) anyDeferred = true;\n return functionTool(tool, true);\n });\n out.push({\n type: \"namespace\",\n name: entry.name,\n description: entry.description,\n tools: inner,\n });\n } else {\n if (entry.deferred) anyDeferred = true;\n out.push(functionTool(entry, true));\n }\n }\n\n // Without this the deferred schemas are unreachable: the model is shown a\n // name and a description and given no way to ask for the rest, which is worse\n // than not deferring at all. Added only when something is actually deferred,\n // so an agent that defers nothing does not pay for a tool it cannot use.\n if (anyDeferred) out.push({ type: \"tool_search\" });\n\n return out;\n}\n\nfunction functionTool(tool: ProviderToolSpec, allowDeferred: boolean): ResponsesTool {\n const spec: ResponsesTool = {\n type: \"function\",\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters,\n strict: tool.strict,\n };\n if (allowDeferred && tool.deferred) spec.defer_loading = true;\n return spec;\n}\n",
15
+ "import type { ReasoningEffort } from \"./Agent\";\nimport { streamResponses, uploadFile, type ResponsesEndpoint } from \"./providers/call\";\nimport { capabilitiesForModel } from \"./providers/capabilities\";\nimport { normalizeProviderError } from \"./providers/errors\";\nimport { buildResponsesRequest } from \"./providers/request\";\nimport type { JSONSchema } from \"./Schema\";\nimport type { AgentError, AgentMessage, FinishReason, Usage } from \"./types\";\n\n/**\n * A provider makes one model call. It does not run the tool loop.\n *\n * The split matters: approvals, `maxSteps`, deferred tools, skill loading and\n * persistence are all provider-independent, and putting them in the provider\n * would mean writing them again for the second provider. So the provider's\n * whole job is to translate gemi's messages into a request, and the response\n * stream back into `ProviderEvent`s. Everything above that lives in `Agent`.\n *\n * v1 targets OpenAI's Responses API — native reasoning items and strict\n * structured output without reassembling them by hand. The interface is kept\n * free of anything Responses-specific so a Chat Completions provider (for older\n * Azure deployments and OpenAI-compatible gateways) can be added later without\n * touching Agent, Controller or the client.\n */\n\n/** What a provider will actually honour, so `Agent` can drop the rest rather\n * than have a request rejected at runtime. */\nexport type ProviderCapabilities = {\n reasoning: boolean;\n structuredOutput: boolean;\n fileInput: boolean;\n parallelToolCalls: boolean;\n /**\n * Tool search, and with it deferred loading. Only recent models have it, so a\n * provider that answers `false` is sent every schema inline and the agent\n * runs identically — deferral is a token optimization, and an optimization\n * that changed behaviour when unavailable would not be one.\n */\n toolSearch: boolean;\n};\n\n/** A tool as the model is shown it: schema only, no implementation. */\nexport type ProviderToolSpec = {\n name: string;\n description: string;\n parameters: JSONSchema;\n strict: boolean;\n /** `defer_loading`: send the name and description, withhold the schema until\n * the model searches for it. Ignored when `capabilities.toolSearch` is\n * false. */\n deferred?: boolean;\n};\n\n/** Tools grouped for search. Flattened back to a list by a provider without\n * tool search, since the grouping exists to be searched. */\nexport type ProviderToolNamespace = {\n name: string;\n description: string;\n tools: ProviderToolSpec[];\n};\n\nexport interface ProviderStreamParams {\n messages: AgentMessage[];\n systemPrompt?: string;\n tools?: (ProviderToolSpec | ProviderToolNamespace)[];\n /** Set when the agent declares an `output` schema; the provider turns it into\n * whatever its own strict-JSON parameter is. */\n output?: { name: string; schema: JSONSchema };\n /** Optional: silently dropped by a provider whose `capabilities.reasoning`\n * is false, since a model that cannot reason should not fail a request. */\n reasoning?: ReasoningEffort;\n temperature?: number;\n maxOutputTokens?: number;\n signal?: AbortSignal;\n}\n\n/**\n * The events of a single model call. Deliberately smaller than\n * `AgentStreamEvent`: no run, message, tool-result or approval events, because\n * a provider knows about none of those.\n */\nexport type ProviderEvent =\n | { type: \"text-delta\"; delta: string }\n | { type: \"reasoning-delta\"; delta: string; id?: string }\n /** Arguments arrive as JSON fragments; the provider passes them through and\n * `Agent` assembles and validates against the tool's schema. */\n | {\n type: \"tool-call-delta\";\n toolCallId: string;\n name: string;\n argsDelta: string;\n namespace?: string;\n }\n /**\n * `name` IS FLAT AND STAYS FLAT. This was an open question and the API has\n * answered it: a call to a function that lives inside a namespace comes back\n * as `{name: \"getOrder\", namespace: \"crm\"}`, not as `\"crm.getOrder\"` —\n * recorded in `providers/__fixtures__/openai-tool-search.sse` and pinned by\n * a test that reads that file. So `name` is already the key `Agent`'s tool\n * registry is built on, which is what makes tool names having to be globally\n * unique within an agent (see `ToolNamespace`) the right rule rather than an\n * inconvenience.\n *\n * `namespace` is carried beside it, absent for a tool that was listed bare.\n * It is provenance, not identity: it says which group the model chose to\n * look in, which is worth recording next to the call and is worthless for\n * finding the tool. Folding it into `name` would make a name that is\n * sometimes qualified and sometimes not, and nothing could match on that.\n */\n | { type: \"tool-call\"; toolCallId: string; name: string; args: string; namespace?: string }\n /**\n * The model went looking for a deferred tool and pulled its schema in. Worth\n * surfacing rather than swallowing: it is a step the user paid for, and the\n * pause before it is otherwise unexplained.\n *\n * TWO FIELDS, not one. `loaded` is the function names — `[\"listOrders\",\n * \"getOrder\"]` — and `namespaces` is the groups they came out of —\n * `[\"crm\"]`. Search results arrive as a tree of namespaces containing\n * functions, so a single flat list has to pick one level and throw the other\n * away, and both levels are worth saying: \"searched crm, loaded getOrder\"\n * reads better than either half, and the group is the thing the model\n * actually chose between.\n *\n * `namespaces` is required rather than optional because the parser always\n * knows the answer, and an optional field would let a future provider forget\n * to fill it in silently. Empty means the search returned bare functions.\n */\n | { type: \"tool-search\"; loaded: string[]; namespaces: string[] }\n | { type: \"output-delta\"; delta: string }\n | { type: \"finish\"; reason: FinishReason; usage: Usage }\n | { type: \"error\"; error: AgentError };\n\nexport type ProviderStream = AsyncIterable<ProviderEvent>;\n\nexport type ProviderConfig = {\n apiKey?: string;\n baseURL?: string;\n timeoutMs?: number;\n maxRetries?: number;\n headers?: Record<string, string>;\n};\n\n\n/** Long enough for a reasoning model to think before it says anything, short\n * enough that a hung connection is not mistaken for a slow one. Only covers\n * getting a response; the stream that follows has no deadline. */\nconst DEFAULT_TIMEOUT_MS = 120_000;\nconst DEFAULT_MAX_RETRIES = 2;\n\nfunction env(name: string): string | undefined {\n return typeof process === \"undefined\" ? undefined : process.env?.[name];\n}\n\nexport abstract class AgentProvider {\n abstract readonly model: string;\n abstract readonly capabilities: ProviderCapabilities;\n\n /** The model ids this provider knows about — for autocomplete only; any\n * string is still accepted, because a new model must not require a gemi\n * release to use. */\n static models(): readonly string[] {\n return [];\n }\n\n abstract stream(params: ProviderStreamParams): ProviderStream;\n\n /**\n * Uploads a file and returns the id a `FilePart` carries. Message history\n * therefore holds provider file ids, which is the trade for getting vision\n * and PDF input without gemi owning a storage story in v1.\n */\n abstract upload(file: File): Promise<string>;\n\n /**\n * Maps a provider's error body onto the normalized codes, so an app can\n * branch on `rate_limited` without knowing whose rate limit it was.\n *\n * Shared rather than abstract-in-practice: Azure answers the same error\n * envelope as OpenAI, and the one place it differs — the content filter's\n * code, buried in `innererror` — is handled by reading both.\n */\n normalizeError(error: unknown): AgentError {\n return normalizeProviderError(error);\n }\n}\n\n/**\n * Autocomplete, not a gate. Every id here was confirmed present in\n * `GET https://api.openai.com/v1/models`; any other string is still accepted,\n * because a model released next Tuesday must not need a gemi release to use —\n * see `capabilitiesForModel` for what an unrecognized id is assumed to do.\n *\n * Ordered newest first, and deliberately short. `/v1/models` answers with\n * ninety-odd chat ids once the dated snapshots and the `-codex`, `-pro`,\n * `-chat-latest`, `-search-api` and `-nano` variants are counted; a list that\n * tried to be complete would be stale within the month and would bury the\n * handful of names anyone actually types. Snapshot-pinned ids\n * (`gpt-5.4-2026-03-05`) are left out for the same reason and work identically.\n *\n * The Azure provider returns this same list, which is a small lie it has always\n * told: a resource serves the deployments someone created, not the catalogue.\n * `AzureConfig.deployment` is the escape hatch, and an unrecognized deployment\n * name lands on the same capable default as an unrecognized model.\n */\nconst OPENAI_MODELS = [\n \"gpt-5.5\",\n \"gpt-5.4\",\n \"gpt-5.4-mini\",\n \"gpt-5.4-nano\",\n \"gpt-5.2\",\n \"gpt-5.1\",\n \"gpt-5\",\n \"gpt-5-mini\",\n \"gpt-5-nano\",\n \"gpt-4.1\",\n \"gpt-4.1-mini\",\n \"gpt-4.1-nano\",\n \"gpt-4o\",\n \"gpt-4o-mini\",\n \"o4-mini\",\n \"o3\",\n \"o3-mini\",\n] as const;\n\nexport class OpenAIProvider extends AgentProvider {\n readonly model: string;\n readonly capabilities: ProviderCapabilities;\n protected readonly config: ProviderConfig;\n\n constructor(model: string, config: ProviderConfig = {}) {\n super();\n this.model = model;\n this.capabilities = capabilitiesForModel(model);\n this.config = config;\n }\n\n /** Config defaults come from gemi's config (`ai.openai`), so an app that has\n * set `OPENAI_API_KEY` writes only the model name. */\n static model(model: string, config?: ProviderConfig): OpenAIProvider {\n return new OpenAIProvider(model, config);\n }\n\n static models(): readonly string[] {\n return OPENAI_MODELS;\n }\n\n stream(params: ProviderStreamParams): ProviderStream {\n const body = buildResponsesRequest(params, {\n model: this.model,\n capabilities: this.capabilities,\n });\n return streamResponses(this.endpoint(), body, {\n signal: params.signal,\n // The request carries the schema whenever the agent declared one, so the\n // parser has to read the answer as one too — a model that ignored the\n // parameter answers 400, not prose.\n structuredOutput: Boolean(params.output),\n });\n }\n\n upload(file: File): Promise<string> {\n return uploadFile(this.endpoint(), file);\n }\n\n protected baseURL(): string {\n return (this.config.baseURL ?? env(\"OPENAI_BASE_URL\") ?? \"https://api.openai.com/v1\").replace(\n /\\/+$/,\n \"\",\n );\n }\n\n protected endpoint(): ResponsesEndpoint {\n const base = this.baseURL();\n const config = this.config;\n return {\n responsesUrl: `${base}/responses`,\n filesUrl: `${base}/files`,\n headers: async () => {\n const apiKey = config.apiKey ?? env(\"OPENAI_API_KEY\");\n return {\n ...(apiKey ? { authorization: `Bearer ${apiKey}` } : {}),\n ...config.headers,\n };\n },\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n };\n }\n}\n\nexport type AzureConfig = ProviderConfig & {\n /**\n * The resource host, with or without a trailing `/openai`. Both spellings\n * work — `https://<resource>.cognitiveservices.azure.com` and\n * `https://<resource>.openai.azure.com` — and neither is rewritten, because\n * only one of them exists for a resource that was not created as\n * kind=OpenAI. See `azureBase` for what is done to it.\n */\n endpoint?: string;\n /**\n * Just the resource name, when there is no endpoint to hand. `<name>` is\n * expanded to `https://<name>.cognitiveservices.azure.com/openai`.\n */\n resourceName?: string;\n apiVersion?: string;\n /**\n * The deployment to call, when it is not named after the model. Azure lets\n * whoever ran the template call it anything, and plenty of them are called\n * `prod` — this is the override the class comment promises.\n */\n deployment?: string;\n /**\n * For Entra ID instead of a key. A function, not a token, because these\n * expire mid-conversation.\n */\n getToken?: () => Promise<string>;\n};\n\n/**\n * `preview` selects Azure's `/openai/v1` surface, which is the OpenAI-shaped\n * one — same request body, same SSE frames, same `model` field naming the\n * deployment — and it is the only surface the Responses API has that gemi's\n * request builder can talk to unchanged. It takes no dated version: sending\n * `api-version=2025-04-01-preview` to `/openai/v1/responses` answers\n * `400 {\"code\":\"BadRequest\",\"message\":\"API version not supported\"}`.\n *\n * A dated version is still honoured, and routes to the older\n * `/openai/responses` path instead — see `azurePath`. So an app that pinned\n * one keeps working, which is the promise the old comment here made and could\n * not keep once the paths diverged.\n */\nconst AZURE_API_VERSION = \"preview\";\n\n/**\n * Where an Azure Responses call goes, worked out live rather than from docs.\n *\n * THE PROBLEM THIS SOLVES. `AZURE_OPENAI_ENDPOINT` is conventionally written\n * with `/openai` already on the end, and the old code appended `/openai` again\n * and then a deployment path, producing\n * `…/openai/openai/deployments/<dep>/responses` — a 404 on every request, for\n * every app that configured the provider the documented way. Two separate\n * mistakes were stacked there, and only measuring told them apart.\n *\n * WHAT WAS MEASURED, against a real resource, POSTing a Responses body:\n *\n * 404 {endpoint}/openai/deployments/gpt-5.4/responses?api-version=2025-04-01-preview\n * 404 {host}/openai/deployments/gpt-5.4/responses?api-version=2025-04-01-preview\n * 404 {host}/openai/deployments/gpt-5.4/responses?api-version=preview\n * 400 {host}/openai/v1/responses?api-version=2025-04-01-preview (\"API version not supported\")\n * 200 {host}/openai/v1/responses?api-version=preview\n * 200 {host}/openai/v1/responses (no api-version at all)\n * 200 {host}/openai/responses?api-version=2025-04-01-preview\n *\n * for {host} in BOTH `https://<resource>.cognitiveservices.azure.com` and\n * `https://<resource>.openai.azure.com` — both spellings answered identically,\n * so the host was never the variable. The deployment-in-the-URL path is the\n * Chat Completions shape and the Responses API does not serve it at all; the\n * deployment goes in the body's `model`, which is what `buildResponsesRequest`\n * already puts there.\n *\n * `/openai/v1/files?api-version=preview` and\n * `/openai/files?api-version=2025-04-01-preview` were both checked too (200,\n * empty list), so uploads follow the same fork.\n */\nfunction azureBase(raw: string): string {\n const trimmed = raw.trim().replace(/\\/+$/, \"\");\n if (!trimmed) return \"\";\n // A configured endpoint may or may not already carry `/openai`, and may even\n // carry `/openai/v1` if someone copied a full URL. Normalize down to the\n // resource base and put exactly one `/openai` back, rather than appending\n // blind — appending blind is the bug.\n const base = trimmed.replace(/\\/openai(?:\\/v1)?$/i, \"\");\n return `${base}/openai`;\n}\n\n/** Dated versions belong to the older path; `preview` (and anything that is not\n * a date) belongs to `/v1`. Both were verified above. */\nfunction azurePath(apiVersion: string): string {\n return /^\\d{4}-\\d{2}-\\d{2}/.test(apiVersion) ? \"\" : \"/v1\";\n}\n\n/**\n * Its own class rather than a flag on `OpenAIProvider`: Azure names the\n * deployment rather than the model, pins an api-version, authenticates with an\n * `api-key` header or an Entra token, and puts the resource in the host. One\n * class carrying both shapes means every field is conditionally meaningful.\n *\n * (It used to put the deployment in the URL as well. It does not: the Responses\n * API serves no such path — see `azureBase` for the measurements.)\n *\n * The API stays symmetrical — `.model()`, not `.deployment()`. Apps name a\n * model; mapping that onto a deployment is this class's problem, and an app\n * that named its deployment differently overrides it in config.\n */\nexport class AzureOpenAIProvider extends AgentProvider {\n readonly model: string;\n readonly capabilities: ProviderCapabilities;\n protected readonly config: AzureConfig;\n\n constructor(model: string, config: AzureConfig = {}) {\n super();\n this.model = model;\n // Read off the model, not the deployment: a deployment called `prod` says\n // nothing, and an unrecognized name lands on the all-capabilities default\n // anyway. See `capabilitiesForModel`.\n this.capabilities = capabilitiesForModel(model);\n this.config = config;\n }\n\n /** Defaults from gemi's config (`ai.azure`). */\n static model(model: string, config?: AzureConfig): AzureOpenAIProvider {\n return new AzureOpenAIProvider(model, config);\n }\n\n static models(): readonly string[] {\n return OPENAI_MODELS;\n }\n\n stream(params: ProviderStreamParams): ProviderStream {\n const body = buildResponsesRequest(params, {\n model: this.deployment(),\n capabilities: this.capabilities,\n });\n return streamResponses(this.endpoint(), body, {\n signal: params.signal,\n // The request carries the schema whenever the agent declared one, so the\n // parser has to read the answer as one too — a model that ignored the\n // parameter answers 400, not prose.\n structuredOutput: Boolean(params.output),\n });\n }\n\n upload(file: File): Promise<string> {\n return uploadFile(this.endpoint(), file);\n }\n\n protected deployment(): string {\n return this.config.deployment ?? this.model;\n }\n\n /**\n * The resource base, `<host>/openai`, from whichever of the three ways it was\n * configured. A bare resource name expands to the `cognitiveservices` host\n * rather than the `openai.azure.com` one: both answer for a resource created\n * as kind=OpenAI, only `cognitiveservices` answers for an AI Foundry or\n * multi-service resource, so it is the spelling that is right more often. An\n * app on the other one sets `endpoint` and nothing rewrites it.\n */\n protected base(): string {\n const config = this.config;\n const configured = config.baseURL ?? config.endpoint ?? env(\"AZURE_OPENAI_ENDPOINT\");\n if (configured) return azureBase(configured);\n const resource =\n config.resourceName ?? env(\"AZURE_OPENAI_RESOURCE_NAME\") ?? env(\"AZURE_RESOURCE_NAME\");\n return resource ? azureBase(`https://${resource.trim()}.cognitiveservices.azure.com`) : \"\";\n }\n\n protected endpoint(): ResponsesEndpoint {\n const config = this.config;\n const base = this.base();\n const apiVersion = config.apiVersion ?? env(\"AZURE_OPENAI_API_VERSION\") ?? AZURE_API_VERSION;\n const path = azurePath(apiVersion);\n const query = `?api-version=${encodeURIComponent(apiVersion)}`;\n return {\n // No deployment in the URL: the Responses API does not serve that path,\n // and `buildResponsesRequest` already sends the deployment as `model`.\n responsesUrl: `${base}${path}/responses${query}`,\n // Files are resource-scoped, not deployment-scoped: an upload is not\n // addressed to a model.\n filesUrl: `${base}${path}/files${query}`,\n headers: async () => {\n // Called per request, not per provider: an Entra token minted when the\n // app booted is expired by the time a long conversation reaches step\n // nine, and that failure looks like a random 401 in the middle of a\n // working feature.\n if (config.getToken) {\n return { authorization: `Bearer ${await config.getToken()}`, ...config.headers };\n }\n const apiKey = config.apiKey ?? env(\"AZURE_OPENAI_API_KEY\");\n return { ...(apiKey ? { \"api-key\": apiKey } : {}), ...config.headers };\n },\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n };\n }\n}\n",
16
+ "import type { AgentRun } from \"../Agent\";\nimport type { LiveRuns } from \"../AgentController\";\nimport type { AgentStreamEvent, AgentStreamFrame } from \"../types\";\n\n/** Long enough that a refresh, a tab restore or a flaky mobile connection still\n * lands on the tail; short enough that a finished run is not resident for the\n * rest of the day. */\nconst DEFAULT_TTL_MS = 60 * 1000;\n\n/**\n * How many frames are kept per run.\n *\n * The window has to be bounded or it is a memory leak with a long fuse: a\n * server that never restarts holding every token of every conversation it ever\n * streamed.\n *\n * It was 512 on the reasoning that a reattaching client only needs seconds of\n * catch-up. That is true of the *reattaching* client and false of the one that\n * never left: a frame is roughly a token, so 512 is a four-hundred-word answer,\n * and a reader that falls behind a longer one by more than that is cut off with\n * a 410 mid-stream. On a slow connection — the case reattachment exists for —\n * that is not exotic.\n *\n * 4096 covers essentially any single answer. It is affordable because of two\n * measured facts, and it would not have been before either:\n *\n * - `drain` no longer copies the window per wake, so a reader costs the same\n * whatever the window's size. Measured at 64 readers on a 2000-frame run:\n * 1106 ms of CPU at 4096 before, 425 ms after, and 468 ms at 512 — i.e. the\n * size stopped being a term in the cost.\n * - the entries are pointers to frames the run is holding anyway, so the\n * window costs 8 bytes each, not the frame. Eight times more of them is\n * ~28 KB per run, and a thousand concurrent runs is tens of megabytes.\n *\n * Both would change if the run's own buffer ever became bounded — then this\n * window owns the frames, and its size is their size.\n */\nconst DEFAULT_MAX_FRAMES = 4096;\n\n/**\n * A cursor older than anything still buffered.\n *\n * Deliberately an error rather than \"here is the tail I still have\". A client\n * that asked for frame 12 and silently got frame 300 onwards has a transcript\n * with a hole in it and no way to know — it will render a half-message, or an\n * `awaiting-input` for a tool call it never saw. Saying so lets the client do\n * the only correct thing, which is to reload the thread from the store.\n */\nexport class FrameCursorEvictedError extends Error {\n readonly code = \"frame_cursor_evicted\";\n\n constructor(\n readonly runId: string,\n readonly requested: number,\n readonly oldest: number,\n ) {\n super(\n `Frame ${requested} of run ${runId} has been evicted; the oldest frame ` +\n `still buffered is ${oldest}. Reload the thread instead of resuming.`,\n );\n }\n}\n\n/**\n * No run under that id in *this* process.\n *\n * Which is the honest answer, and the one worth being loud about: the run may\n * well be alive on the box next door. See the note on `MemoryLiveRuns` — behind\n * a round-robin load balancer this is what a refresh hits roughly (n-1)/n of\n * the time, and an explicit miss is the difference between a bug someone finds\n * in an hour and one that presents as \"reattach sometimes does nothing\".\n */\nexport class LiveRunNotFoundError extends Error {\n readonly code = \"live_run_not_found\";\n\n constructor(readonly runId: string) {\n super(`No live run ${runId} in this process.`);\n }\n}\n\nexport type RegisterParams = {\n threadId?: string;\n /**\n * The client's own name for this run, minted before the run had one.\n *\n * `runId` does not reach the client until `run-start`, and a stateless first\n * turn has no `threadId` either, so for the length of a network round trip\n * plus the provider's time to first token there is nothing for `/stop` to\n * name — which is exactly the window a user cancels in. `useChat` sends a\n * `clientRunId` with every turn it starts; recording it here is what makes\n * that window stoppable.\n */\n clientRunId?: string;\n /**\n * Called once per frame, in order, off the buffering path.\n *\n * The controller's `on*` hooks hang off this. It is a callback rather than a\n * second `run.frames()` subscription because every extra subscriber is\n * another consumer of a generator whose multi-subscriber behaviour we do not\n * own, and one pump is one thing to reason about.\n */\n onEvent?: (event: AgentStreamEvent) => void | Promise<void>;\n /** Reported failures: a hook that threw, or a run whose frame iterator did.\n * Injectable so tests can assert on it instead of reading stderr. */\n onInternalError?: (error: unknown) => void;\n};\n\ntype Entry = {\n run: AgentRun;\n threadId?: string;\n clientRunId?: string;\n /** A contiguous window of the run's frames, oldest first. */\n frames: AgentStreamFrame[];\n lastSeq: number;\n /**\n * The lowest `seq` still obtainable, or 0 while nothing has been dropped.\n *\n * Not derivable from `frames[0].seq`, which is what this used to compare\n * against. `seq` starts at 1, so a run that has evicted nothing still has an\n * oldest frame of 1, and a cursor of 0 — the \"I have no transcript yet\"\n * cursor that `replay` itself picks for a run registered but not yet pumped —\n * read as older than the buffer. A ten-frame run in a five-hundred-frame\n * window answered a refresh with 410, which is both false and unactionable:\n * refreshing right after sending is the case `/attach` exists to serve.\n */\n lostBefore: number;\n ended: boolean;\n evictAt: ReturnType<typeof setTimeout> | null;\n wake: Set<() => void>;\n /**\n * Bumped on every push and on the end.\n *\n * A reader cannot just park on \"wake me when something happens\": it suspends\n * at every `yield` while its consumer reads, and anything that arrives during\n * that suspension notifies an empty waiter set — so the reader parks *after*\n * the event it was waiting for and never hears another. The version it read\n * before scanning is what closes that window: if it moved, there is more to\n * scan and the wait is skipped.\n */\n version: number;\n};\n\n/**\n * The runs currently in flight in this process, and their recent frames.\n *\n * PER-PROCESS IS NOT AN IMPLEMENTATION SHORTCUT THAT A BETTER STORE FIXES. A\n * running generator lives in one process, and a second server cannot attach to\n * it — no amount of Redis moves an in-flight async iterator across a socket.\n * Reattachment therefore needs the request to land where the run is: one\n * server, sticky routing, or a proxy that forwards by `runId`. Worth saying out\n * loud, because the failure mode behind a round-robin load balancer is a\n * refresh that usually works.\n *\n * `find` and `replay` are built so that failure is an explicit miss — a 404\n * naming the run, a 410 naming the cursor — and never an SSE stream that opens,\n * says nothing and closes. An empty stream is indistinguishable from a run that\n * finished quietly, which is exactly the confusion this is supposed to avoid.\n */\nexport class MemoryLiveRuns implements LiveRuns {\n ttlMs: number;\n readonly maxFrames: number;\n\n private runs = new Map<string, Entry>();\n /** Thread to the most recently registered run for it. */\n private byThread = new Map<string, string>();\n /** The client's pre-`run-start` name for a run, to the run. */\n private byClientRun = new Map<string, string>();\n\n constructor(params: { ttlMs?: number; maxFrames?: number } = {}) {\n this.ttlMs = params.ttlMs ?? DEFAULT_TTL_MS;\n this.maxFrames = params.maxFrames ?? DEFAULT_MAX_FRAMES;\n }\n\n /**\n * Takes ownership of a run: starts buffering its frames and holds it until\n * `ttlMs` past the end.\n */\n register(run: AgentRun, params: RegisterParams = {}): void {\n const entry: Entry = {\n run: run as AgentRun,\n threadId: params.threadId,\n clientRunId: params.clientRunId,\n frames: [],\n lastSeq: -1,\n lostBefore: 0,\n ended: false,\n evictAt: null,\n wake: new Set(),\n version: 0,\n };\n this.runs.set(run.runId, entry);\n if (params.threadId) {\n this.byThread.set(params.threadId, run.runId);\n }\n if (params.clientRunId) {\n this.byClientRun.set(params.clientRunId, run.runId);\n }\n void this.pump(entry, params);\n }\n\n /**\n * The run a client named before the server had named it.\n *\n * Deliberately not folded into `find`, whose parameter is part of the\n * read-side `LiveRuns` interface an app may already implement — widening that\n * parameter would break every such implementation, and this lookup is only\n * ever asked by `/stop`.\n */\n findByClientRunId(clientRunId: string): string | null {\n const runId = this.byClientRun.get(clientRunId);\n return runId && this.runs.has(runId) ? runId : null;\n }\n\n /** What the client asks after a refresh: is anything still going here? */\n async find(params: { threadId: string }): Promise<{ runId: string; seq: number } | null> {\n const runId = this.byThread.get(params.threadId);\n if (!runId) {\n return null;\n }\n const entry = this.runs.get(runId);\n if (!entry) {\n return null;\n }\n // `seq` is the last frame emitted, not the next one: it is the same number\n // the transport puts in `Last-Event-ID`, so a client can compare the two\n // without knowing which end of the range each one means.\n return { runId, seq: entry.lastSeq };\n }\n\n get(runId: string): AgentRun | null {\n return this.runs.get(runId)?.run ?? null;\n }\n\n /**\n * The buffered frames from `from` onwards, followed by live ones until the\n * run ends.\n *\n * Throws before returning anything, so an evicted cursor and an unknown run\n * are still HTTP statuses rather than events on a stream that already\n * committed to a 200.\n *\n * `from` omitted means \"start wherever you still can\", not \"start at 0\".\n * These are genuinely different requests: a client that names a cursor is\n * telling us where its transcript ends, and handing it a later frame leaves\n * an invisible hole — that is the 410. A client with no cursor at all — the\n * browser reattaching on mount, which is the case `/attach` exists for — has\n * no transcript to put a hole in, and refusing it the tail because the run is\n * older than the buffer would 410 every run past `maxFrames`, i.e. every run\n * long enough to be worth reattaching to.\n */\n replay(runId: string, from?: number): AsyncIterable<AgentStreamFrame> {\n const entry = this.runs.get(runId);\n if (!entry) {\n throw new LiveRunNotFoundError(runId);\n }\n if (from !== undefined && from < entry.lostBefore) {\n throw new FrameCursorEvictedError(runId, from, entry.lostBefore);\n }\n const oldest = entry.frames[0]?.seq;\n // With nothing buffered — a run registered but not yet pumped — `lastSeq`\n // is -1 and this is 0, which is the same answer by another route.\n return this.drain(entry, runId, from ?? oldest ?? entry.lastSeq + 1);\n }\n\n /** Test seam: drops everything and cancels the pending eviction timers. */\n clear(): void {\n for (const entry of this.runs.values()) {\n if (entry.evictAt) {\n clearTimeout(entry.evictAt);\n }\n // Marked ended before waking: a reader parked on `wait` would otherwise\n // come back, find the entry unfinished, and park again forever.\n entry.ended = true;\n this.notify(entry);\n }\n this.runs.clear();\n this.byThread.clear();\n this.byClientRun.clear();\n }\n\n get size(): number {\n return this.runs.size;\n }\n\n private async pump(entry: Entry, params: RegisterParams): Promise<void> {\n // Hooks run on their own chain: they stay in order relative to each other,\n // and a slow one never stalls the buffer a reattaching client reads from.\n let hooks = Promise.resolve();\n try {\n for await (const frame of entry.run.frames()) {\n entry.frames.push(frame);\n entry.lastSeq = frame.seq;\n if (entry.frames.length > this.maxFrames) {\n const dropped = entry.frames.shift();\n if (dropped) entry.lostBefore = dropped.seq + 1;\n }\n this.notify(entry);\n const onEvent = params.onEvent;\n if (onEvent) {\n hooks = hooks\n .then(() => onEvent(frame.event))\n .catch((err) => {\n params.onInternalError?.(err);\n });\n }\n }\n } catch (err) {\n // The run's own iterator failed. There is nothing left to replay, so the\n // entry ends here; whoever is attached sees the stream close.\n params.onInternalError?.(err);\n } finally {\n entry.ended = true;\n this.notify(entry);\n // Eviction is scheduled off the ttl clock, BEFORE the hook chain is\n // awaited. `hooks` is app code — `onAwaitingInput` is documented as the\n // place to notify an approver, i.e. network I/O — and a `fetch` with no\n // timeout never rejects, it just never settles. Awaiting it first made\n // retention conditional on app code: one hanging hook pinned its entry,\n // its 512 frames, the run and everything the run closes over in the map\n // for the life of the process, and `find` kept answering with a run that\n // ended hours ago. Retention is this class's job and belongs on its own\n // clock. A hook still pending when the timer fires simply outlives the\n // entry, which is fine — it holds no reference the map needed.\n this.scheduleEviction(entry);\n await hooks;\n }\n }\n\n private async *drain(\n entry: Entry,\n runId: string,\n from: number,\n ): AsyncGenerator<AgentStreamFrame, void, void> {\n let cursor = from;\n while (true) {\n const seen = entry.version;\n // The window is contiguous and ordered, so a reader's position in it is\n // arithmetic, not a search. This used to copy the whole window on every\n // wake and scan it for frames past the cursor, which is O(window) per\n // frame per reader — invisible at a 512-frame cap and the reason the cap\n // could not be raised. Indexing makes the window's size stop mattering.\n for (;;) {\n if (cursor < entry.lostBefore) {\n // The window rolled past this reader mid-stream. Same reasoning as\n // the pre-flight check: a gap the client cannot see is worse than a\n // stream that stops and says why. Re-checked inside the loop rather\n // than once per wake, because a yield suspends this reader for as\n // long as its consumer takes and the pump keeps running.\n throw new FrameCursorEvictedError(runId, cursor, entry.lostBefore);\n }\n const frames = entry.frames;\n const oldest = frames[0]?.seq;\n if (oldest === undefined) {\n break;\n }\n // Clamped rather than treated as a gap: a cursor below the first seq\n // that ever existed is \"from the beginning\", not a lost position.\n const index = Math.max(0, cursor - oldest);\n if (index >= frames.length) {\n break;\n }\n const frame = frames[index]!;\n yield frame;\n cursor = frame.seq + 1;\n }\n if (entry.ended && cursor > entry.lastSeq) {\n return;\n }\n await this.wait(entry, seen);\n }\n }\n\n private wait(entry: Entry, seen: number): Promise<void> {\n if (entry.version !== seen) {\n return Promise.resolve();\n }\n return new Promise<void>((resolve) => entry.wake.add(resolve));\n }\n\n private notify(entry: Entry): void {\n entry.version++;\n const waiters = Array.from(entry.wake);\n entry.wake.clear();\n for (const resolve of waiters) {\n resolve();\n }\n }\n\n private scheduleEviction(entry: Entry): void {\n if (entry.evictAt) {\n return;\n }\n const timer = setTimeout(() => {\n const runId = entry.run.runId;\n this.runs.delete(runId);\n if (entry.threadId && this.byThread.get(entry.threadId) === runId) {\n this.byThread.delete(entry.threadId);\n }\n if (entry.clientRunId && this.byClientRun.get(entry.clientRunId) === runId) {\n this.byClientRun.delete(entry.clientRunId);\n }\n // Anyone still draining is holding an ended entry; wake them so they see\n // `ended` and finish rather than hanging on a promise nothing resolves.\n this.notify(entry);\n }, this.ttlMs);\n // A finished run must not be the reason a process stays up.\n (timer as { unref?: () => void }).unref?.();\n entry.evictAt = timer;\n }\n}\n\n/**\n * The process-wide default, shared by every `AgentController` that does not\n * bring its own. One map per process is the whole point — see the class note.\n */\nexport const liveRuns = new MemoryLiveRuns();\n",
17
+ "import type { AgentStore } from \"../AgentController\";\nimport type { AgentMessage } from \"../types\";\n\n/** A day. Long enough that a conversation survives a lunch break, short enough\n * that a chat nobody came back to is not still resident a week later. */\nconst DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;\n\n/** How often the map is walked looking for expired threads. */\nconst SWEEP_INTERVAL_MS = 60 * 1000;\n\ntype Thread = {\n messages: AgentMessage[];\n /** Bumped by every read and every write: a conversation someone is still\n * having must not expire out from under them mid-turn. */\n touchedAt: number;\n};\n\n/**\n * The default store: conversations last as long as the process.\n *\n * It exists so that `threadId` works out of the box, not so that anything is\n * durable — a restart loses every thread, and a second server never had them.\n * That is the honest default for a framework store, and it is why stateless is\n * still the mode an app gets without asking: the client carrying its own\n * history survives a deploy, and this does not.\n *\n * Expiry is swept lazily rather than on a timer. A `setTimeout` per thread is a\n * timer per conversation and a reference the GC cannot collect, and an interval\n * running forever keeps a process alive that has nothing else to do — so the\n * sweep happens on access, at most once a minute, and an untouched process\n * simply stops sweeping.\n *\n * A thread the store does not have is `null` from `loadThread` and an error\n * from `appendMessages`, never an empty conversation. It used to be the other\n * way, and the three ways a thread goes missing — it expired, the id was\n * mistyped, it lived on an instance that was scaled in — all read as a fresh\n * chat: the history was gone with no signal, and the next turn was persisted\n * under the dead id as though it were the first. `clientOwnedIds` is the one\n * setup where an unknown id is not a lost thread, because the client minted it.\n */\nexport class MemoryAgentStore implements AgentStore {\n readonly ttlMs: number;\n /** The ids come from the client, not from `createThread`, so an id this\n * store has never seen is a conversation starting rather than one lost. */\n readonly clientOwnedIds: boolean;\n\n private threads = new Map<string, Thread>();\n private lastSweep = 0;\n\n constructor(params: { ttlMs?: number; clientOwnedIds?: boolean } = {}) {\n this.ttlMs = params.ttlMs ?? DEFAULT_TTL_MS;\n this.clientOwnedIds = params.clientOwnedIds ?? false;\n }\n\n async createThread(params: { userId?: string | number }): Promise<{ threadId: string }> {\n // The user id is not part of the id and not stored: this store cannot\n // authorize anything, and an id that looked like a key would invite an app\n // to treat it as one. Ownership belongs to the app's own table.\n void params;\n const threadId = crypto.randomUUID();\n this.threads.set(threadId, { messages: [], touchedAt: Date.now() });\n this.sweep();\n return { threadId };\n }\n\n async loadThread(threadId: string): Promise<AgentMessage[] | null> {\n this.sweep();\n const thread = this.threads.get(threadId);\n if (!thread) {\n // With client-owned ids the first turn arrives before anything has been\n // written under it, so unknown is empty. Otherwise unknown is a thread\n // that expired or never existed, and the controller has to be able to\n // tell: `[]` here is the silent fresh conversation this store used to\n // hand out in place of the user's history.\n return this.clientOwnedIds ? [] : null;\n }\n thread.touchedAt = Date.now();\n // Copied, so a caller that sorts or splices the result does not edit the\n // stored history in place.\n return thread.messages.slice();\n }\n\n async appendMessages(threadId: string, messages: AgentMessage[]): Promise<void> {\n this.sweep();\n let thread = this.threads.get(threadId);\n if (!thread) {\n if (!this.clientOwnedIds) {\n // Creating the thread here would persist a turn under an id the client\n // believes holds a longer conversation, and hide from the app that the\n // conversation is gone. The controller checks before the run and never\n // reaches this; a store-level caller that does gets told.\n throw new Error(`Thread ${threadId} does not exist here, or has expired.`);\n }\n // The client owns the id, so an append to one the store has never seen is\n // the first turn, and refusing it would lose a turn that already happened.\n thread = { messages: [], touchedAt: Date.now() };\n this.threads.set(threadId, thread);\n }\n // Upsert, not push. A turn that resolves a pending call hands back the\n // assistant message that made the call under the id it already had, now\n // with the result attached; pushing it would leave the thread holding both\n // versions, and the model would read the same call twice on every turn\n // that follows. Replacing in place keeps the message where the\n // conversation put it.\n for (const message of messages) {\n const at = thread.messages.findIndex((held) => held.id === message.id);\n if (at === -1) {\n thread.messages.push(message);\n } else {\n thread.messages[at] = message;\n }\n }\n thread.touchedAt = Date.now();\n }\n\n /** Test seam, and a way for an app to drop a conversation on request. */\n delete(threadId: string): void {\n this.threads.delete(threadId);\n }\n\n get size(): number {\n return this.threads.size;\n }\n\n sweep(now = Date.now()): void {\n if (now - this.lastSweep < SWEEP_INTERVAL_MS) {\n return;\n }\n this.lastSweep = now;\n for (const [threadId, thread] of this.threads) {\n if (now - thread.touchedAt > this.ttlMs) {\n this.threads.delete(threadId);\n }\n }\n }\n}\n\n/**\n * The process-wide default every `AgentController` uses unless it is given\n * another.\n *\n * It has to be a shared instance, not a field initializer. A gemi controller is\n * constructed per request — `RouteHandler.run()` does `new Controller()` every\n * time — so `store = new MemoryAgentStore()` written in a controller field is a\n * brand new, empty store on every turn, and a threaded conversation would read\n * back nothing while looking like it was configured correctly. Anything\n * process-lived that a controller holds has to be created outside it.\n */\nexport const defaultAgentStore = new MemoryAgentStore();\n",
18
+ "import { Controller } from \"../http/Controller\";\nimport { HttpRequest } from \"../http/HttpRequest\";\nimport type { MiddlewareInput } from \"../http/middlewareList\";\nimport type { AgentRun, AgentRunResult, AnyAgent, ToolShapesOf } from \"./Agent\";\nimport {\n FrameCursorEvictedError,\n liveRuns as defaultLiveRuns,\n LiveRunNotFoundError,\n MemoryLiveRuns,\n} from \"./store/LiveRuns\";\nimport { defaultAgentStore, MemoryAgentStore } from \"./store/MemoryAgentStore\";\nimport { sseResponse } from \"./store/sse\";\nimport type {\n AgentError,\n AgentMessage,\n AgentStreamEvent,\n ClientTurn,\n PendingToolCall,\n ToolShapes,\n} from \"./types\";\n\n// --- storage -------------------------------------------------------------\n\n/**\n * Where conversations live.\n *\n * Stateless is the default and nothing here is required to hold a conversation:\n * the client can carry its own history, and a pending approval travels in it\n * safely because the server signed it. What a store buys is a conversation that\n * survives the browser — and, with `/attach`, one whose interrupted turn is\n * still there after a refresh.\n */\nexport interface AgentStore {\n /**\n * Where a `threadId` comes from. `ApiRouter.agent()` mounts no route for\n * this: the app writes one, calls it here, and hands the id to `useChat` —\n * the mount is the app's because it is where ownership gets recorded, and a\n * store that holds no user cannot do that for it. An id that did not come out\n * of here is `null` from `loadThread` and a 404 from the controller, unless\n * the store's ids are the client's by design (`MemoryAgentStore`'s\n * `clientOwnedIds`).\n */\n createThread(params: { userId?: string | number }): Promise<{ threadId: string }>;\n /**\n * The history, or `null` for a thread the store does not have.\n *\n * `null` and `[]` are different answers and the controller acts on the\n * difference: an empty array is a conversation with nothing in it yet, and a\n * turn on it runs; `null` is a 404 before anything runs. A store that answers\n * `[]` for an id it has never seen turns an expired or mistyped thread into a\n * fresh conversation with no signal, and persists the next turn under the\n * dead id. Only a store whose ids are minted by the client should do that,\n * and then on purpose — see `MemoryAgentStore`'s `clientOwnedIds`.\n */\n loadThread(threadId: string): Promise<AgentMessage[] | null>;\n /**\n * Upsert by message id: replace a message the thread already holds, append\n * one it does not, and keep the order the thread had. Called with a thread\n * `loadThread` just found; must not create one.\n *\n * The name says append because that is what almost every call is, but a\n * turn that resolves a pending call reports the earlier assistant message\n * again — same id, now with the result attached — and a store that only\n * appends ends up with both versions. A table keyed by message id has the\n * lookup already but still needs an insert-or-update rather than a plain\n * insert, which would fail on the key; a store that is a list has to look\n * before it pushes.\n */\n appendMessages(threadId: string, messages: AgentMessage[]): Promise<void>;\n}\n\n/** The default: conversations last as long as the process. */\nexport { defaultAgentStore, MemoryAgentStore };\n\n/**\n * The runs currently in flight, and their frames.\n *\n * A run outlives the request that started it, so something has to hold it while\n * no one is listening, and hold what it emitted meanwhile so a returning client\n * can catch up rather than start over. That is all this is: a per-process map\n * plus a bounded buffer.\n *\n * Per-process is not an implementation shortcut that a better store fixes — a\n * running generator lives in one process, and a second server cannot attach to\n * it. Reattachment therefore needs the request to land where the run is: one\n * server, sticky routing, or a proxy that forwards by `runId`. Worth saying out\n * loud, because the failure mode behind a round-robin load balancer is a\n * refresh that usually works.\n *\n * This is the read side, which is all `attach` and `stop` need. Registering a\n * run and replaying its buffer are on `MemoryLiveRuns`, the only implementation\n * there can be — see the note there for why a second one would not help.\n */\nexport interface LiveRuns {\n /** What the client asks after a refresh: is anything still going here? */\n find(params: { threadId: string }): Promise<{ runId: string; seq: number } | null>;\n get(runId: string): AgentRun | null;\n /** Kept for a short while after `run-end`, so a refresh a second late still\n * sees the tail instead of an empty screen. */\n ttlMs: number;\n}\n\nexport {\n FrameCursorEvictedError,\n LiveRunNotFoundError,\n MemoryLiveRuns,\n defaultLiveRuns as liveRuns,\n};\n\n// --- controller ----------------------------------------------------------\n\nexport type AgentHookContext = {\n req: HttpRequest<any, any>;\n runId: string;\n threadId?: string;\n};\n\n/**\n * `Controller.kind` is typed as the literal `\"controller\"`, so a subclass that\n * declares a `kind` of its own fails the static-side check (TS2417). Widening\n * it belongs in `http/Controller.ts`, which this slice does not own; erasing\n * the static side of the base here is the smaller change and costs nothing —\n * `Controller.kind` has no reader, in this package or out of it.\n */\nconst ControllerBase = Controller as new () => Controller;\n\n/**\n * The thread a `stream` is setting up on, to the setup ahead of it. Module\n * level because the controller is constructed per request, so nothing on it\n * can be seen by the next request; keyed by thread rather than held on\n * `liveRuns` because it guards the controller's protocol, not the frames. An\n * entry is removed once the last setup queued on it releases.\n */\nconst threadLocks = new Map<string, Promise<void>>();\n\n/**\n * Each run to the promise that its transcript has been stored. Weak, so a run\n * the map has evicted is not kept alive here for a promise nobody will ask for.\n */\nconst persisted = new WeakMap<AgentRun, Promise<void>>();\n\n/**\n * Turns read but not yet registered, by the client's name for them.\n *\n * A run can be stopped from `register` on, and named from `run-start` on. What\n * `/stop` could not reach was a turn still waiting its place on the thread —\n * which is where a user who sent twice and thought better of it presses stop,\n * and the wait is now as long as the old run's unwind. Falling through to\n * `threadId` there found the old run, already stopping, said `stopped: true`,\n * and the queued turn started anyway: unwatched, billing, and with no handle\n * left on the client that had let go of it. The entry is marked rather than\n * removed, because the turn itself is what answers once its wait is over.\n */\nconst pendingTurns = new Map<string, { cancelled: boolean }>();\n\nexport abstract class AgentController<A extends AnyAgent = AnyAgent> extends ControllerBase {\n static kind = \"agent-controller\" as const;\n\n /** The agent this controller serves. A property rather than a constructor\n * argument so `Router.agent(ChatController)` can take the class, matching how\n * every other controller is mounted. */\n abstract agent: A;\n\n /**\n * Defaults to the process-wide `MemoryAgentStore`.\n *\n * Whatever you put here, make it something that outlives the request: this\n * controller is constructed fresh for every call, so `store = new\n * MemoryAgentStore()` written here is an empty store on every turn and a\n * threaded conversation silently reads back nothing. Assign a module-level\n * instance, or a store whose state is somewhere else entirely.\n */\n store: AgentStore = defaultAgentStore;\n\n /**\n * Defaults to the process-wide map. Overridable so a test — or an app running\n * two agents that must not see each other's runs — can hold its own; not so\n * that it can be moved off the process, which is not a thing that can be\n * done. See `MemoryLiveRuns`.\n */\n liveRuns: MemoryLiveRuns = defaultLiveRuns;\n\n /** Appended to the agent's static instructions for this request — the user's\n * name, tenant, today's date. */\n instructions(req: HttpRequest<any, any>): string | Promise<string> | void {\n void req;\n }\n\n /**\n * `POST /<path>` — one route for every client turn. A first message, an\n * approval, an answer to a question and a client tool's result are all just\n * the next turn, so none of them gets an endpoint of its own.\n */\n async stream(req: HttpRequest<any, any> = new HttpRequest()): Promise<Response> {\n const parsed = await readJsonBody(req);\n if (parsed.error) {\n // Before anything is registered or charged for. A run started off a body\n // we could not read would answer nothing, at the user's expense.\n return invalidRequest(parsed);\n }\n const body = parsed.body;\n const threadId = typeof body.threadId === \"string\" ? body.threadId : undefined;\n const turn = toClientTurn(body);\n const clientRunId = typeof body.clientRunId === \"string\" ? body.clientRunId : undefined;\n\n // From here until `register`, the only thing `/stop` can find this turn by.\n // See `pendingTurns`.\n const pending = clientRunId ? { cancelled: false } : null;\n if (pending) {\n pendingTurns.set(clientRunId, pending);\n }\n\n // The whole of the stateless/threaded difference, in one expression: with a\n // thread the server owns the history, without one the client carries it.\n // Nothing else below branches on it, which is why stateless keeps working\n // even for an app that never configures a store.\n //\n // The `threadId` is the client's, and nothing here checks that this caller\n // owns it — `AgentStore` cannot, since it holds no user. A `threadId` is\n // therefore a capability and has to be unguessable (`createThread` mints a\n // uuid) and, for anything that matters, checked: override `instructions()`\n // or a `store` that scopes by `req.user`. The framework's job is to make\n // sure the route is behind the router's middleware in the first place,\n // which `ApiRouter.agent()` now does.\n //\n // Everything from the load on happens inside `start`, which on a thread\n // runs under the thread's lock once the previous run's transcript is in the\n // store — the load has to come after that, or it reads a history the old\n // answer is missing from. `instructions()` follows the load in there rather\n // than running ahead of the lock, so that a dead thread is still a 404\n // before the app's own work is spent on it; the cost is that a turn queued\n // behind this one waits for `instructions()` as well.\n const start = async (): Promise<Response> => {\n let messages: AgentMessage[];\n if (threadId) {\n const history = await this.store.loadThread(threadId);\n if (!history) {\n // Before `instructions()` and before the run: nothing has been\n // charged for, and the client has to learn that its thread is gone —\n // expired, mistyped, or on an instance that no longer exists — rather\n // than see it answered as an empty conversation and have this turn\n // persisted under the dead id.\n //\n // That ordering is deliberate, and it costs something: the ownership\n // check the comment above points at `instructions()` for has not run\n // yet, so a caller holding a uuid learns whether it is live here\n // without the app's say. `/attach` already answers a question of that\n // shape to anyone with the id and never calls `instructions()`, and\n // the id is unguessable — which is why the load stays above\n // `instructions()`, whose own work (a database read, typically) would\n // otherwise be spent on a thread that is gone. Move it below and that\n // work is spent on every dead id instead.\n return jsonResponse(404, {\n code: \"thread_not_found\",\n message: `Thread ${threadId} does not exist here, or has expired.`,\n });\n }\n messages = history;\n } else {\n messages = Array.isArray(body.messages) ? (body.messages as AgentMessage[]) : [];\n }\n\n const instructions = (await this.instructions(req)) || undefined;\n\n if (pending?.cancelled) {\n // Stopped while it waited. Nothing has been asked of the model and\n // nothing registered, so there is no run to end and nothing charged\n // for. Checked after the last `await` above, so that a stop landing\n // during it is not missed: from here to `register` nothing yields.\n return jsonResponse(409, {\n code: \"stopped\",\n message: \"The turn was stopped before it started.\",\n });\n }\n\n const run = this.agent.stream({\n messages,\n turn,\n req,\n threadId,\n instructions,\n }) as AgentRun;\n\n const ctx: AgentHookContext = { req, runId: run.runId, threadId };\n\n // Registered before the response is built: the run is now owned by the\n // process rather than by this request, which is the property `/attach`\n // depends on and the reason a dropped connection no longer cancels\n // anything.\n this.liveRuns.register(run, {\n threadId,\n // The client's handle on a run it started, which is the only one that\n // exists before `run-start` reaches it. See `RegisterParams`.\n clientRunId,\n onEvent: (event) => this.dispatchEvent(event, ctx),\n onInternalError: (err) => this.reportHookFailure(err),\n });\n\n // Kept, not just fired: the next turn on this thread has to know when\n // this one's transcript is in the store. See `withThread`.\n persisted.set(run, this.persistRun(run, ctx));\n\n return run.toResponse();\n };\n\n try {\n return threadId ? await this.withThread(threadId, start) : await start();\n } finally {\n if (pending && pendingTurns.get(clientRunId) === pending) {\n pendingTurns.delete(clientRunId);\n }\n }\n }\n\n /**\n * A thread holds one run at a time; a new turn on it ends the old one first.\n *\n * Since a dropped connection no longer stops a run, a user who sends again\n * mid-answer used to leave the first run going. It could not see the new\n * turn, the new run's `loadThread` could not see its answer, and both\n * appended when they finished — in whichever order the model returned them,\n * so the thread read `user2, assistant2, user1, assistant1`. `byThread` then\n * named the second run while the first was still live and unstoppable by\n * `threadId`.\n *\n * Stopping the old run and waiting for its transcript to land is chosen over\n * refusing the new turn with a 409, because sending again *is* the stop: it\n * is what `useChat.send` means, and a client that has to poll `/stop` until\n * the run is really gone before it may post the turn it has already shown is\n * a worse client for no better thread. The cost is that the new turn waits\n * for the old run to unwind, which is as long as its slowest tool in flight —\n * and that wait is the thing that puts `assistant1` before `user2`.\n *\n * The wait is on `persistRun`, not on `run.result()`. `result()` settling is\n * the transcript being final, not stored: `appendMessages` runs after it, and\n * a `loadThread` in that gap reads a history the old answer is missing from,\n * which is the original bug by a shorter route. It is also *only* that:\n * `persistRun` settles once the transcript is stored and lets the app's\n * hooks run on without it, so a slow `onMessage` is not a slow thread and a\n * hung one is not a hung thread.\n *\n * The lock around it is what makes a *third* turn wait for the second rather\n * than for the first. Two turns arriving together both see the same live\n * run, both stop it, both wait for it, and both start — the same race, one\n * message later. Under the lock the later one finds the earlier one\n * registered and stops that instead. Per process, like `LiveRuns`, and for\n * the same reason: the run it guards lives here.\n */\n private async withThread<T>(threadId: string, fn: () => Promise<T>): Promise<T> {\n const previous = threadLocks.get(threadId) ?? Promise.resolve();\n let release!: () => void;\n const held = new Promise<void>((resolve) => {\n release = resolve;\n });\n const tail = previous.then(() => held);\n threadLocks.set(threadId, tail);\n await previous;\n try {\n const live = await this.liveRuns.find({ threadId });\n const run = live ? this.liveRuns.get(live.runId) : null;\n if (run) {\n // A run that already ended is still `find`-able for `ttlMs`; stopping\n // it is a no-op and waiting on it is the append it may still be doing.\n run.stop({ reason: \"superseded by a later turn on this thread\" });\n await persisted.get(run);\n }\n return await fn();\n } finally {\n release();\n if (threadLocks.get(threadId) === tail) {\n threadLocks.delete(threadId);\n }\n }\n }\n\n /**\n * `POST /<path>/attach` — subscribe to a run already in progress, from a\n * cursor. This is a read of a live run, not a continuation of a stopped one:\n * the work never paused, the listener changed.\n *\n * The cursor is `from`, else the client's `cursor`, else `Last-Event-ID`,\n * else the oldest frame still buffered — and it is honoured only for the run\n * the client's `runId` names. A cursor the buffer has dropped is a 410 naming\n * what survives; *no* cursor is the tail, because a page reattaching on mount\n * has no transcript to leave a hole in. See `resolveCursor`.\n */\n async attach(req: HttpRequest<any, any> = new HttpRequest()): Promise<Response> {\n const parsed = await readJsonBody(req);\n if (parsed.error) {\n return invalidRequest(parsed);\n }\n const body = parsed.body;\n const threadId =\n typeof body.threadId === \"string\" ? body.threadId : searchParam(req, \"threadId\");\n\n if (!threadId) {\n return jsonResponse(400, {\n code: \"invalid_request\",\n message: \"attach needs a threadId: it is the handle that survives a refresh.\",\n });\n }\n\n // The store is not consulted. This route answers whether a run is in\n // flight here, and a run it finds was started on a thread `stream` had\n // already loaded; a miss is `no_live_run` whether or not the thread exists,\n // because a client that gets one re-reads the thread anyway (see\n // `onAttachMiss`) and learns there. The thread's own 404 is `stream`'s,\n // where a turn would otherwise be persisted under it.\n const live = await this.liveRuns.find({ threadId });\n if (!live) {\n // An explicit miss, not a 200 with an empty stream. See `MemoryLiveRuns`:\n // behind a round-robin load balancer this is the common case, and it has\n // to be visible as one.\n return jsonResponse(404, {\n code: \"no_live_run\",\n message: `No run in progress for thread ${threadId} in this process.`,\n });\n }\n\n // A cursor is only a number if you know which run it counts within: `seq`\n // restarts at zero in every run, so honouring a cursor from run_1 against a\n // live run_2 would skip that many frames off the head of a run this client\n // has seen nothing of. `runId` is the client saying which run its cursor\n // means; naming one that is not live forfeits the cursor and takes the\n // tail, which is as close to the start as the buffer can offer.\n //\n // Only a MISMATCH forfeits. An absent `runId` is not a wrong answer, it is\n // an older question: `from` and `Last-Event-ID` predate the pairing and\n // carry no run, and an `EventSource` reconnecting on its own will never\n // grow one. Those keep resuming exactly as before.\n const cursorRunId = typeof body.runId === \"string\" ? body.runId : undefined;\n const cursor = cursorRunId && cursorRunId !== live.runId ? undefined : resolveCursor(req, body);\n\n try {\n return sseResponse(this.liveRuns.replay(live.runId, cursor));\n } catch (err) {\n if (err instanceof FrameCursorEvictedError) {\n // 410 rather than 404: the run is there, the position is not. A client\n // that gets this reloads the thread instead of resuming into a hole.\n return jsonResponse(410, {\n code: err.code,\n message: err.message,\n oldestSeq: err.oldest,\n });\n }\n if (err instanceof LiveRunNotFoundError) {\n // Lost the race with eviction between `find` and `replay`.\n return jsonResponse(404, { code: err.code, message: err.message });\n }\n throw err;\n }\n }\n\n /**\n * `POST /<path>/stop` — the explicit cancel. Since a dropped connection no\n * longer stops a run, this and a later turn on the same thread are the only\n * things that do, and it is why stopping cannot be a client-side concern:\n * the tool loop is here, and a client that stops reading has not stopped\n * step four from charging a card.\n *\n * Returns as soon as the run is aborted, not when it has finished unwinding.\n * The terminal events — the stopped tool results, the aborted message — go\n * out on the run's own stream, so whoever is watching it sees the ending,\n * and `onMessage` records it whether anyone is watching or not.\n *\n * Answers `{ stopped }` normally, and a `Response` only to reject a request\n * it could not read — the union is the error, not a second success shape.\n */\n async stop(\n req: HttpRequest<any, any> = new HttpRequest(),\n ): Promise<{ stopped: boolean } | Response> {\n const parsed = await readJsonBody(req);\n if (parsed.error) {\n // `{ stopped: false }` would be the wrong answer as well as the wrong\n // status: it means \"there was nothing to stop\", and the truth is that we\n // could not tell what to stop. A client that believes the first one stops\n // asking, and the run keeps going.\n return invalidRequest(parsed);\n }\n const body = parsed.body;\n\n // Three handles, most specific first, because which ones the client has\n // depends on how far the run got. `runId` is the server's own and settles\n // it. `clientRunId` covers the window before `run-start`, when the client\n // has nothing else for a stateless first turn — and, before that, a turn\n // that has not become a run yet because it is waiting its place on the\n // thread, which is ended where it waits. `threadId` is the fallback for a\n // client that did not start this run at all — one that attached to it,\n // whose replayed tail carried no `run-start`.\n let runId = typeof body.runId === \"string\" ? body.runId : undefined;\n if (!runId && typeof body.clientRunId === \"string\") {\n runId = this.liveRuns.findByClientRunId(body.clientRunId) ?? undefined;\n if (!runId) {\n const pending = pendingTurns.get(body.clientRunId);\n if (pending) {\n // Not on to `threadId`: that names the run this turn is queued\n // behind, which is already stopping, and answering for it would\n // leave this one to start.\n pending.cancelled = true;\n return { stopped: true };\n }\n }\n }\n if (!runId && typeof body.threadId === \"string\") {\n runId = (await this.liveRuns.find({ threadId: body.threadId }))?.runId;\n }\n\n const run = runId ? this.liveRuns.get(runId) : null;\n if (!run) {\n // Already finished, already evicted, or never here. Not an error: the\n // caller wanted the run stopped and it is not running.\n return { stopped: false };\n }\n\n run.stop({ reason: typeof body.reason === \"string\" ? body.reason : undefined });\n\n // Deliberately not awaiting `run.result()`. Unwinding means letting tools\n // in flight settle into `denied` results and finalizing the assistant\n // message, which can take as long as the slowest tool — and a stop button\n // that spins for twenty seconds is a stop button people press twice.\n return { stopped: true };\n }\n\n /** `POST /<path>/files` — uploads an attachment and returns its file id. */\n async upload(req: HttpRequest<any, any> = new HttpRequest()): Promise<{ fileId: string }> {\n const form = await req.rawRequest.formData();\n const file = form.get(\"file\");\n if (!(file instanceof Blob)) {\n throw new Error(\"upload expects a multipart body with a `file` field.\");\n }\n // Straight through the provider: message history holds provider file ids,\n // which is the trade `AgentProvider.upload` documents — vision and PDF\n // input without gemi owning a storage story in v1.\n const fileId = await this.agent.provider.upload(file as File);\n return { fileId };\n }\n\n /**\n * Protected, not private: these exist to be overridden. `onMessage` fires for\n * every completed message, user and assistant alike, and is the intended\n * persistence point for an app that is not using `store`.\n */\n protected onMessage(message: AgentMessage, ctx: AgentHookContext): void | Promise<void> {\n void message;\n void ctx;\n }\n\n protected onToolCall(\n call: { toolCallId: string; name: string; input: unknown },\n ctx: AgentHookContext,\n ): void | Promise<void> {\n void call;\n void ctx;\n }\n\n /** Fires before the stream ends `awaiting-input` — where to notify whoever\n * has to approve, if they are not the person watching the stream. */\n protected onAwaitingInput(\n pending: PendingToolCall[],\n ctx: AgentHookContext,\n ): void | Promise<void> {\n void pending;\n void ctx;\n }\n\n protected onError(error: AgentError, ctx: AgentHookContext): void | Promise<void> {\n void error;\n void ctx;\n }\n\n protected onStreamComplete(\n result: AgentRunResult<ToolShapesOf<A[\"tools\"]>, any>,\n ctx: AgentHookContext,\n ): void | Promise<void> {\n void result;\n void ctx;\n }\n\n /**\n * WHAT HAPPENS WHEN A HOOK THROWS: it is reported and the run carries on.\n *\n * The alternative is to fail the run, and that trade is not close. These\n * hooks are an app's persistence and notification points; the run is a model\n * call the user has already been charged for and whose tools may already have\n * charged a card. Letting a failed `INSERT` in `onMessage` abort a generation\n * mid-sentence loses the answer as well as the row, and the user cannot\n * retry into a better outcome. So the answer survives and the failure is\n * logged.\n *\n * It is logged rather than routed to `onError`: `onError` is itself a hook,\n * and a hook that throws inside the handler for hooks that throw is a loop.\n * Override this to send it somewhere with a pager attached.\n */\n protected reportHookFailure(error: unknown): void {\n console.error(\"[gemi/ai] agent controller hook failed\", error);\n }\n\n private async dispatchEvent(event: AgentStreamEvent, ctx: AgentHookContext): Promise<void> {\n switch (event.type) {\n case \"tool-call\":\n // Skipped while the arguments are still streaming: a hook that fires\n // per token would fire with a half-parsed input, which is worse than\n // firing late. And skipped for a re-sent frame, which carries a parked\n // sub-run's record on a call this hook has already seen — once per call\n // is the contract, and a run that re-parks would otherwise fire it for\n // a call some earlier run made.\n if (!event.part.partial && !event.resent) {\n await this.onToolCall(\n {\n toolCallId: event.part.toolCallId,\n name: String(event.part.name),\n input: event.part.input,\n },\n ctx,\n );\n }\n return;\n case \"awaiting-input\":\n await this.onAwaitingInput(event.pending as PendingToolCall[], ctx);\n return;\n case \"error\":\n await this.onError(event.error, ctx);\n return;\n default:\n return;\n }\n }\n\n /**\n * Runs after the stream is over, whether or not anyone was still watching it.\n *\n * The messages come from `result()` rather than from the event stream because\n * assembling a message out of deltas is the agent's job and doing it twice is\n * how the two copies drift. It also means a stopped run persists the same way\n * a finished one does: `stop()` finalizes the transcript, so by the time this\n * resolves there is a valid history to store.\n *\n * Settles when the transcript is in the store, not when the app is done with\n * it. The next turn on this thread waits on this (see `withThread`), and the\n * hooks are the app's: an `onMessage` that writes to something slow would\n * make every later turn wait for it, once per message of the old run, and\n * one that never settles — which `safely` cannot catch — would hold the\n * thread, and every turn queued on it, behind an open connection each. So\n * the hooks run on after this on their own, reported the same way.\n */\n private async persistRun(run: AgentRun, ctx: AgentHookContext): Promise<void> {\n let result: AgentRunResult<ToolShapes, unknown>;\n try {\n result = await run.result();\n } catch (err) {\n void this.safely(() =>\n this.onError(\n {\n code: \"unknown\",\n message: err instanceof Error ? err.message : String(err),\n retryable: false,\n },\n ctx,\n ),\n );\n return;\n }\n\n const messages = result.messages as AgentMessage[];\n\n if (ctx.threadId && messages.length > 0) {\n try {\n await this.store.appendMessages(ctx.threadId, messages);\n } catch (err) {\n this.reportHookFailure(err);\n }\n }\n\n void this.notifyRun(result, messages, ctx);\n }\n\n /** The hooks on a finished run, in order. Never rejects: see `safely`. */\n private async notifyRun(\n result: AgentRunResult<ToolShapes, unknown>,\n messages: AgentMessage[],\n ctx: AgentHookContext,\n ): Promise<void> {\n for (const message of messages) {\n await this.safely(() => this.onMessage(message, ctx));\n }\n\n await this.safely(() => this.onStreamComplete(result as any, ctx));\n }\n\n private async safely(fn: () => void | Promise<void>): Promise<void> {\n try {\n await fn();\n } catch (err) {\n this.reportHookFailure(err);\n }\n }\n}\n\n// --- request plumbing ----------------------------------------------------\n\n/**\n * A body, or the reason there is not one.\n *\n * Deliberately one shape with an optional `error` rather than a discriminated\n * union on `ok`: this package compiles with `strict: false`, and without\n * `strictNullChecks` TypeScript will not narrow a union by a boolean\n * discriminant — `if (!parsed.ok)` leaves `parsed.message` an error. A field\n * that is either set or not needs no narrowing to read.\n */\ntype ParsedBody = {\n body: Record<string, any>;\n error?: string;\n /** Which HTTP error the rejection is. A missing one is the 400. */\n status?: number;\n code?: string;\n};\n\n/**\n * The body, as JSON — or a reason it is not.\n *\n * Read off the raw request rather than through `req.input()`: that path matches\n * `Content-Type` exactly, so `application/json; charset=utf-8` — which several\n * HTTP clients send by default — parses as an empty body, and an agent turn\n * that silently loses its text is a bad way to find that out.\n *\n * Matching the type by prefix is not the same as ignoring it. A body that\n * arrives as anything other than `application/json` is a 415, and the reason\n * is not tidiness: a cross-site `<form enctype=\"text/plain\">` can be made to\n * concatenate its one field into valid JSON, and a JSON parser that reads\n * whatever it is handed turns that form into a turn on someone else's\n * conversation. Insisting on `application/json` is what makes these routes\n * non-simple requests — the browser will not send one cross-origin without a\n * preflight — and that holds whether or not the app's cookies are `SameSite`\n * and whether or not `CSRFMiddleware` is mounted. Only a request that carries a\n * body is held to this; a bodiless POST has no type to check and stays `{}`.\n *\n * The three cases are kept apart deliberately. NO body is a real request — a\n * reattach, or a turn that just lets the model continue — and reads as `{}`. A\n * body that will not parse, or that parses to something other than an object,\n * is a failed request and has to say so: folding it into `{}` made a truncated\n * proxy response or a mis-serialized client indistinguishable from an empty\n * turn, so `stream` billed a model call with no history and no turn and threw\n * the user's actual message away. That presents as the model hallucinating\n * rather than as an error, which is the expensive way to debug it. Pre-flight\n * failures stay ordinary HTTP errors and never reach the event stream.\n *\n * An array counts as malformed even though `typeof [] === \"object\"`: nothing\n * downstream reads a positional body, so `[1,2,3]` could only ever have run as\n * an empty turn.\n */\nasync function readJsonBody(req: HttpRequest<any, any>): Promise<ParsedBody> {\n const raw = req?.rawRequest;\n if (!raw || raw.method === \"GET\" || raw.method === \"HEAD\" || !raw.body) {\n return { body: {} };\n }\n\n if (!isJsonContentType(raw.headers.get(\"Content-Type\"))) {\n // Before the body is read: nothing in a body about to be refused is worth\n // the bytes, and the refusal must not depend on what they were.\n return {\n body: {},\n status: 415,\n code: \"unsupported_media_type\",\n error: \"The request body must be sent as application/json.\",\n };\n }\n\n let text: string;\n try {\n text = await raw.text();\n } catch {\n // A body that stopped arriving mid-flight. Same class of failure as one\n // that arrived truncated, and the same answer.\n return { body: {}, error: \"The request body could not be read.\" };\n }\n\n if (!text.trim()) {\n return { body: {} };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return { body: {}, error: \"The request body is not valid JSON.\" };\n }\n\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return { body: {}, error: \"The request body must be a JSON object.\" };\n }\n\n return { body: parsed as Record<string, any> };\n}\n\n/**\n * Media types compare case-insensitively and may carry parameters, so the\n * comparison is on the lowercased type with its parameters cut off, and\n * `Application/JSON; charset=utf-8` passes. It is an equality on that type\n * rather than a prefix, so `application/json-seq` and the other types that\n * merely begin with those bytes do not. None of the three types a browser will\n * send without a preflight — `text/plain`, `application/x-www-form-urlencoded`,\n * `multipart/form-data` — does either, and neither does no type at all, which\n * is what a hand-written `fetch` with a string body and no header ends up\n * sending as `text/plain`.\n */\nfunction isJsonContentType(value: string | null): boolean {\n if (typeof value !== \"string\") return false;\n const [type] = value.split(\";\", 1);\n return type.trim().toLowerCase() === \"application/json\";\n}\n\nfunction invalidRequest(parsed: ParsedBody): Response {\n return jsonResponse(parsed.status ?? 400, {\n code: parsed.code ?? \"invalid_request\",\n message: parsed.error,\n });\n}\n\n/**\n * The client's turn, accepting both `{ turn: {...} }` and the flattened\n * `{ text, files, toolResults }` — the second is what a hand-written `fetch`\n * writes, and refusing it buys nothing.\n *\n * Returns `undefined` for an empty turn, which is a real request: reattaching\n * to a conversation and letting the model continue is a turn with nothing in\n * it.\n */\nfunction toClientTurn(body: Record<string, any>): ClientTurn | undefined {\n const source = body.turn && typeof body.turn === \"object\" ? body.turn : body;\n const turn: ClientTurn = {};\n if (typeof source.text === \"string\") {\n turn.text = source.text;\n }\n if (Array.isArray(source.files)) {\n turn.files = source.files;\n }\n if (Array.isArray(source.toolResults)) {\n turn.toolResults = source.toolResults;\n }\n return Object.keys(turn).length > 0 ? turn : undefined;\n}\n\n/**\n * Where to resume from, or `undefined` for \"wherever you still can\".\n *\n * An explicit `from` wins, because a client that tracked its own position knows\n * something the transport does not. Otherwise `Last-Event-ID` — the browser\n * sends it on its own when an `EventSource` reconnects, and the frames put\n * `seq` in `id:` precisely so that header is already the right question. It\n * names the last event *received*, so the resume point is one past it.\n *\n * With neither, the answer is `undefined` and NOT 0. A client reattaching on\n * mount is a fresh POST from a page that has just loaded: no `Last-Event-ID`,\n * and no cursor of its own, because the only handle it was given is the\n * `threadId`. Reading that as \"resume from frame 0\" asked `replay` for a frame\n * every run longer than `maxFrames` has already evicted, so the mount-time\n * reattach — the one case `/attach` exists for — 410'd on exactly the long runs\n * it was meant to rescue, and the documented remedy of reloading the thread\n * does not help because the store is only written at run end. `undefined` means\n * the tail, which is all such a client can use anyway.\n */\nfunction resolveCursor(req: HttpRequest<any, any>, body: Record<string, any>): number | undefined {\n if (typeof body.from === \"number\" && Number.isFinite(body.from)) {\n return Math.max(0, Math.floor(body.from));\n }\n // `cursor` is what `useChat` actually sends, and it counts the other way:\n // `from` is the frame to resume AT, `cursor` the last frame the client\n // APPLIED — the same convention as `Last-Event-ID`, and the same `+ 1`. A\n // client that has applied nothing sends -1, which is not a position but the\n // absence of one, so it falls through to the tail rather than asking for\n // frame 0 and 410ing on precisely the long runs `/attach` exists to rescue.\n if (typeof body.cursor === \"number\" && Number.isFinite(body.cursor)) {\n const applied = Math.floor(body.cursor);\n if (applied >= 0) {\n return applied + 1;\n }\n return undefined;\n }\n const header = req?.rawRequest?.headers?.get(\"Last-Event-ID\");\n if (header) {\n const seq = Number.parseInt(header, 10);\n if (Number.isFinite(seq)) {\n return Math.max(0, seq + 1);\n }\n }\n return undefined;\n}\n\nfunction searchParam(req: HttpRequest<any, any>, key: string): string | undefined {\n const value = req?.search?.get(key);\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction jsonResponse(status: number, error: Record<string, unknown>): Response {\n return new Response(JSON.stringify({ error }), {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\n// --- routing -------------------------------------------------------------\n//\n// `agent()` itself belongs on ApiRouter next to `resource()`, which is the\n// method it works like: one call, several routes, all of them the controller's.\n// The types are declared here because they are the ai module's contract, not\n// the router's.\n//\n// class Api extends ApiRouter {\n// routes = {\n// \"/chat\": this.agent(ChatAgentController),\n// };\n// }\n//\n// POST /chat → stream every client turn\n// POST /chat/attach → attach reattach to a run in progress\n// POST /chat/stop → stop explicit cancel\n// POST /chat/files → upload attachments\n//\n// Mounting under a single path is what gives the client one key to name. The\n// agent's tool types ride along on `AgentRoute`, so `useChat(\"/chat\")` gets them\n// out of the existing `RPC` interface — no second augmentation to generate, and\n// renaming the route moves the client key with it.\n\nexport type AgentRouteMethod = \"stream\" | \"attach\" | \"stop\" | \"upload\";\n\nexport type AgentMiddlewareConfig = Partial<Record<AgentRouteMethod, MiddlewareInput>>;\n\nexport type AgentRoute<T extends new () => AgentController<any>> = {\n __internal_brand: \"AgentRoute\";\n controller: T;\n middleware(config: AgentMiddlewareConfig): AgentRoute<T>;\n};\n\n/** What `CreateRPC` should produce for an agent route: enough for the client to\n * type its messages, and nothing that drags server code into the bundle. */\nexport type AgentRouteRPC<T extends new () => AgentController<any>> = {\n __agent: true;\n tools: InstanceType<T>[\"agent\"] extends AnyAgent\n ? ToolShapesOf<InstanceType<T>[\"agent\"][\"tools\"]>\n : ToolShapes;\n output: unknown;\n};\n"
19
+ ],
20
+ "mappings": "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",
21
+ "debugId": "906EB9538B9BB7D764756E2164756E21",
22
+ "names": []
23
+ }