@namzu/sdk 40.0.0 → 42.0.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 (188) hide show
  1. package/CHANGELOG.md +236 -0
  2. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  3. package/dist/agents/ReactiveAgent.js +3 -0
  4. package/dist/agents/ReactiveAgent.js.map +1 -1
  5. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  6. package/dist/agents/SupervisorAgent.js +11 -0
  7. package/dist/agents/SupervisorAgent.js.map +1 -1
  8. package/dist/agents/runAgent.d.ts +14 -0
  9. package/dist/agents/runAgent.d.ts.map +1 -1
  10. package/dist/agents/runAgent.js +3 -0
  11. package/dist/agents/runAgent.js.map +1 -1
  12. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  13. package/dist/bridge/a2a/mapper.js +8 -0
  14. package/dist/bridge/a2a/mapper.js.map +1 -1
  15. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  16. package/dist/bridge/sse/mapper.js +11 -0
  17. package/dist/bridge/sse/mapper.js.map +1 -1
  18. package/dist/connector/index.d.ts +2 -2
  19. package/dist/connector/index.d.ts.map +1 -1
  20. package/dist/connector/index.js +1 -1
  21. package/dist/connector/index.js.map +1 -1
  22. package/dist/connector/mcp/adapter.d.ts.map +1 -1
  23. package/dist/connector/mcp/adapter.js +92 -4
  24. package/dist/connector/mcp/adapter.js.map +1 -1
  25. package/dist/connector/mcp/audio-admission.d.ts +17 -0
  26. package/dist/connector/mcp/audio-admission.d.ts.map +1 -0
  27. package/dist/connector/mcp/audio-admission.js +171 -0
  28. package/dist/connector/mcp/audio-admission.js.map +1 -0
  29. package/dist/connector/mcp/client.d.ts +252 -1
  30. package/dist/connector/mcp/client.d.ts.map +1 -1
  31. package/dist/connector/mcp/client.js +611 -39
  32. package/dist/connector/mcp/client.js.map +1 -1
  33. package/dist/connector/mcp/envelope.d.ts +91 -0
  34. package/dist/connector/mcp/envelope.d.ts.map +1 -0
  35. package/dist/connector/mcp/envelope.js +173 -0
  36. package/dist/connector/mcp/envelope.js.map +1 -0
  37. package/dist/connector/mcp/era.d.ts +130 -0
  38. package/dist/connector/mcp/era.d.ts.map +1 -0
  39. package/dist/connector/mcp/era.js +304 -0
  40. package/dist/connector/mcp/era.js.map +1 -0
  41. package/dist/connector/mcp/errors.d.ts +106 -0
  42. package/dist/connector/mcp/errors.d.ts.map +1 -0
  43. package/dist/connector/mcp/errors.js +154 -0
  44. package/dist/connector/mcp/errors.js.map +1 -0
  45. package/dist/connector/mcp/http-sse.d.ts +11 -0
  46. package/dist/connector/mcp/http-sse.d.ts.map +1 -1
  47. package/dist/connector/mcp/http-sse.js +21 -6
  48. package/dist/connector/mcp/http-sse.js.map +1 -1
  49. package/dist/connector/mcp/index.d.ts +7 -0
  50. package/dist/connector/mcp/index.d.ts.map +1 -1
  51. package/dist/connector/mcp/index.js +10 -0
  52. package/dist/connector/mcp/index.js.map +1 -1
  53. package/dist/connector/mcp/streamable-http.d.ts +83 -0
  54. package/dist/connector/mcp/streamable-http.d.ts.map +1 -1
  55. package/dist/connector/mcp/streamable-http.js +177 -11
  56. package/dist/connector/mcp/streamable-http.js.map +1 -1
  57. package/dist/connector/mcp/x-mcp-header.d.ts +56 -0
  58. package/dist/connector/mcp/x-mcp-header.d.ts.map +1 -0
  59. package/dist/connector/mcp/x-mcp-header.js +254 -0
  60. package/dist/connector/mcp/x-mcp-header.js.map +1 -0
  61. package/dist/constants/mcp/index.d.ts +123 -15
  62. package/dist/constants/mcp/index.d.ts.map +1 -1
  63. package/dist/constants/mcp/index.js +135 -16
  64. package/dist/constants/mcp/index.js.map +1 -1
  65. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  66. package/dist/manager/agent/lifecycle.js +43 -0
  67. package/dist/manager/agent/lifecycle.js.map +1 -1
  68. package/dist/prompt/coding-agent-doctrine.d.ts +20 -0
  69. package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
  70. package/dist/prompt/coding-agent-doctrine.js +19 -3
  71. package/dist/prompt/coding-agent-doctrine.js.map +1 -1
  72. package/dist/prompt/index.d.ts +1 -1
  73. package/dist/prompt/index.d.ts.map +1 -1
  74. package/dist/prompt/index.js +1 -1
  75. package/dist/prompt/index.js.map +1 -1
  76. package/dist/public-runtime.d.ts +7 -4
  77. package/dist/public-runtime.d.ts.map +1 -1
  78. package/dist/public-runtime.js +16 -4
  79. package/dist/public-runtime.js.map +1 -1
  80. package/dist/public-tools.d.ts +1 -1
  81. package/dist/public-tools.d.ts.map +1 -1
  82. package/dist/public-tools.js +4 -2
  83. package/dist/public-tools.js.map +1 -1
  84. package/dist/registry/tool/execute.d.ts.map +1 -1
  85. package/dist/registry/tool/execute.js +10 -1
  86. package/dist/registry/tool/execute.js.map +1 -1
  87. package/dist/runtime/bidi/session.d.ts +11 -0
  88. package/dist/runtime/bidi/session.d.ts.map +1 -1
  89. package/dist/runtime/bidi/session.js +2 -0
  90. package/dist/runtime/bidi/session.js.map +1 -1
  91. package/dist/runtime/query/executor.d.ts +6 -0
  92. package/dist/runtime/query/executor.d.ts.map +1 -1
  93. package/dist/runtime/query/executor.js +6 -0
  94. package/dist/runtime/query/executor.js.map +1 -1
  95. package/dist/runtime/query/guardrail-presets.d.ts +187 -1
  96. package/dist/runtime/query/guardrail-presets.d.ts.map +1 -1
  97. package/dist/runtime/query/guardrail-presets.js +298 -0
  98. package/dist/runtime/query/guardrail-presets.js.map +1 -1
  99. package/dist/runtime/query/index.d.ts +14 -0
  100. package/dist/runtime/query/index.d.ts.map +1 -1
  101. package/dist/runtime/query/index.js +3 -0
  102. package/dist/runtime/query/index.js.map +1 -1
  103. package/dist/runtime/query/tooling.d.ts +2 -0
  104. package/dist/runtime/query/tooling.d.ts.map +1 -1
  105. package/dist/runtime/query/tooling.js +3 -0
  106. package/dist/runtime/query/tooling.js.map +1 -1
  107. package/dist/sandbox/provider/local.d.ts.map +1 -1
  108. package/dist/sandbox/provider/local.js +46 -3
  109. package/dist/sandbox/provider/local.js.map +1 -1
  110. package/dist/scheduler/local.d.ts.map +1 -1
  111. package/dist/scheduler/local.js +8 -0
  112. package/dist/scheduler/local.js.map +1 -1
  113. package/dist/store/run/disk.d.ts +35 -1
  114. package/dist/store/run/disk.d.ts.map +1 -1
  115. package/dist/store/run/disk.js +100 -0
  116. package/dist/store/run/disk.js.map +1 -1
  117. package/dist/tools/coordinator/agent.d.ts.map +1 -1
  118. package/dist/tools/coordinator/agent.js +17 -2
  119. package/dist/tools/coordinator/agent.js.map +1 -1
  120. package/dist/tools/coordinator/index.d.ts.map +1 -1
  121. package/dist/tools/coordinator/index.js +17 -3
  122. package/dist/tools/coordinator/index.js.map +1 -1
  123. package/dist/tools/untrusted-envelope.d.ts +35 -0
  124. package/dist/tools/untrusted-envelope.d.ts.map +1 -1
  125. package/dist/tools/untrusted-envelope.js +91 -3
  126. package/dist/tools/untrusted-envelope.js.map +1 -1
  127. package/dist/types/agent/base.d.ts +23 -0
  128. package/dist/types/agent/base.d.ts.map +1 -1
  129. package/dist/types/agent/scheduler.d.ts +20 -0
  130. package/dist/types/agent/scheduler.d.ts.map +1 -1
  131. package/dist/types/agent/task.d.ts +39 -0
  132. package/dist/types/agent/task.d.ts.map +1 -1
  133. package/dist/types/connector/mcp.d.ts +205 -0
  134. package/dist/types/connector/mcp.d.ts.map +1 -1
  135. package/dist/types/run/events.d.ts +56 -0
  136. package/dist/types/run/events.d.ts.map +1 -1
  137. package/dist/types/run/events.js.map +1 -1
  138. package/dist/types/run/store.d.ts +41 -0
  139. package/dist/types/run/store.d.ts.map +1 -1
  140. package/dist/types/sandbox/index.d.ts +68 -1
  141. package/dist/types/sandbox/index.d.ts.map +1 -1
  142. package/dist/types/sandbox/index.js.map +1 -1
  143. package/dist/types/tool/index.d.ts +19 -0
  144. package/dist/types/tool/index.d.ts.map +1 -1
  145. package/dist/types/tool/index.js.map +1 -1
  146. package/package.json +1 -1
  147. package/src/agents/ReactiveAgent.ts +3 -0
  148. package/src/agents/SupervisorAgent.ts +11 -0
  149. package/src/agents/runAgent.ts +18 -0
  150. package/src/bridge/a2a/mapper.ts +8 -0
  151. package/src/bridge/sse/mapper.ts +11 -0
  152. package/src/connector/index.ts +27 -0
  153. package/src/connector/mcp/adapter.ts +103 -4
  154. package/src/connector/mcp/audio-admission.ts +173 -0
  155. package/src/connector/mcp/client.ts +694 -45
  156. package/src/connector/mcp/envelope.ts +235 -0
  157. package/src/connector/mcp/era.ts +400 -0
  158. package/src/connector/mcp/errors.ts +171 -0
  159. package/src/connector/mcp/http-sse.ts +23 -6
  160. package/src/connector/mcp/index.ts +37 -0
  161. package/src/connector/mcp/streamable-http.ts +199 -11
  162. package/src/connector/mcp/x-mcp-header.ts +322 -0
  163. package/src/constants/mcp/index.ts +145 -16
  164. package/src/manager/agent/lifecycle.ts +51 -0
  165. package/src/prompt/coding-agent-doctrine.ts +31 -4
  166. package/src/prompt/index.ts +1 -0
  167. package/src/public-runtime.ts +42 -0
  168. package/src/public-tools.ts +8 -2
  169. package/src/registry/tool/execute.ts +9 -1
  170. package/src/runtime/bidi/session.ts +13 -0
  171. package/src/runtime/query/executor.ts +13 -0
  172. package/src/runtime/query/guardrail-presets.ts +356 -0
  173. package/src/runtime/query/index.ts +17 -0
  174. package/src/runtime/query/tooling.ts +5 -0
  175. package/src/sandbox/provider/local.ts +45 -2
  176. package/src/scheduler/local.ts +8 -0
  177. package/src/store/run/disk.ts +108 -0
  178. package/src/tools/coordinator/agent.ts +17 -2
  179. package/src/tools/coordinator/index.ts +17 -3
  180. package/src/tools/untrusted-envelope.ts +94 -3
  181. package/src/types/agent/base.ts +24 -0
  182. package/src/types/agent/scheduler.ts +21 -0
  183. package/src/types/agent/task.ts +41 -0
  184. package/src/types/connector/mcp.ts +205 -1
  185. package/src/types/run/events.ts +56 -0
  186. package/src/types/run/store.ts +42 -0
  187. package/src/types/sandbox/index.ts +69 -1
  188. package/src/types/tool/index.ts +20 -0
