@namzu/sdk 39.0.0 → 41.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.
- package/CHANGELOG.md +328 -0
- package/dist/bridge/a2a/mapper.d.ts.map +1 -1
- package/dist/bridge/a2a/mapper.js +8 -0
- package/dist/bridge/a2a/mapper.js.map +1 -1
- package/dist/bridge/sse/mapper.d.ts.map +1 -1
- package/dist/bridge/sse/mapper.js +11 -0
- package/dist/bridge/sse/mapper.js.map +1 -1
- package/dist/connector/index.d.ts +2 -2
- package/dist/connector/index.d.ts.map +1 -1
- package/dist/connector/index.js +1 -1
- package/dist/connector/index.js.map +1 -1
- package/dist/connector/mcp/adapter.d.ts.map +1 -1
- package/dist/connector/mcp/adapter.js +112 -10
- package/dist/connector/mcp/adapter.js.map +1 -1
- package/dist/connector/mcp/audio-admission.d.ts +17 -0
- package/dist/connector/mcp/audio-admission.d.ts.map +1 -0
- package/dist/connector/mcp/audio-admission.js +171 -0
- package/dist/connector/mcp/audio-admission.js.map +1 -0
- package/dist/connector/mcp/client.d.ts +252 -1
- package/dist/connector/mcp/client.d.ts.map +1 -1
- package/dist/connector/mcp/client.js +611 -39
- package/dist/connector/mcp/client.js.map +1 -1
- package/dist/connector/mcp/envelope.d.ts +91 -0
- package/dist/connector/mcp/envelope.d.ts.map +1 -0
- package/dist/connector/mcp/envelope.js +173 -0
- package/dist/connector/mcp/envelope.js.map +1 -0
- package/dist/connector/mcp/era.d.ts +130 -0
- package/dist/connector/mcp/era.d.ts.map +1 -0
- package/dist/connector/mcp/era.js +304 -0
- package/dist/connector/mcp/era.js.map +1 -0
- package/dist/connector/mcp/errors.d.ts +106 -0
- package/dist/connector/mcp/errors.d.ts.map +1 -0
- package/dist/connector/mcp/errors.js +154 -0
- package/dist/connector/mcp/errors.js.map +1 -0
- package/dist/connector/mcp/http-sse.d.ts +11 -0
- package/dist/connector/mcp/http-sse.d.ts.map +1 -1
- package/dist/connector/mcp/http-sse.js +21 -6
- package/dist/connector/mcp/http-sse.js.map +1 -1
- package/dist/connector/mcp/index.d.ts +7 -0
- package/dist/connector/mcp/index.d.ts.map +1 -1
- package/dist/connector/mcp/index.js +10 -0
- package/dist/connector/mcp/index.js.map +1 -1
- package/dist/connector/mcp/streamable-http.d.ts +83 -0
- package/dist/connector/mcp/streamable-http.d.ts.map +1 -1
- package/dist/connector/mcp/streamable-http.js +177 -11
- package/dist/connector/mcp/streamable-http.js.map +1 -1
- package/dist/connector/mcp/x-mcp-header.d.ts +56 -0
- package/dist/connector/mcp/x-mcp-header.d.ts.map +1 -0
- package/dist/connector/mcp/x-mcp-header.js +254 -0
- package/dist/connector/mcp/x-mcp-header.js.map +1 -0
- package/dist/constants/mcp/index.d.ts +123 -15
- package/dist/constants/mcp/index.d.ts.map +1 -1
- package/dist/constants/mcp/index.js +135 -16
- package/dist/constants/mcp/index.js.map +1 -1
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +23 -0
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/manager/run/persistence.d.ts +8 -0
- package/dist/manager/run/persistence.d.ts.map +1 -1
- package/dist/manager/run/persistence.js +12 -0
- package/dist/manager/run/persistence.js.map +1 -1
- package/dist/prompt/coding-agent-doctrine.d.ts +20 -0
- package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
- package/dist/prompt/coding-agent-doctrine.js +19 -3
- package/dist/prompt/coding-agent-doctrine.js.map +1 -1
- package/dist/prompt/index.d.ts +1 -1
- package/dist/prompt/index.d.ts.map +1 -1
- package/dist/prompt/index.js +1 -1
- package/dist/prompt/index.js.map +1 -1
- package/dist/public-runtime.d.ts +6 -4
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +8 -4
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-tools.d.ts +11 -0
- package/dist/public-tools.d.ts.map +1 -1
- package/dist/public-tools.js +14 -0
- package/dist/public-tools.js.map +1 -1
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +2 -3
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/registry/tool/portable.d.ts +65 -0
- package/dist/registry/tool/portable.d.ts.map +1 -0
- package/dist/registry/tool/portable.js +244 -0
- package/dist/registry/tool/portable.js.map +1 -0
- package/dist/registry/tool/schema.d.ts +32 -5
- package/dist/registry/tool/schema.d.ts.map +1 -1
- package/dist/registry/tool/schema.js +35 -9
- package/dist/registry/tool/schema.js.map +1 -1
- package/dist/registry/toolset/catalog.js +8 -8
- package/dist/registry/toolset/catalog.js.map +1 -1
- package/dist/runtime/jobs/awaited-jobs.d.ts +215 -0
- package/dist/runtime/jobs/awaited-jobs.d.ts.map +1 -0
- package/dist/runtime/jobs/awaited-jobs.js +259 -0
- package/dist/runtime/jobs/awaited-jobs.js.map +1 -0
- package/dist/runtime/jobs/registry.d.ts +33 -2
- package/dist/runtime/jobs/registry.d.ts.map +1 -1
- package/dist/runtime/jobs/registry.js +37 -0
- package/dist/runtime/jobs/registry.js.map +1 -1
- package/dist/runtime/query/executor.d.ts +28 -0
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +39 -1
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/file-evidence-context.d.ts.map +1 -1
- package/dist/runtime/query/file-evidence-context.js +159 -43
- package/dist/runtime/query/file-evidence-context.js.map +1 -1
- package/dist/runtime/query/file-evidence-replay.d.ts +260 -0
- package/dist/runtime/query/file-evidence-replay.d.ts.map +1 -0
- package/dist/runtime/query/file-evidence-replay.js +647 -0
- package/dist/runtime/query/file-evidence-replay.js.map +1 -0
- package/dist/runtime/query/file-evidence-seed.d.ts +50 -0
- package/dist/runtime/query/file-evidence-seed.d.ts.map +1 -0
- package/dist/runtime/query/file-evidence-seed.js +100 -0
- package/dist/runtime/query/file-evidence-seed.js.map +1 -0
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +94 -2
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +87 -9
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +193 -28
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +10 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js +5 -1
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/plugin-hooks.d.ts +14 -0
- package/dist/runtime/query/plugin-hooks.d.ts.map +1 -1
- package/dist/runtime/query/plugin-hooks.js +18 -0
- package/dist/runtime/query/plugin-hooks.js.map +1 -1
- package/dist/runtime/query/repeat-call.d.ts +17 -4
- package/dist/runtime/query/repeat-call.d.ts.map +1 -1
- package/dist/runtime/query/repeat-call.js +26 -19
- package/dist/runtime/query/repeat-call.js.map +1 -1
- package/dist/runtime/query/steering.d.ts +11 -1
- package/dist/runtime/query/steering.d.ts.map +1 -1
- package/dist/runtime/query/steering.js +12 -1
- package/dist/runtime/query/steering.js.map +1 -1
- package/dist/runtime/query/tooling.d.ts +2 -0
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js +1 -0
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/sandbox/provider/local.d.ts.map +1 -1
- package/dist/sandbox/provider/local.js +46 -3
- package/dist/sandbox/provider/local.js.map +1 -1
- package/dist/scheduler/completion-inbox.d.ts +48 -2
- package/dist/scheduler/completion-inbox.d.ts.map +1 -1
- package/dist/scheduler/completion-inbox.js +102 -10
- package/dist/scheduler/completion-inbox.js.map +1 -1
- package/dist/scheduler/local.d.ts.map +1 -1
- package/dist/scheduler/local.js +8 -0
- package/dist/scheduler/local.js.map +1 -1
- package/dist/store/run/disk.d.ts +35 -1
- package/dist/store/run/disk.d.ts.map +1 -1
- package/dist/store/run/disk.js +100 -0
- package/dist/store/run/disk.js.map +1 -1
- package/dist/tools/builtins/bash.d.ts.map +1 -1
- package/dist/tools/builtins/bash.js +4 -10
- package/dist/tools/builtins/bash.js.map +1 -1
- package/dist/tools/builtins/edit-apply.d.ts +126 -0
- package/dist/tools/builtins/edit-apply.d.ts.map +1 -0
- package/dist/tools/builtins/edit-apply.js +360 -0
- package/dist/tools/builtins/edit-apply.js.map +1 -0
- package/dist/tools/builtins/edit.d.ts +143 -1
- package/dist/tools/builtins/edit.d.ts.map +1 -1
- package/dist/tools/builtins/edit.js +37 -219
- package/dist/tools/builtins/edit.js.map +1 -1
- package/dist/tools/builtins/index.d.ts +1 -0
- package/dist/tools/builtins/index.d.ts.map +1 -1
- package/dist/tools/builtins/index.js +9 -3
- package/dist/tools/builtins/index.js.map +1 -1
- package/dist/tools/builtins/job.js +1 -1
- package/dist/tools/builtins/job.js.map +1 -1
- package/dist/tools/builtins/read-file.d.ts +2 -2
- package/dist/tools/builtins/read-file.d.ts.map +1 -1
- package/dist/tools/builtins/read-file.js +50 -65
- package/dist/tools/builtins/read-file.js.map +1 -1
- package/dist/tools/builtins/read-render.d.ts +56 -0
- package/dist/tools/builtins/read-render.d.ts.map +1 -0
- package/dist/tools/builtins/read-render.js +73 -0
- package/dist/tools/builtins/read-render.js.map +1 -0
- package/dist/tools/builtins/wait-for-job-bounds.d.ts +67 -0
- package/dist/tools/builtins/wait-for-job-bounds.d.ts.map +1 -0
- package/dist/tools/builtins/wait-for-job-bounds.js +108 -0
- package/dist/tools/builtins/wait-for-job-bounds.js.map +1 -0
- package/dist/tools/builtins/wait-for-job.d.ts +6 -0
- package/dist/tools/builtins/wait-for-job.d.ts.map +1 -0
- package/dist/tools/builtins/wait-for-job.js +162 -0
- package/dist/tools/builtins/wait-for-job.js.map +1 -0
- package/dist/tools/builtins/write-file.js +5 -0
- package/dist/tools/builtins/write-file.js.map +1 -1
- package/dist/tools/coordinator/index.d.ts.map +1 -1
- package/dist/tools/coordinator/index.js +1 -7
- package/dist/tools/coordinator/index.js.map +1 -1
- package/dist/tools/file-read-tracker.d.ts.map +1 -1
- package/dist/tools/file-read-tracker.js +88 -10
- package/dist/tools/file-read-tracker.js.map +1 -1
- package/dist/types/agent/scheduler.d.ts +20 -0
- package/dist/types/agent/scheduler.d.ts.map +1 -1
- package/dist/types/agent/task.d.ts +20 -0
- package/dist/types/agent/task.d.ts.map +1 -1
- package/dist/types/connector/mcp.d.ts +205 -0
- package/dist/types/connector/mcp.d.ts.map +1 -1
- package/dist/types/message/index.d.ts +1 -1
- package/dist/types/message/index.d.ts.map +1 -1
- package/dist/types/message/index.js +2 -0
- package/dist/types/message/index.js.map +1 -1
- package/dist/types/run/entity.d.ts +13 -0
- package/dist/types/run/entity.d.ts.map +1 -1
- package/dist/types/run/events.d.ts +56 -0
- package/dist/types/run/events.d.ts.map +1 -1
- package/dist/types/run/events.js.map +1 -1
- package/dist/types/run/store.d.ts +41 -0
- package/dist/types/run/store.d.ts.map +1 -1
- package/dist/types/sandbox/index.d.ts +83 -15
- package/dist/types/sandbox/index.d.ts.map +1 -1
- package/dist/types/sandbox/index.js.map +1 -1
- package/dist/types/tool/index.d.ts +109 -0
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/tool/index.js.map +1 -1
- package/dist/utils/env.d.ts +19 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +25 -0
- package/dist/utils/env.js.map +1 -0
- package/package.json +1 -1
- package/src/bridge/a2a/mapper.ts +8 -0
- package/src/bridge/sse/mapper.ts +11 -0
- package/src/connector/index.ts +27 -0
- package/src/connector/mcp/adapter.ts +123 -10
- package/src/connector/mcp/audio-admission.ts +173 -0
- package/src/connector/mcp/client.ts +694 -45
- package/src/connector/mcp/envelope.ts +235 -0
- package/src/connector/mcp/era.ts +400 -0
- package/src/connector/mcp/errors.ts +171 -0
- package/src/connector/mcp/http-sse.ts +23 -6
- package/src/connector/mcp/index.ts +37 -0
- package/src/connector/mcp/streamable-http.ts +199 -11
- package/src/connector/mcp/x-mcp-header.ts +322 -0
- package/src/constants/mcp/index.ts +145 -16
- package/src/manager/agent/lifecycle.ts +29 -0
- package/src/manager/run/persistence.ts +12 -0
- package/src/prompt/coding-agent-doctrine.ts +31 -4
- package/src/prompt/index.ts +1 -0
- package/src/public-runtime.ts +37 -1
- package/src/public-tools.ts +18 -0
- package/src/registry/tool/execute.ts +2 -4
- package/src/registry/tool/portable.ts +264 -0
- package/src/registry/tool/schema.ts +38 -8
- package/src/registry/toolset/catalog.ts +8 -9
- package/src/runtime/jobs/awaited-jobs.ts +271 -0
- package/src/runtime/jobs/registry.ts +50 -0
- package/src/runtime/query/executor.ts +49 -1
- package/src/runtime/query/file-evidence-context.ts +190 -46
- package/src/runtime/query/file-evidence-replay.ts +776 -0
- package/src/runtime/query/file-evidence-seed.ts +126 -0
- package/src/runtime/query/index.ts +104 -2
- package/src/runtime/query/iteration/index.ts +202 -28
- package/src/runtime/query/iteration/phases/context.ts +10 -0
- package/src/runtime/query/iteration/phases/tool-review.ts +4 -0
- package/src/runtime/query/plugin-hooks.ts +20 -0
- package/src/runtime/query/repeat-call.ts +28 -18
- package/src/runtime/query/steering.ts +11 -0
- package/src/runtime/query/tooling.ts +3 -0
- package/src/sandbox/provider/local.ts +45 -2
- package/src/scheduler/completion-inbox.ts +105 -9
- package/src/scheduler/local.ts +8 -0
- package/src/store/run/disk.ts +108 -0
- package/src/tools/builtins/bash.ts +4 -10
- package/src/tools/builtins/edit-apply.ts +456 -0
- package/src/tools/builtins/edit.ts +39 -270
- package/src/tools/builtins/index.ts +9 -3
- package/src/tools/builtins/job.ts +1 -1
- package/src/tools/builtins/read-file.ts +56 -77
- package/src/tools/builtins/read-render.ts +104 -0
- package/src/tools/builtins/wait-for-job-bounds.ts +179 -0
- package/src/tools/builtins/wait-for-job.ts +184 -0
- package/src/tools/builtins/write-file.ts +5 -0
- package/src/tools/coordinator/index.ts +1 -7
- package/src/tools/file-read-tracker.ts +85 -7
- package/src/types/agent/scheduler.ts +21 -0
- package/src/types/agent/task.ts +21 -0
- package/src/types/connector/mcp.ts +205 -1
- package/src/types/message/index.ts +2 -0
- package/src/types/run/entity.ts +14 -0
- package/src/types/run/events.ts +56 -0
- package/src/types/run/store.ts +42 -0
- package/src/types/sandbox/index.ts +84 -15
- package/src/types/tool/index.ts +104 -0
- package/src/utils/env.ts +23 -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
|
-
| {
|
|
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
|
package/src/types/run/entity.ts
CHANGED
|
@@ -123,6 +123,20 @@ export interface Run {
|
|
|
123
123
|
*/
|
|
124
124
|
abandonedTaskIds?: readonly string[]
|
|
125
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Background jobs the model was waiting on that were still running when
|
|
128
|
+
* this run ended.
|
|
129
|
+
*
|
|
130
|
+
* Only jobs `wait_for_job` named: a dev server nobody awaited is not work
|
|
131
|
+
* this run walked away from, it is work it deliberately left behind. The
|
|
132
|
+
* run holds itself open for these, bounded, and names the ones the bound
|
|
133
|
+
* ran out on — the same honesty `abandonedTaskIds` owes for a delegated
|
|
134
|
+
* worker, and with the same limit: naming a job is not stopping it. A
|
|
135
|
+
* run-owned job is still stopped by the run's own teardown; one bound to
|
|
136
|
+
* the host's session keeps running, which is what it was started for.
|
|
137
|
+
*/
|
|
138
|
+
abandonedJobIds?: readonly string[]
|
|
139
|
+
|
|
126
140
|
parentRunId?: RunId
|
|
127
141
|
|
|
128
142
|
depth?: number
|
package/src/types/run/events.ts
CHANGED
|
@@ -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'
|
package/src/types/run/store.ts
CHANGED
|
@@ -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
|
|
@@ -296,22 +325,23 @@ export interface Sandbox {
|
|
|
296
325
|
* Open a real pseudo-terminal whose complete process tree is confined to
|
|
297
326
|
* and owned by this sandbox.
|
|
298
327
|
*
|
|
299
|
-
* Optional, and a backend that cannot provide one must **
|
|
300
|
-
* than hand back a pipe — the same
|
|
301
|
-
*
|
|
302
|
-
* work: bytes would flow, and every
|
|
303
|
-
* take its non-interactive branch. The
|
|
304
|
-
* exits immediately, the progress bar
|
|
305
|
-
* nothing says why.
|
|
328
|
+
* Optional, and a backend that cannot provide one must **omit this
|
|
329
|
+
* method** rather than hand back a pipe — the same skip-if-unavailable
|
|
330
|
+
* rule {@link Sandbox.openTcpConnection} states below, and for a sharper
|
|
331
|
+
* reason. A pipe would appear to work: bytes would flow, and every
|
|
332
|
+
* program that calls `isatty` would take its non-interactive branch. The
|
|
333
|
+
* prompt never appears, the REPL exits immediately, the progress bar
|
|
334
|
+
* prints ten thousand lines, and nothing says why.
|
|
306
335
|
*
|
|
307
|
-
* A backend that
|
|
308
|
-
* await every terminal it returned. Merely starting a host
|
|
309
|
-
* with `rootDir` as its working directory does not
|
|
310
|
-
* confinement or the ownership contract.
|
|
336
|
+
* A backend that DOES implement this method MUST make {@link destroy}
|
|
337
|
+
* kill and await every terminal it returned. Merely starting a host
|
|
338
|
+
* pseudo-terminal with `rootDir` as its working directory does not
|
|
339
|
+
* satisfy either the confinement or the ownership contract.
|
|
311
340
|
*
|
|
312
|
-
* The Firecracker backend satisfies both guarantees by owning the PTY in
|
|
313
|
-
* guest and awaiting its exit before the microVM is released.
|
|
314
|
-
* cannot provide that boundary omit the capability
|
|
341
|
+
* The Firecracker backend satisfies both guarantees by owning the PTY in
|
|
342
|
+
* the guest and awaiting its exit before the microVM is released.
|
|
343
|
+
* Backends that cannot provide that boundary omit the capability, as
|
|
344
|
+
* stated above.
|
|
315
345
|
*/
|
|
316
346
|
openTerminal?(options: OpenTerminalOptions): Promise<TerminalSession>
|
|
317
347
|
/**
|
|
@@ -322,7 +352,46 @@ export interface Sandbox {
|
|
|
322
352
|
*/
|
|
323
353
|
openTcpConnection?(options: SandboxTcpConnectOptions): Promise<SandboxTcpConnection>
|
|
324
354
|
writeFile(path: string, content: string | Buffer): Promise<void>
|
|
325
|
-
|
|
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>
|
|
326
395
|
/**
|
|
327
396
|
* Recursively enumerate regular files under `rootPath`. Directories,
|
|
328
397
|
* symlinks, sockets, and other non-regular entries are skipped.
|
package/src/types/tool/index.ts
CHANGED
|
@@ -113,6 +113,33 @@ export interface BackgroundJobRegistryRef {
|
|
|
113
113
|
}
|
|
114
114
|
kill(id: string): Promise<{ id: string; status: string }>
|
|
115
115
|
list(): readonly { id: string; command: string; status: string }[]
|
|
116
|
+
/**
|
|
117
|
+
* Await this job's exit instead of reading it in a loop; resolves at
|
|
118
|
+
* once for a job that has already stopped. Optional, and added after
|
|
119
|
+
* the rest of this surface: a host implementing this interface directly
|
|
120
|
+
* rather than through `bindOwner` may not have it yet, so `wait_for_job`
|
|
121
|
+
* checks for it and says so rather than assuming every host can wait.
|
|
122
|
+
*/
|
|
123
|
+
waitForExit?(
|
|
124
|
+
id: string,
|
|
125
|
+
opts?: { signal?: AbortSignal },
|
|
126
|
+
): Promise<{
|
|
127
|
+
id: string
|
|
128
|
+
status: string
|
|
129
|
+
exitCode?: number
|
|
130
|
+
}>
|
|
131
|
+
/**
|
|
132
|
+
* Say that the model is waiting on this job, so the run stays open for it
|
|
133
|
+
* when the model stops calling tools.
|
|
134
|
+
*
|
|
135
|
+
* Called by `wait_for_job` and nothing else. The kernel holds a finishing
|
|
136
|
+
* run open — bounded, and for no model tokens — only for a job marked
|
|
137
|
+
* here; a job nobody marked never delays a run, which is what a dev server
|
|
138
|
+
* or a watcher needs. Optional for the reason `waitForExit` is: a host
|
|
139
|
+
* implementing this interface directly may have nowhere to record the
|
|
140
|
+
* intent, and then there is simply no hold.
|
|
141
|
+
*/
|
|
142
|
+
markAwaited?(id: string): void
|
|
116
143
|
}
|
|
117
144
|
|
|
118
145
|
/**
|
|
@@ -138,6 +165,83 @@ export interface FileReadTracker {
|
|
|
138
165
|
* preserves it; different or unknown content clears it. Never infer from a name.
|
|
139
166
|
*/
|
|
140
167
|
writeCallId?(key: string): string | undefined
|
|
168
|
+
/**
|
|
169
|
+
* Optional chain of calls whose bodies compose the current content: the
|
|
170
|
+
* full-body write that started it, then the successful edits applied on
|
|
171
|
+
* top of it, in order.
|
|
172
|
+
*
|
|
173
|
+
* Defined only while at least one edit sits on a witnessed write — exactly
|
|
174
|
+
* when `writeCallId` is not. An edited file's body is no longer the write
|
|
175
|
+
* call's body, and a consumer that knows only `writeCallId` has to keep
|
|
176
|
+
* seeing nothing there rather than a claim that has quietly stopped being
|
|
177
|
+
* true. The chain names INPUTS: reconstructing the body means replaying
|
|
178
|
+
* those calls' visible arguments and checking the result against
|
|
179
|
+
* `fingerprint(key)`, never asserting it.
|
|
180
|
+
*/
|
|
181
|
+
editChain?(key: string): { rootWriteCallId: string; editCallIds: readonly string[] } | undefined
|
|
182
|
+
/**
|
|
183
|
+
* Optional record of a successful edit's resulting content, with the call
|
|
184
|
+
* that produced it.
|
|
185
|
+
*
|
|
186
|
+
* Does everything `recordRead(key, content)` does, and additionally extends
|
|
187
|
+
* the chain when this edit ran against content the ledger already had a
|
|
188
|
+
* fingerprint for and a witnessed write underneath it — the two facts that
|
|
189
|
+
* make the replay reproducible. Missing either, it is an ordinary
|
|
190
|
+
* observation of a body nobody can replay: the fingerprint advances and the
|
|
191
|
+
* chain is cleared. Pass ToolContext.toolUseId only after the edit succeeded.
|
|
192
|
+
*/
|
|
193
|
+
recordEdit?(key: string, content: string, callId: string): void
|
|
194
|
+
/**
|
|
195
|
+
* Optional witness of a read that returned the file WHOLE, with the
|
|
196
|
+
* fingerprint of the rendering it returned.
|
|
197
|
+
*
|
|
198
|
+
* Does everything `recordRead(key, content)` does, and additionally records
|
|
199
|
+
* that the body is visible in `callId`'s receipt — not as text this ledger
|
|
200
|
+
* holds, but as the exact rendering `callId` emitted, so a consumer can
|
|
201
|
+
* check the receipt it can see against `renderedFingerprint` before
|
|
202
|
+
* referencing it. A partial read never calls this: a window proves nothing
|
|
203
|
+
* about the rest of the file. Pass `ToolContext.toolUseId` and the
|
|
204
|
+
* fingerprint of the tool's own output string.
|
|
205
|
+
*
|
|
206
|
+
* The witness is recorded only where no write witness or chain survives the
|
|
207
|
+
* observation, because a write-rooted body is one the model composed and
|
|
208
|
+
* can be replayed through. It is cleared by exactly what clears a write
|
|
209
|
+
* witness — different or unknown content — and additionally by any
|
|
210
|
+
* `recordEdit`, because a read roots no chain: the body it witnesses exists
|
|
211
|
+
* only as a rendering, and nothing may be replayed on top of it.
|
|
212
|
+
*/
|
|
213
|
+
recordFullRead?(key: string, content: string, callId: string, renderedFingerprint: string): void
|
|
214
|
+
/**
|
|
215
|
+
* Optional witness of the full read above: the call whose receipt holds the
|
|
216
|
+
* body, and the fingerprint of what that call emitted.
|
|
217
|
+
*
|
|
218
|
+
* `renderedFingerprint` is deliberately not the body's fingerprint —
|
|
219
|
+
* `fingerprint(key)` is that. It describes the RECEIPT, so a consumer
|
|
220
|
+
* admits the reference only while the receipt it can see is byte-for-byte
|
|
221
|
+
* what the tool returned; an elided, spilled or cleared one is not.
|
|
222
|
+
*
|
|
223
|
+
* The derived work context asks a tracker for `writeCallId` and
|
|
224
|
+
* `fingerprint` before it reads any witness at all — a name alone does not
|
|
225
|
+
* say the ledger is the one execution wrote — so a tracker implementing
|
|
226
|
+
* this pair and neither of those still establishes nothing.
|
|
227
|
+
*/
|
|
228
|
+
readWitness?(key: string): { callId: string; renderedFingerprint: string } | undefined
|
|
229
|
+
/**
|
|
230
|
+
* Optional note that a built-in mutation has just refused this path because
|
|
231
|
+
* the body on disk differs from the fingerprint above.
|
|
232
|
+
*
|
|
233
|
+
* Not an observation. The refusing tool read the disk, but all it reports
|
|
234
|
+
* here is the disagreement — recording the body it found would re-baseline
|
|
235
|
+
* the drift check and admit the very mutation that was refused. An
|
|
236
|
+
* implementation must therefore leave `fingerprint`, `hasRead`,
|
|
237
|
+
* `writeCallId`, `editChain` and `readWitness` exactly as they were, and any
|
|
238
|
+
* later content observation clears the flag. It exists so a consumer that
|
|
239
|
+
* cannot read the filesystem — the derived work context — can stop
|
|
240
|
+
* referencing a body it has been told is stale, without a check of its own.
|
|
241
|
+
*/
|
|
242
|
+
recordDriftObserved?(key: string): void
|
|
243
|
+
/** Whether a refused mutation has reported this path stale since the last observation. */
|
|
244
|
+
driftObserved?(key: string): boolean
|
|
141
245
|
/**
|
|
142
246
|
* Fingerprint of the body captured at the last read, when one was.
|
|
143
247
|
*
|
package/src/utils/env.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A positive whole number of milliseconds from the environment, or the
|
|
3
|
+
* caller's own default.
|
|
4
|
+
*
|
|
5
|
+
* Every bound that can be tuned wants the same three answers, and the third
|
|
6
|
+
* is the one worth sharing: a variable set to `soon`, to `-1` or to nothing
|
|
7
|
+
* at all falls back rather than parsing, because a run must not wait, hold or
|
|
8
|
+
* time out for `NaN`.
|
|
9
|
+
*
|
|
10
|
+
* `process.env` is read on every call, so where it is called decides when the
|
|
11
|
+
* value is sampled — `wait_for_job` fixes its bounds at module load and names
|
|
12
|
+
* them in a tool schema, and the kernel's hold ceiling asks per hold. That
|
|
13
|
+
* choice is why this lives here rather than being imported from the tool: the
|
|
14
|
+
* kernel reaching into `wait_for_job` for the parse would pull the tool's
|
|
15
|
+
* module-load sampling into the runtime's own graph, and move when the
|
|
16
|
+
* `NAMZU_JOB_WAIT_*` bounds are read.
|
|
17
|
+
*/
|
|
18
|
+
export function readPositiveIntEnv(key: string, fallback: number): number {
|
|
19
|
+
const value = process.env[key]?.trim()
|
|
20
|
+
if (!value) return fallback
|
|
21
|
+
const parsed = Number(value)
|
|
22
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback
|
|
23
|
+
}
|