@@ -40,11 +40,40 @@ export interface MCPStdioTransportConfig extends MCPTransportConfigBase {
40
40
  cwd?: string
41
41
  }
42
42
 
43
+ /**
44
+ * Anything that answers like `fetch`, restricted to the request shape the
45
+ * MCP HTTP transports actually send: a URL string, an optional
46
+ * method/headers/body, `redirect` (both transports pin this to `'manual'`
47
+ * so a caller cannot silently re-enable auto-following a redirect), and an
48
+ * abort signal.
49
+ *
50
+ * Structurally identical in spirit to `bridge/a2a/client.ts`'s `FetchLike`
51
+ * — the same injectable, socket-free function shape, so a test needs no
52
+ * socket — but the return type stays the real `Response` rather than that
53
+ * bridge's narrower `{ok, status, json(), text()}` duck type: both MCP
54
+ * transports already read `.headers` (content type, session id) and one of
55
+ * them reads `.body` as a stream (the SSE GET), neither of which the A2A
56
+ * bridge's version exposes. Re-declared here, rather than imported from the
57
+ * A2A bridge, so that bridge is not forced to grow fields it does not use.
58
+ */
59
+ export type MCPFetchLike = (
60
+ input: string,
61
+ init?: {
62
+ method?: string
63
+ headers?: Record<string, string>
64
+ body?: string
65
+ redirect?: 'manual' | 'follow' | 'error'
66
+ signal?: AbortSignal
67
+ },
68
+ ) => Promise<Response>
69
+
43
70
  export interface MCPHttpSseTransportConfig extends MCPTransportConfigBase {
44
71
  type: 'http-sse'
45
72
  url: string
46
73
  headers?: Record<string, string>
47
74
  timeoutMs?: number
75
+ /** Injected in place of the ambient global `fetch`. Defaults to it. */
76
+ fetch?: MCPFetchLike
48
77
  }
49
78
 
50
79
  export interface MCPStreamableHttpTransportConfig extends MCPTransportConfigBase {
@@ -52,6 +81,8 @@ export interface MCPStreamableHttpTransportConfig extends MCPTransportConfigBase
52
81
  url: string
53
82
  headers?: Record<string, string>
54
83
  timeoutMs?: number
84
+ /** Injected in place of the ambient global `fetch`. Defaults to it. */
85
+ fetch?: MCPFetchLike
55
86
  }
56
87
 
57
88
  export type MCPTransportUnion =
@@ -65,6 +96,79 @@ export interface MCPJsonRpcError {
65
96
  data?: unknown
66
97
  }
67
98
 
99
+ /**
100
+ * A protocol revision this client can still negotiate DOWN to when a server
101
+ * does not speak the current spec, newest first.
102
+ *
103
+ * Kept as a literal union (rather than just `string`) so a caller pattern
104
+ * matching on `McpEra` gets real exhaustiveness checking; the runtime array
105
+ * of the same values lives in `constants/mcp` and is typed against this.
106
+ */
107
+ export type McpLegacyVersion = '2025-11-25' | '2025-06-18' | '2025-03-26' | '2024-11-05'
108
+
109
+ /**
110
+ * A protocol revision this client speaks WITHOUT the `initialize`
111
+ * handshake.
112
+ *
113
+ * A modern connection is stateless: there is no handshake, no session id,
114
+ * and every request carries its own protocol version, client capabilities
115
+ * and client info in `_meta`. `connect()` probes for one before it offers
116
+ * the legacy handshake.
117
+ */
118
+ export type McpModernVersion = '2026-07-28'
119
+
120
+ /**
121
+ * Which family of the wire protocol a connection resolved to, and which
122
+ * exact revision within it.
123
+ *
124
+ * `kind` alone tells a caller which rules apply — whether `_meta` and the
125
+ * stateless per-request shape are in play, or the `initialize` handshake
126
+ * and (for 2025-06-18 and later) the `MCP-Protocol-Version` header — without
127
+ * re-deriving it from the version string on every read.
128
+ *
129
+ * `MCPClient.connect()` resolves this by probing for a modern peer first
130
+ * and falling back to the legacy `initialize` handshake, so which arm a
131
+ * given connection lands on is the server's answer, not a configuration.
132
+ */
133
+ export type McpEra =
134
+ | { readonly kind: 'modern'; readonly version: McpModernVersion }
135
+ | { readonly kind: 'legacy'; readonly version: McpLegacyVersion }
136
+
137
+ /**
138
+ * What a modern server answers `server/discover` with.
139
+ *
140
+ * The modern era's replacement for the `initialize` result: it names the
141
+ * revisions the server speaks, what it can do, and — under the reserved
142
+ * `_meta` key — who it is. Every field is optional on the wire as far as
143
+ * this client is concerned, because the one thing it MUST be able to do
144
+ * with a malformed answer is decline to treat it as proof of a modern peer.
145
+ */
146
+ export interface MCPDiscoverResult {
147
+ /** Newest first is conventional but not required; this client sorts. */
148
+ supportedVersions?: readonly string[]
149
+ capabilities?: MCPServerCapabilities
150
+ _meta?: Record<string, unknown>
151
+ }
152
+
153
+ /**
154
+ * Where a resolved {@link McpEra} is remembered between connections.
155
+ *
156
+ * The spec's own guidance: a client SHOULD cache the era for the lifetime
157
+ * of the server process (stdio) or the origin (HTTP) and re-probe if the
158
+ * cached assumption later fails. Without it every connection to a legacy
159
+ * server pays a wasted probe round trip.
160
+ *
161
+ * An interface rather than a module-level `Map` because a process-global
162
+ * cache leaks between tests and would make a conformance suite depend on
163
+ * the order its cases happen to run in. `MCPClientConfig.eraCache` injects
164
+ * one; omitting it uses a process-wide default.
165
+ */
166
+ export interface MCPEraCache {
167
+ get(key: string): McpEra | undefined
168
+ set(key: string, era: McpEra): void
169
+ delete(key: string): void
170
+ }
171
+
68
172
  export interface MCPJsonRpcMessage {
69
173
  jsonrpc: '2.0'
70
174
  id?: string | number
@@ -83,12 +187,48 @@ export interface MCPRequestOptions {
83
187
  * waiting, not that an already-started remote side effect was rolled back.
84
188
  */
85
189
  readonly signal?: AbortSignal
190
+ /**
191
+ * Extra headers for this one request, merged over the transport's static
192
+ * config headers (a collision resolves to this value) and under this same
193
+ * call's `bearerToken`, if both are given.
194
+ *
195
+ * The protocol's own headers are the exception: `MCP-Protocol-Version`,
196
+ * `Mcp-Method` and `Mcp-Name` mirror values inside the request this call
197
+ * is sending, and a server rejects a header that disagrees with the body
198
+ * it mirrors. A value given here under one of those names — matched
199
+ * without regard to case — is refused and warn-logged rather than put on
200
+ * the wire.
201
+ *
202
+ * A transport with no header concept (stdio) receives the field and does
203
+ * nothing with it.
204
+ */
205
+ readonly headers?: Readonly<Record<string, string>>
206
+ /**
207
+ * Sent as `Authorization: Bearer <bearerToken>` on this one request.
208
+ *
209
+ * Overrides a configured `Authorization` header — static or supplied via
210
+ * `headers` above — for this request only; it never touches a
211
+ * differently-named header such as a static `X-API-Key`. Omit it and a
212
+ * configured `Authorization` header is left exactly as configured.
213
+ */
214
+ readonly bearerToken?: string
86
215
  }
87
216
 
88
217
  /** Authority for one transport write and any response body it consumes. */
89
218
  export interface MCPTransportSendOptions {
90
219
  /** A pre-aborted signal starts no transport work. */
91
220
  readonly signal?: AbortSignal
221
+ /**
222
+ * Extra headers for this one send.
223
+ *
224
+ * An HTTP-speaking transport merges these over its static config
225
+ * headers; a transport with no header concept (stdio) receives the
226
+ * field and does nothing with it. Introduced so the client — which
227
+ * alone knows the negotiated era — can ask for `MCP-Protocol-Version`
228
+ * on a post-initialize request without the transport having to know
229
+ * what a protocol version is.
230
+ */
231
+ readonly headers?: Readonly<Record<string, string>>
92
232
  }
93
233
 
94
234
  export interface MCPTransport {
@@ -138,10 +278,38 @@ export interface MCPToolDefinition {
138
278
  annotations?: MCPToolAnnotations
139
279
  }
140
280
 
281
+ /**
282
+ * Audience/priority/freshness hints a server may attach to a content block,
283
+ * part of the schema since 2025-06-18. Advisory only: namzu does not act on
284
+ * any of these fields today, but drops none of them either — they survive
285
+ * into `ToolResult.data` for a host that wants to read them.
286
+ *
287
+ * Distinct from {@link MCPToolAnnotations}, which describes a TOOL
288
+ * (read-only, destructive, …); this describes one piece of CONTENT.
289
+ */
290
+ export interface MCPContentAnnotations {
291
+ audience?: Array<'user' | 'assistant'>
292
+ priority?: number
293
+ lastModified?: string
294
+ }
295
+
141
296
  export type MCPContentBlock =
142
297
  | { type: 'text'; text: string }
143
298
  | { type: 'image'; data: string; mimeType: string }
144
- | { type: 'resource'; resource: { uri: string; mimeType?: string; text?: string } }
299
+ | {
300
+ type: 'resource'
301
+ resource: { uri: string; mimeType?: string; text?: string; blob?: string }
302
+ annotations?: MCPContentAnnotations
303
+ }
304
+ /** Since 2025-03-26. Raw audio bytes, base64-encoded like `image`. */
305
+ | { type: 'audio'; data: string; mimeType: string }
306
+ /**
307
+ * Since 2025-06-18. A pointer to a resource the server has NOT embedded
308
+ * inline — unlike `resource`, which always carries `text` or `blob`.
309
+ * Because this block carries no content at all, the adapter names it
310
+ * for the model rather than fabricating text the server never sent.
311
+ */
312
+ | { type: 'resource_link'; uri: string; name: string; description?: string; mimeType?: string }
145
313
 
146
314
  export interface MCPToolResult {
147
315
  content: MCPContentBlock[]
@@ -160,6 +328,23 @@ export interface MCPToolResult {
160
328
  _meta?: Record<string, unknown>
161
329
  }
162
330
 
331
+ /**
332
+ * One thing the client would have to do that it never declared it could —
333
+ * elicit input, sample a message, list roots, or something a later spec
334
+ * revision defines. Only `method` is read by this client; every other field
335
+ * is carried opaquely so a shape it does not understand still names itself.
336
+ *
337
+ * namzu declares `clientCapabilities: {}` in every era, so MRTR rule 7 — a
338
+ * server MUST NOT send an `inputRequests` entry for a capability the client
339
+ * did not declare — means a CONFORMING server never produces one of these.
340
+ * The type exists for the defensive path: a non-conforming server's demand
341
+ * is named and refused rather than silently misread as an ordinary result.
342
+ */
343
+ export interface MCPInputRequest {
344
+ readonly method: string
345
+ readonly [key: string]: unknown
346
+ }
347
+
163
348
  export interface MCPResource {
164
349
  uri: string
165
350
  name: string
@@ -242,6 +427,25 @@ export interface MCPClientConfig {
242
427
  * forever — no error, no failure, just a run that stopped.
243
428
  */
244
429
  requestTimeoutMs?: number
430
+ /**
431
+ * How long `connect()`'s era probe waits for an answer before deciding
432
+ * the peer speaks a legacy revision. Defaults to
433
+ * `DEFAULT_MCP_ERA_PROBE_TIMEOUT_MS`.
434
+ *
435
+ * Never longer than `requestTimeoutMs`: a probe is a request, and a
436
+ * probe that outlived the deadline every other request is held to would
437
+ * be a connect that hangs past its own timeout.
438
+ */
439
+ eraProbeTimeoutMs?: number
440
+ /**
441
+ * Where this client reads and records the resolved era.
442
+ *
443
+ * Defaults to a process-wide cache shared by every `MCPClient`, which is
444
+ * the point — two clients reaching the same origin should not each pay a
445
+ * probe. Inject a fresh one to isolate a test, or a longer-lived one to
446
+ * scope the memory to a host rather than the process.
447
+ */
448
+ eraCache?: MCPEraCache
245
449
  /**
246
450
  * A pre-built logger. Threaded into the transport `MCPClient` constructs
247
451
  * internally (`createTransport`), so a caller that supplies this gets a
@@ -812,6 +812,62 @@ type CoreRunEvent =
812
812
  /** Approved plan edge carried while the blocking tool is still live. */
813
813
  planId?: string
814
814
  planStepId?: string
815
+ /**
816
+ * How the host that delegated this child wants it GROUPED on screen —
817
+ * a shared label over a set of related delegations, typically one
818
+ * operator-visible piece of work several children are doing together.
819
+ *
820
+ * These fields are display annotations only; they do not create
821
+ * dependencies, barriers, or serial execution. Nothing in the kernel
822
+ * reads them: admission, ordering and concurrency come from the
823
+ * scheduler and from {@link planId}/{@link planStepId}, which is the
824
+ * field pair that DOES carry correlation a host may act on. A reader
825
+ * who infers execution structure from a label here has inferred it
826
+ * from a caption.
827
+ *
828
+ * Absent unless the delegating host supplied them, which is the
829
+ * normal case — a host that groups nothing sends nothing, and a
830
+ * consumer written before these existed reads the same event it
831
+ * always did.
832
+ *
833
+ * They ride this event rather than staying in the delegating
834
+ * process's memory for REACH: a consumer watching from outside
835
+ * that process — another listener, or an SSE client — can rebuild
836
+ * the same picture instead of seeing an undifferentiated list of
837
+ * children.
838
+ *
839
+ * Reach is not durability, and this event buys only the first.
840
+ * Like every delegation lifecycle event, it is handed straight to
841
+ * a host's listener and never enters a run's log — which is what
842
+ * the absent `seq` on this variant says, and what the `seq` doc
843
+ * above spells out. A label here is therefore written nowhere by
844
+ * the kernel and does not survive a restart of the host that chose
845
+ * it; a host wanting the grouping to outlive its process records it
846
+ * from the listener.
847
+ */
848
+ workflow?: string
849
+ /**
850
+ * Display group WITHIN {@link workflow} — a stage of that work, as
851
+ * the delegating host labelled it. Display-only on the same terms as
852
+ * {@link workflow}: it creates no dependencies, barriers or serial
853
+ * execution, and two children naming the same phase are not thereby
854
+ * sequenced or synchronised.
855
+ */
856
+ phase?: string
857
+ /**
858
+ * Longer text explaining {@link phase}, for a surface that has room
859
+ * to show it. Display-only on the same terms as {@link workflow}.
860
+ */
861
+ phaseDetail?: string
862
+ /**
863
+ * Where {@link phase} sits in the host's intended DISPLAY order,
864
+ * zero-based. Display-only on the same terms as {@link workflow}: it
865
+ * orders a list on a screen and orders nothing that runs. Children in
866
+ * one phase are expected to carry the same value; a consumer that
867
+ * sees two disagree should keep the first rather than resequence,
868
+ * because nothing here is authoritative enough to arbitrate.
869
+ */
870
+ phaseOrder?: number
815
871
  }
816
872
  | {
817
873
  type: 'agent_completed'
@@ -28,6 +28,7 @@ import type { RunEvidenceScope, RunTextEvidenceSource } from '../../store/eviden
28
28
  * re-keyed per call, it happens once, deliberately, as its own change.
29
29
  */
30
30
 
31
+ import type { RunExecutionStatus } from '../common/index.js'
31
32
  import type { Message } from '../message/index.js'
32
33
  import type { AuditEvent } from './audit.js'
33
34
  import type { Run } from './entity.js'
@@ -103,6 +104,47 @@ export type ToolExecutionRecord =
103
104
  | (CompletedToolRecord & { readonly status: 'completed' })
104
105
  | { readonly toolUseId: string; readonly toolName: string; readonly status: 'started' }
105
106
 
107
+ /**
108
+ * One delegated child run found on disk under its parent's `children/`
109
+ * directory, as {@link import('../../store/run/disk.js').RunDiskStore.listChildren}
110
+ * reports it.
111
+ *
112
+ * A DISCOVERY record, not the child's evidence: every field here comes from
113
+ * the child's `run.json`, and the transcript, message snapshot and report
114
+ * beside it stay on disk until something asks for them. {@link dir} is what
115
+ * that something reads from.
116
+ *
117
+ * Everything the file supplies is optional, because a `run.json` is written
118
+ * by the child's own terminal path and a process killed before it got there
119
+ * leaves a directory whose other evidence is still worth opening. An absent
120
+ * field is "this file did not say", never a zero or an empty string.
121
+ */
122
+ export interface DelegatedChildRun {
123
+ /**
124
+ * The child's run id, taken from the directory name.
125
+ *
126
+ * The location is the fact: `initRun` names the directory after the run
127
+ * it binds, so a `run.json` whose `id` disagrees with its own directory
128
+ * was moved or hand-edited, and the directory is the half that decides
129
+ * where the evidence actually is.
130
+ */
131
+ readonly id: string
132
+ /** The parent run whose `children/` directory holds this one. */
133
+ readonly parentRunId: string
134
+ /** Absolute path to the child's evidence directory. */
135
+ readonly dir: string
136
+ readonly agentId?: string
137
+ readonly agentName?: string
138
+ /** `metadata.config.model` — the model the child was configured with. */
139
+ readonly model?: string
140
+ readonly status?: RunExecutionStatus
141
+ readonly startedAt?: number
142
+ readonly endedAt?: number
143
+ /** `tokenUsage.totalTokens` — this child's own cumulative spend. */
144
+ readonly totalTokens?: number
145
+ readonly depth?: number
146
+ }
147
+
106
148
  /** Absence proves no recorded start only when the whole selected log is complete. */
107
149
  export interface ToolExecutionSnapshot {
108
150
  readonly complete: boolean
@@ -261,6 +261,35 @@ export interface SandboxTcpConnectOptions {
261
261
  readonly host?: '127.0.0.1' | '::1'
262
262
  }
263
263
 
264
+ /**
265
+ * What to read, and how to stop reading it. Every field is optional, so
266
+ * `readFile(path)` and `readFile(path, {})` mean the same thing: the whole
267
+ * file.
268
+ */
269
+ export interface SandboxReadFileOptions {
270
+ /** First byte to read. Defaults to 0. */
271
+ readonly offset?: number
272
+ /**
273
+ * How many bytes to read. Defaults to the rest of the file. A range
274
+ * that runs past the end returns the bytes that exist, not an error —
275
+ * a caller resuming from a remembered offset must be able to ask
276
+ * without knowing the answer first.
277
+ *
278
+ * **A backend may cap how large a single range it will serve**, and
279
+ * one past that cap is REFUSED rather than shortened — a caller that
280
+ * asked for 4 MiB, got 1 MiB and was told nothing would read the short
281
+ * answer as the end of its range. The agent-backed backends cap it at
282
+ * `NAMZU_AGENT_READ_FILE_RANGE_BYTES` (1 MiB by default), because one
283
+ * range is one wire frame there; a provider reading from local disk has
284
+ * no such ceiling. A caller that wants more than a frame's worth in one
285
+ * call iterates {@link Sandbox.readFileStream} instead, which is not
286
+ * capped.
287
+ */
288
+ readonly length?: number
289
+ /** Aborts the read. */
290
+ readonly signal?: AbortSignal
291
+ }
292
+
264
293
  export interface Sandbox {
265
294
  readonly id: SandboxId
266
295
  readonly status: SandboxStatus
@@ -323,7 +352,46 @@ export interface Sandbox {
323
352
  */
324
353
  openTcpConnection?(options: SandboxTcpConnectOptions): Promise<SandboxTcpConnection>
325
354
  writeFile(path: string, content: string | Buffer): Promise<void>
326
- readFile(path: string): Promise<Buffer>
355
+ /**
356
+ * Read a file out of the sandbox.
357
+ *
358
+ * `options` is optional in both directions, which is what keeps this
359
+ * source-compatible: a caller may go on writing `readFile(path)`, and a
360
+ * backend may go on declaring the one-parameter form and still satisfy
361
+ * this signature. A backend that accepts the parameter and IGNORES
362
+ * `offset`/`length` does not — returning the whole file where a slice
363
+ * was asked for is a wrong answer, not a degraded one, so such a
364
+ * backend must reject instead.
365
+ *
366
+ * @param options.offset First byte to read. Defaults to 0.
367
+ * @param options.length How many bytes to read. Defaults to the rest of
368
+ * the file. A range that runs past the end returns the bytes that
369
+ * exist rather than failing.
370
+ * @param options.signal Aborts the read.
371
+ */
372
+ readFile(path: string, options?: SandboxReadFileOptions): Promise<Buffer>
373
+ /**
374
+ * Read a file as a stream of chunks, so neither the sandbox nor this
375
+ * process ever holds the whole of it.
376
+ *
377
+ * Optional, in the same way {@link Sandbox.openTerminal} is: a backend
378
+ * that cannot read a file incrementally must OMIT this rather than
379
+ * implement it by reading the file whole and chopping the result up,
380
+ * which would give a caller the bounded-memory behaviour it asked for in
381
+ * name only. A caller that needs the bound therefore refuses an absent
382
+ * method rather than falling back to {@link Sandbox.readFile}.
383
+ *
384
+ * Chunk boundaries are not part of the contract — only the order and
385
+ * the concatenation are. Aborting `options.signal`, or leaving the loop
386
+ * early, must stop the transfer and release whatever the sandbox opened
387
+ * for it.
388
+ *
389
+ * Hosts that drain agent-produced output files before {@link destroy}
390
+ * (see {@link listFiles}) are the reason this exists: those files are
391
+ * routinely tens to hundreds of megabytes, and a whole-file read of one
392
+ * of them costs several times its size in the sandbox.
393
+ */
394
+ readFileStream?(path: string, options?: SandboxReadFileOptions): AsyncIterable<Buffer>
327
395
  /**
328
396
  * Recursively enumerate regular files under `rootPath`. Directories,
329
397
  * symlinks, sockets, and other non-regular entries are skipped.
@@ -469,6 +469,26 @@ export interface ToolContext {
469
469
  */
470
470
  maxToolOutputChars?: number
471
471
 
472
+ /**
473
+ * Screens the RUN asked for, applied to results this call produces.
474
+ *
475
+ * Worth having because a run usually does not build its registry: a host
476
+ * assembles one and hands it to `runAgent`, so a registry-construction
477
+ * option alone is the host's to write and the kernel's default reaches
478
+ * nobody.
479
+ *
480
+ * The registry's own {@link ToolRegistryConfig.resultGuardrails} WIN when
481
+ * the registry was built with them — including an empty array, which means
482
+ * none — because a registry that stated its policy has stated it. These
483
+ * apply to a registry that declared none, which is the ordinary case: a
484
+ * host assembles a registry and hands it to a run it does not own.
485
+ *
486
+ * `undefined` means the run declared none; an empty array means the run
487
+ * declared none ON PURPOSE, which is how a caller turns off a screen the
488
+ * executor would otherwise install by default.
489
+ */
490
+ toolResultGuardrails?: readonly ToolResultGuardrailSpec[]
491
+
472
492
  /**
473
493
  * Run another tool through the same dispatch this call came through.
474
494
  *