@theokit/sdk 4.54.0 → 4.56.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 +159 -0
- package/dist/a2a/index.cjs +13 -4
- package/dist/a2a/index.cjs.map +1 -1
- package/dist/a2a/index.d.cts +1 -1
- package/dist/a2a/index.d.ts +1 -1
- package/dist/a2a/index.js +13 -5
- package/dist/a2a/index.js.map +1 -1
- package/dist/a2a/message-bus.d.cts +33 -4
- package/dist/a2a/message-bus.d.ts +33 -4
- package/dist/{agent-CIUgz7cN.d.cts → agent-D3Xr_-6Z.d.cts} +61 -6
- package/dist/{agent-DSec-E0c.d.ts → agent-DIu6FooJ.d.ts} +61 -6
- package/dist/{agent-VGD5WL4N.js → agent-K3PQBS7D.js} +10 -9
- package/dist/{agent-VGD5WL4N.js.map → agent-K3PQBS7D.js.map} +1 -1
- package/dist/{agent-NOEGF4GI.cjs → agent-PJMBK7HQ.cjs} +11 -10
- package/dist/{agent-NOEGF4GI.cjs.map → agent-PJMBK7HQ.cjs.map} +1 -1
- package/dist/{chunk-SSQZA3DZ.js → chunk-2BDH744Z.js} +3 -3
- package/dist/{chunk-SSQZA3DZ.js.map → chunk-2BDH744Z.js.map} +1 -1
- package/dist/chunk-6HTXPPHK.cjs +18 -0
- package/dist/{chunk-3KGLRRFC.cjs.map → chunk-6HTXPPHK.cjs.map} +1 -1
- package/dist/{chunk-5UOVYM3P.cjs → chunk-6VLKVX7O.cjs} +131 -54
- package/dist/chunk-6VLKVX7O.cjs.map +1 -0
- package/dist/{chunk-5PHVENFV.js → chunk-7FHZ4VQX.js} +3 -55
- package/dist/chunk-7FHZ4VQX.js.map +1 -0
- package/dist/{chunk-Q47R5E2X.cjs → chunk-E3WZ6Y4H.cjs} +7 -59
- package/dist/chunk-E3WZ6Y4H.cjs.map +1 -0
- package/dist/{chunk-TTHBHAJI.cjs → chunk-H5GOSXSC.cjs} +4 -4
- package/dist/{chunk-TTHBHAJI.cjs.map → chunk-H5GOSXSC.cjs.map} +1 -1
- package/dist/{chunk-UNDROG5N.cjs → chunk-HLPSLDGL.cjs} +94 -26
- package/dist/chunk-HLPSLDGL.cjs.map +1 -0
- package/dist/{chunk-TPTZA6NI.js → chunk-KBXWEWKS.js} +70 -29
- package/dist/chunk-KBXWEWKS.js.map +1 -0
- package/dist/chunk-KRD3GQAA.cjs +71 -0
- package/dist/chunk-KRD3GQAA.cjs.map +1 -0
- package/dist/chunk-KVNWIAO4.js +68 -0
- package/dist/chunk-KVNWIAO4.js.map +1 -0
- package/dist/{chunk-UFAO4T7Z.cjs → chunk-LQYQHXIW.cjs} +129 -88
- package/dist/chunk-LQYQHXIW.cjs.map +1 -0
- package/dist/{chunk-AGSBJD2L.js → chunk-M7UHYBEY.js} +3 -3
- package/dist/{chunk-AGSBJD2L.js.map → chunk-M7UHYBEY.js.map} +1 -1
- package/dist/{chunk-VDEWG5TV.js → chunk-MVAPK2BX.js} +77 -9
- package/dist/chunk-MVAPK2BX.js.map +1 -0
- package/dist/{chunk-RM7Y65IG.cjs → chunk-NIRE5CNO.cjs} +10 -3
- package/dist/{chunk-FXEUP75G.js.map → chunk-NIRE5CNO.cjs.map} +1 -1
- package/dist/{chunk-DAPSQZT4.js → chunk-ODTZ7HX3.js} +131 -54
- package/dist/chunk-ODTZ7HX3.js.map +1 -0
- package/dist/{chunk-DUIF54UP.js → chunk-OHBIUXKM.js} +3 -3
- package/dist/{chunk-DUIF54UP.js.map → chunk-OHBIUXKM.js.map} +1 -1
- package/dist/{chunk-FXEUP75G.js → chunk-Q4CMI2LP.js} +9 -2
- package/dist/chunk-Q4CMI2LP.js.map +1 -0
- package/dist/{chunk-5BJV5UPY.cjs → chunk-V2UUGUY4.cjs} +3 -3
- package/dist/{chunk-5BJV5UPY.cjs.map → chunk-V2UUGUY4.cjs.map} +1 -1
- package/dist/{compact-session-K5LXTBPJ.js → compact-session-FUJDVF7B.js} +4 -4
- package/dist/{compact-session-K5LXTBPJ.js.map → compact-session-FUJDVF7B.js.map} +1 -1
- package/dist/{compact-session-YCT6JMBX.cjs → compact-session-LEWF554G.cjs} +12 -12
- package/dist/{compact-session-YCT6JMBX.cjs.map → compact-session-LEWF554G.cjs.map} +1 -1
- package/dist/context/index.cjs +6 -5
- package/dist/context/index.cjs.map +1 -1
- package/dist/context/index.js +3 -2
- package/dist/context/index.js.map +1 -1
- package/dist/{cron-DxxeQ-sK.d.cts → cron-BcWmzWzT.d.cts} +1 -1
- package/dist/{cron-CRwy2JBF.d.ts → cron-De6hzWCF.d.ts} +1 -1
- package/dist/cron.cjs +10 -9
- package/dist/cron.d.cts +2 -2
- package/dist/cron.d.ts +2 -2
- package/dist/cron.js +9 -8
- package/dist/eval.cjs +9 -8
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +8 -7
- package/dist/eval.js.map +1 -1
- package/dist/{index-manager-ZMRJ6ZII.js → index-manager-WBIMDVQT.js} +4 -3
- package/dist/{index-manager-ZMRJ6ZII.js.map → index-manager-WBIMDVQT.js.map} +1 -1
- package/dist/{index-manager-NG5YENWO.cjs → index-manager-WC5ZVJWO.cjs} +5 -4
- package/dist/{index-manager-NG5YENWO.cjs.map → index-manager-WC5ZVJWO.cjs.map} +1 -1
- package/dist/index.cjs +47 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +12 -11
- package/dist/index.js.map +1 -1
- package/dist/{inject-session-DDR6X6PC.js → inject-session-BJMJH5BX.js} +3 -3
- package/dist/{inject-session-DDR6X6PC.js.map → inject-session-BJMJH5BX.js.map} +1 -1
- package/dist/{inject-session-XLO3KTBM.cjs → inject-session-WQGGMCQY.cjs} +4 -4
- package/dist/{inject-session-XLO3KTBM.cjs.map → inject-session-WQGGMCQY.cjs.map} +1 -1
- package/dist/internal/llm/prompt-cache-key.d.ts +1 -0
- package/dist/internal/llm/responses.d.ts +67 -1
- package/dist/internal/llm/types.d.ts +15 -0
- package/dist/internal/local-agent/real-local-run-tools.d.ts +17 -6
- package/dist/internal/memory/storage/markdown-store.d.ts +14 -2
- package/dist/internal/memory/storage/memory-file.d.ts +54 -0
- package/dist/internal/memory/types.d.ts +28 -0
- package/dist/models.cjs +9 -9
- package/dist/models.js +1 -1
- package/dist/providers.cjs +4 -4
- package/dist/providers.js +2 -2
- package/dist/sandbox/index.cjs +1 -1
- package/dist/sandbox/index.cjs.map +1 -1
- package/dist/sandbox/index.js +1 -1
- package/dist/sandbox/index.js.map +1 -1
- package/dist/subagents-loader.d.cts +1 -1
- package/dist/subagents-loader.d.ts +1 -1
- package/dist/types/agent.d.ts +47 -5
- package/dist/types/provider-profile.d.ts +13 -0
- package/docs/error-codes.md +22 -20
- package/docs/harness-capability-map.md +3 -1
- package/package.json +1 -1
- package/dist/chunk-3KGLRRFC.cjs +0 -18
- package/dist/chunk-5PHVENFV.js.map +0 -1
- package/dist/chunk-5UOVYM3P.cjs.map +0 -1
- package/dist/chunk-DAPSQZT4.js.map +0 -1
- package/dist/chunk-Q47R5E2X.cjs.map +0 -1
- package/dist/chunk-RM7Y65IG.cjs.map +0 -1
- package/dist/chunk-TPTZA6NI.js.map +0 -1
- package/dist/chunk-UFAO4T7Z.cjs.map +0 -1
- package/dist/chunk-UNDROG5N.cjs.map +0 -1
- package/dist/chunk-VDEWG5TV.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,164 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.56.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- b08f696: `MessageBus.request` now rejects a timeout with `A2ARequestTimeoutError`, carrying
|
|
8
|
+
`code: "a2a_request_timeout"` plus the peer's address and the limit as fields.
|
|
9
|
+
|
|
10
|
+
It used to reject with a plain `Error` and no code, so the only way to identify a timeout was to
|
|
11
|
+
match the message — the practice `docs/error-codes.md` tells consumers never to rely on, and that
|
|
12
|
+
message embeds the address and the limit, so it changes with context exactly as the document warns.
|
|
13
|
+
|
|
14
|
+
The distinction this restores is what a retry policy is built on: a peer that did not answer is
|
|
15
|
+
transient and worth retrying, a peer whose handler threw is likely deterministic. A handler's own
|
|
16
|
+
error still propagates unchanged and is not this type.
|
|
17
|
+
|
|
18
|
+
- f7e70e4: The memory store now writes the layout the Claude Code CLI reads.
|
|
19
|
+
|
|
20
|
+
This SDK's differentiator is that it emits the formats that CLI opens — point `local.sessionDir` at
|
|
21
|
+
`~/.claude` and `--continue` a session your agent wrote. Memory did not hold that line: a fact was a
|
|
22
|
+
bullet under `## Facts`, so pointing a memory directory at `~/.claude/projects/<project>/memory/`
|
|
23
|
+
produced nothing the CLI could read.
|
|
24
|
+
|
|
25
|
+
Now each memory is its own file with the frontmatter Claude Code writes — `name`, `description`, and
|
|
26
|
+
`metadata` carrying `type` and an ISO 8601 `modified` — and `MEMORY.md` is the index that points at
|
|
27
|
+
them.
|
|
28
|
+
|
|
29
|
+
Legacy `## Facts` bullets are still read, so no store loses what it recorded. The brief encoding that
|
|
30
|
+
put a fact's kind in a trailing HTML comment never reached a published version, so there is nothing
|
|
31
|
+
to migrate from it.
|
|
32
|
+
|
|
33
|
+
`parseSimpleYaml` also stops flattening nested maps: `metadata:` with indented keys used to yield
|
|
34
|
+
`metadata: []` plus the nested keys as top-level entries, so `metadata.type` read as `undefined`
|
|
35
|
+
while `type` appeared where it never was.
|
|
36
|
+
|
|
37
|
+
- 5036f04: A memory fact can now say what it IS and when it was learned.
|
|
38
|
+
|
|
39
|
+
`MemoryFact` gains an optional `kind` — `user`, `feedback`, `project` or `reference` — and a
|
|
40
|
+
`modified` timestamp. Without them a durable preference and a project note that went stale were
|
|
41
|
+
indistinguishable: no staleness signal, no way for recall to filter, no basis for selective
|
|
42
|
+
retention, and no way for a surface to separate "what I remember about you" from "what I know about
|
|
43
|
+
this project".
|
|
44
|
+
|
|
45
|
+
Additive, so existing stores keep working. A hand-written bullet under `## Facts` still parses and
|
|
46
|
+
stays untyped — a kind is never inferred, because a wrong one makes recall confident about the wrong
|
|
47
|
+
thing. `modified` is stamped by the SDK and ignored when supplied by a caller: a timestamp a caller
|
|
48
|
+
can set is one that can lie about when something was learned.
|
|
49
|
+
|
|
50
|
+
### Patch Changes
|
|
51
|
+
|
|
52
|
+
- 7587c00: A confined command that spawns a child no longer loses its output.
|
|
53
|
+
|
|
54
|
+
The restricted-network seccomp filter denied `getsockname`, `getpeername`, `setsockopt` and
|
|
55
|
+
`getsockopt`. Those four take an already-open fd, and cBPF cannot dereference one to learn its
|
|
56
|
+
address family — so they were denied on AF_UNIX too, which is what libuv uses for a child's IPC
|
|
57
|
+
channel. Any command that spawned a child died, and the parent's buffered stdout died with it:
|
|
58
|
+
`node --test` returned zero lines through `shell_exec`, and an agent reading test output saw an
|
|
59
|
+
empty string.
|
|
60
|
+
|
|
61
|
+
The four leave the denied set. Everything that takes an address or changes an fd's role —
|
|
62
|
+
`connect`, `bind`, `listen`, `accept`, `accept4`, `sendto`, `sendmmsg`, `recvmmsg`, `shutdown` —
|
|
63
|
+
stays denied, and `socket()` still refuses every family but AF_UNIX. Measured across the fix: an
|
|
64
|
+
AF_INET socket is `EPERM` before and after.
|
|
65
|
+
|
|
66
|
+
## 4.55.0
|
|
67
|
+
|
|
68
|
+
### Minor Changes
|
|
69
|
+
|
|
70
|
+
- 1988b1d: Responses-API requests now carry `prompt_cache_key`, so the provider can reuse the cached prompt
|
|
71
|
+
prefix between rounds instead of re-charging the whole system prompt and tool schema every time.
|
|
72
|
+
|
|
73
|
+
Measured on a consumer product against OpenAI Codex — same provider, same model, same reasoning
|
|
74
|
+
effort, same task — the SDK sent a THIRD of the bytes (24,691 c vs 76,331 c) and paid 2.8x the tokens
|
|
75
|
+
(24,914 vs 9,036). The difference was not what was sent; it was that theirs was cached and ours was
|
|
76
|
+
not, because no key told the provider which prefix to match.
|
|
77
|
+
|
|
78
|
+
The key is derived (SHA-256, truncated, prefixed) from the run's session identity — the id
|
|
79
|
+
`Agent.getOrCreate(sessionId)` keys on — so it is identical across every round of a turn and every
|
|
80
|
+
turn of a session, different for unrelated sessions, and stable across a process restart, while
|
|
81
|
+
disclosing nothing about a caller-chosen session name. Both halves matter: a key that changes per
|
|
82
|
+
round caches nothing, and a key shared between sessions asks the provider to match one conversation's
|
|
83
|
+
prefix against another's.
|
|
84
|
+
|
|
85
|
+
Alongside it, a provider profile may now declare `encryptedReasoning: true`. When it does, the
|
|
86
|
+
request adds `include: ["reasoning.encrypted_content"]` and `reasoning.context: "all_turns"`, and the
|
|
87
|
+
transport replays the ciphertext the provider returned immediately before the tool call it produced,
|
|
88
|
+
so the model does not re-derive its chain of thought on every round. It is off by default and on for
|
|
89
|
+
the builtin `openai-chatgpt` profile: `include` is a documented Responses-API field but
|
|
90
|
+
`reasoning.context` is not, and that endpoint is the one where acceptance was observed rather than
|
|
91
|
+
assumed. Every other provider's request body is unchanged.
|
|
92
|
+
|
|
93
|
+
`store` stays `false`, now as a recorded decision rather than an unexamined default. Codex sends
|
|
94
|
+
`true`; SDK requests routinely carry a consumer's source code and shell output from machines whose
|
|
95
|
+
operator never agreed to server-side retention, and nothing in the caching work needs it — the cache
|
|
96
|
+
key handles the prefix and the encrypted-reasoning carry is precisely the mechanism for keeping
|
|
97
|
+
reasoning without server-side state.
|
|
98
|
+
|
|
99
|
+
Fixes `usetheokit/theokit-sdk#383`.
|
|
100
|
+
|
|
101
|
+
- 63b0831: A local agent can now withhold the SDK's builtin tools from the catalog it declares to the model,
|
|
102
|
+
and a disabled memory store no longer writes a session transcript into the consumer's repository.
|
|
103
|
+
|
|
104
|
+
`AgentOptions.withheldBuiltinTools?: readonly BuiltinToolName[]` names builtins — `shell`,
|
|
105
|
+
`memory_search`, `memory_get` — that this agent must not declare. Absent or empty, every builtin the
|
|
106
|
+
rest of the configuration would register is declared exactly as before, so nothing changes for an
|
|
107
|
+
agent that does not ask.
|
|
108
|
+
|
|
109
|
+
The option exists because denying a tool and never offering it are different things. A consumer
|
|
110
|
+
whose sandbox scope cannot admit `shell` could already refuse the call in a `pre_tool_call` hook, and
|
|
111
|
+
paid for the tool twice anyway: 267 characters of schema in every request of every round, plus a
|
|
112
|
+
round the model can spend discovering a refusal it had no way to anticipate. Withholding removes the
|
|
113
|
+
tool from the catalog, so the model is never shown what it cannot have. Withholding also releases the
|
|
114
|
+
name — a withheld `shell` may be replaced by a custom tool called `shell` without the
|
|
115
|
+
`tool_reserved_name` error, since the reservation exists to prevent a collision that no longer
|
|
116
|
+
exists. Builtins still declared stay reserved.
|
|
117
|
+
|
|
118
|
+
Fixes `usetheokit/theokit-sdk#381`.
|
|
119
|
+
|
|
120
|
+
`memory: { enabled: false }` now suppresses the per-run session transcript at
|
|
121
|
+
`<cwd>/.theokit/memory/sessions/<runId>.md`. It previously did not: that write was gated on the run's
|
|
122
|
+
status and nothing else, so an agent with memory switched off still had the full user prompt and
|
|
123
|
+
assistant reply written into the working directory — someone else's git repository, in the reported
|
|
124
|
+
case. Every other memory surface already honoured the flag, so "memory is off" was true of the
|
|
125
|
+
subsystem apart from the one part of it that creates files. Both writers are covered, the legacy
|
|
126
|
+
call and the `MemoryProvider.recordSessionSummary` port.
|
|
127
|
+
|
|
128
|
+
Leaving `memory` unset is unchanged and still writes, because that file is what
|
|
129
|
+
`memory_search({ corpus: "sessions" })` reads once memory is switched on; treating an absent config
|
|
130
|
+
as off would empty that corpus for consumers who asked for nothing. Writing `enabled: false` is the
|
|
131
|
+
opt-out.
|
|
132
|
+
|
|
133
|
+
So: if you run an agent inside a repository and were adding `.theokit/` to `.gitignore` to keep
|
|
134
|
+
prompts and replies out of it, `memory: { enabled: false }` now stops them being written at all.
|
|
135
|
+
`memory_search({ corpus: "sessions" })` returns nothing for those runs, which is the trade — no
|
|
136
|
+
transcript on disk, nothing to recall from it.
|
|
137
|
+
|
|
138
|
+
Fixes `usetheokit/theokit-sdk#382`.
|
|
139
|
+
|
|
140
|
+
### Patch Changes
|
|
141
|
+
|
|
142
|
+
- a3bdbd1: The Responses transport now reads `input_tokens_details.cached_tokens` and `.cache_write_tokens`,
|
|
143
|
+
so a consumer can tell what a turn actually cost.
|
|
144
|
+
|
|
145
|
+
`input_tokens` INCLUDES the slice the provider served from its prompt cache. This transport reported
|
|
146
|
+
`cacheReadTokens: 0` regardless, so adding input to output counted tokens nobody is paying for.
|
|
147
|
+
Measured on a three-round turn with `prompt_cache_key` in use: the provider reported
|
|
148
|
+
`cached_tokens: 4608` on every round, and the consumer received 9,835 where 619 were new — 16x.
|
|
149
|
+
|
|
150
|
+
The sibling Chat Completions transport has always read the equivalent
|
|
151
|
+
(`prompt_tokens_details.cached_tokens`); this one read `output_tokens_details.reasoning_tokens`
|
|
152
|
+
beside it and skipped this one. The response type declared neither, so it was invisible at the type
|
|
153
|
+
level too.
|
|
154
|
+
|
|
155
|
+
It matters beyond an inaccurate number: it makes the SDK look expensive when it is not. Comparing a
|
|
156
|
+
consumer against OpenAI Codex on identical tasks, the gross figure said 2.8x. Codex reports the net
|
|
157
|
+
figure (`non_cached_input + output`). Measured with the same formula on both sides, the same task
|
|
158
|
+
costs 14,317 against 13,560 — inside the run-to-run variance.
|
|
159
|
+
|
|
160
|
+
Fixes `usetheokit/theokit-sdk#386`.
|
|
161
|
+
|
|
3
162
|
## 4.54.0
|
|
4
163
|
|
|
5
164
|
### Minor Changes
|
package/dist/a2a/index.cjs
CHANGED
|
@@ -35,6 +35,17 @@ var AgentMailbox = class {
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
// src/a2a/message-bus.ts
|
|
38
|
+
var A2ARequestTimeoutError = class extends Error {
|
|
39
|
+
constructor(to, timeoutMs) {
|
|
40
|
+
super(`A2A request timeout: ${to} did not respond within ${timeoutMs}ms`);
|
|
41
|
+
this.to = to;
|
|
42
|
+
this.timeoutMs = timeoutMs;
|
|
43
|
+
this.name = "A2ARequestTimeoutError";
|
|
44
|
+
}
|
|
45
|
+
to;
|
|
46
|
+
timeoutMs;
|
|
47
|
+
code = "a2a_request_timeout";
|
|
48
|
+
};
|
|
38
49
|
var MessageBus = class {
|
|
39
50
|
_handlers = /* @__PURE__ */ new Map();
|
|
40
51
|
register(agentId, handler) {
|
|
@@ -81,10 +92,7 @@ var MessageBus = class {
|
|
|
81
92
|
return await Promise.race([
|
|
82
93
|
Promise.resolve(handler(message)),
|
|
83
94
|
new Promise((_, reject) => {
|
|
84
|
-
timer = setTimeout(
|
|
85
|
-
() => reject(new Error(`A2A request timeout: ${to} did not respond within ${timeoutMs}ms`)),
|
|
86
|
-
timeoutMs
|
|
87
|
-
);
|
|
95
|
+
timer = setTimeout(() => reject(new A2ARequestTimeoutError(to, timeoutMs)), timeoutMs);
|
|
88
96
|
})
|
|
89
97
|
]);
|
|
90
98
|
} finally {
|
|
@@ -107,6 +115,7 @@ Object.defineProperty(exports, "SubAgent", {
|
|
|
107
115
|
enumerable: true,
|
|
108
116
|
get: function () { return chunk4O5TGQBW_cjs.SubAgent; }
|
|
109
117
|
});
|
|
118
|
+
exports.A2ARequestTimeoutError = A2ARequestTimeoutError;
|
|
110
119
|
exports.AgentMailbox = AgentMailbox;
|
|
111
120
|
exports.MessageBus = MessageBus;
|
|
112
121
|
//# sourceMappingURL=index.cjs.map
|
package/dist/a2a/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/a2a/agent-mailbox.ts","../../src/a2a/message-bus.ts"],"names":["diag"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * AgentMailbox — per-agent inbox for A2A communication (T20.1, ADR D453).\n *\n * Wraps MessageBus registration with a convenient API for sending,\n * receiving, and requesting messages.\n *\n * @public\n */\n\nimport type { MessageBus, RequestOptions } from \"./message-bus.js\";\nimport type { A2AMessage, MessageHandler } from \"./types.js\";\n\n/**\n * One agent's endpoint on a {@link MessageBus}: registers `agentId` on\n * construction and forwards inbound messages to the handler installed by\n * `onMessage`.\n *\n * const mailbox = new AgentMailbox(\"worker\", bus);\n * mailbox.onMessage((m) => `echo:${m.payload}`);\n * await mailbox.send(\"boss\", { type: \"ready\", payload: null });\n *\n * Needs an already-constructed `MessageBus` — the mailbox does not create one, and\n * two mailboxes reach each other only through the SAME bus instance.\n *\n * How it fails: `send` and `request` are thin forwards, so they carry the bus's\n * failures unchanged (plain `Error` for an unregistered peer, plus a timeout\n * rejection for `request`).\n *\n * Traps:\n * - The constructor registers IMMEDIATELY, before `onMessage` can be called. A\n * message arriving in that window is dropped silently, and a peer's `request`\n * RESOLVES WITH `undefined` instead of timing out — install the handler in the\n * same tick as construction.\n * - Constructing a second mailbox with the same `agentId` on the same bus takes\n * the id over silently (`MessageBus.register` overwrites), and the loser's\n * `dispose()` then unregisters the WINNER.\n * - `dispose()` only unregisters and clears the handler. Requests already in\n * flight are neither cancelled nor rejected; they time out on the caller's side.\n */\nexport class AgentMailbox {\n readonly agentId: string;\n private readonly _bus: MessageBus;\n private _handler: MessageHandler | null = null;\n\n constructor(agentId: string, bus: MessageBus) {\n this.agentId = agentId;\n this._bus = bus;\n this._bus.register(agentId, (msg) => this._dispatch(msg));\n }\n\n onMessage(handler: MessageHandler): void {\n this._handler = handler;\n }\n\n async send(to: string, partial: { type: string; payload: unknown }): Promise<void> {\n return this._bus.send(this.agentId, to, partial);\n }\n\n async request(\n to: string,\n partial: { type: string; payload: unknown },\n opts?: RequestOptions,\n ): Promise<unknown> {\n return this._bus.request(this.agentId, to, partial, opts);\n }\n\n dispose(): void {\n this._bus.unregister(this.agentId);\n this._handler = null;\n }\n\n private _dispatch(msg: A2AMessage): unknown {\n if (this._handler) {\n return this._handler(msg);\n }\n }\n}\n","/**\n * MessageBus — in-process typed message router for A2A (T20.1, ADR D453).\n *\n * Routes messages between agents by ID. Supports fire-and-forget (send)\n * and request/response (request with timeout).\n *\n * @public\n */\n\nimport { diag } from \"../internal/diagnostics.js\";\nimport type { A2AMessage, MessageHandler } from \"./types.js\";\n\n/**\n * Per-call knobs for {@link MessageBus.request} / `AgentMailbox.request`.\n */\nexport interface RequestOptions {\n /**\n * How long to wait for the peer handler to settle before rejecting.\n * Default `30_000` (30 s). The rejection is a plain `Error` reading\n * `A2A request timeout: <to> did not respond within <n>ms` — there is no typed\n * timeout class and no `code` field, so a caller that must distinguish a\n * timeout from a handler failure has to match on the message.\n */\n timeoutMs?: number;\n}\n\n/**\n * In-process router that delivers A2A messages between agents keyed by string id.\n *\n * Purely in-memory and single-process: nothing is persisted and nothing crosses a\n * process or network boundary. Register one handler per agent id, then `send`\n * (fire-and-forget) or `request` (await the handler's return value).\n *\n * const bus = new MessageBus();\n * bus.register(\"worker\", (m) => `echo:${m.payload}`);\n * const reply = await bus.request(\"boss\", \"worker\", { type: \"ping\", payload: 1 });\n *\n * Callers supply only `{ type, payload }`; the bus stamps `from`, `to`,\n * `timestamp` and `origin` onto the delivered {@link A2AMessage}.\n *\n * How it fails: `send` and `request` both reject with a plain `Error`\n * (`Agent \"<to>\" not registered on MessageBus`) when `to` has no handler, and\n * `request` additionally rejects on timeout. No typed error class is exported for\n * either, so there is nothing to `instanceof`.\n *\n * Traps:\n * - `register` silently OVERWRITES an existing id; the previous handler simply\n * stops receiving anything. Call `has(id)` first when that matters.\n * - `send` is declared `async` but never awaits the handler. A handler that\n * rejects produces an UNHANDLED rejection that `await bus.send(...)` does not\n * observe — only the \"not registered\" failure reaches the caller. Use\n * `request` when the handler's failure has to be visible.\n * - `from` is whatever the caller passes; the bus never checks that the sender\n * is registered. It is self-asserted provenance, not authentication.\n */\nexport class MessageBus {\n private readonly _handlers = new Map<string, MessageHandler>();\n\n register(agentId: string, handler: MessageHandler): void {\n this._handlers.set(agentId, handler);\n }\n\n unregister(agentId: string): void {\n this._handlers.delete(agentId);\n }\n\n async send(from: string, to: string, partial: { type: string; payload: unknown }): Promise<void> {\n const handler = this._handlers.get(to);\n if (!handler) {\n throw new Error(`Agent \"${to}\" not registered on MessageBus`);\n }\n const message: A2AMessage = {\n ...partial,\n from,\n to,\n timestamp: Date.now(),\n // SE3 — provenance projection of the sender address (thin view over `from`).\n origin: { kind: \"peer\", from },\n };\n // Fire-and-forget: the SENDER does not wait for the result, which is the whole point of\n // `send`. It does not mean nobody is told when delivery fails — that is the difference\n // between asynchronous and silent (#365).\n //\n // The returned promise used to be dropped on the floor. `MessageHandler` may return one, so a\n // rejecting handler became an unhandled rejection: fatal under Node's default\n // `--unhandled-rejections=throw`, and invisible to the caller, whose `await send(...)`\n // resolved cleanly either way. Attaching a catch keeps the call non-blocking and reports the\n // failure instead of discarding it (`error-handling.md` § 5).\n void Promise.resolve(handler(message)).catch((cause: unknown) => {\n const reason = cause instanceof Error ? cause.message : String(cause);\n diag(`[theokit-sdk] a2a: handler for \"${to}\" failed on a fire-and-forget send: ${reason}\\n`);\n });\n }\n\n async request(\n from: string,\n to: string,\n partial: { type: string; payload: unknown },\n opts?: RequestOptions,\n ): Promise<unknown> {\n const handler = this._handlers.get(to);\n if (!handler) {\n throw new Error(`Agent \"${to}\" not registered on MessageBus`);\n }\n const timeoutMs = opts?.timeoutMs ?? 30_000;\n const message: A2AMessage = {\n ...partial,\n from,\n to,\n timestamp: Date.now(),\n // SE3 — provenance projection of the sender address (thin view over `from`).\n origin: { kind: \"peer\", from },\n };\n // Hold the timer so it can be cleared once the race settles — otherwise a\n // successful request leaks a live `setTimeout` that keeps the Node event loop\n // alive (the process hangs after the reply). Cleared in `finally`.\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n Promise.resolve(handler(message)),\n new Promise((_, reject) => {\n timer = setTimeout(\n () =>\n reject(new Error(`A2A request timeout: ${to} did not respond within ${timeoutMs}ms`)),\n timeoutMs,\n );\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n }\n\n has(agentId: string): boolean {\n return this._handlers.has(agentId);\n }\n\n listAgents(): string[] {\n return [...this._handlers.keys()];\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/a2a/agent-mailbox.ts","../../src/a2a/message-bus.ts"],"names":["diag"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * AgentMailbox — per-agent inbox for A2A communication (T20.1, ADR D453).\n *\n * Wraps MessageBus registration with a convenient API for sending,\n * receiving, and requesting messages.\n *\n * @public\n */\n\nimport type { MessageBus, RequestOptions } from \"./message-bus.js\";\nimport type { A2AMessage, MessageHandler } from \"./types.js\";\n\n/**\n * One agent's endpoint on a {@link MessageBus}: registers `agentId` on\n * construction and forwards inbound messages to the handler installed by\n * `onMessage`.\n *\n * const mailbox = new AgentMailbox(\"worker\", bus);\n * mailbox.onMessage((m) => `echo:${m.payload}`);\n * await mailbox.send(\"boss\", { type: \"ready\", payload: null });\n *\n * Needs an already-constructed `MessageBus` — the mailbox does not create one, and\n * two mailboxes reach each other only through the SAME bus instance.\n *\n * How it fails: `send` and `request` are thin forwards, so they carry the bus's\n * failures unchanged (plain `Error` for an unregistered peer, plus a timeout\n * rejection for `request`).\n *\n * Traps:\n * - The constructor registers IMMEDIATELY, before `onMessage` can be called. A\n * message arriving in that window is dropped silently, and a peer's `request`\n * RESOLVES WITH `undefined` instead of timing out — install the handler in the\n * same tick as construction.\n * - Constructing a second mailbox with the same `agentId` on the same bus takes\n * the id over silently (`MessageBus.register` overwrites), and the loser's\n * `dispose()` then unregisters the WINNER.\n * - `dispose()` only unregisters and clears the handler. Requests already in\n * flight are neither cancelled nor rejected; they time out on the caller's side.\n */\nexport class AgentMailbox {\n readonly agentId: string;\n private readonly _bus: MessageBus;\n private _handler: MessageHandler | null = null;\n\n constructor(agentId: string, bus: MessageBus) {\n this.agentId = agentId;\n this._bus = bus;\n this._bus.register(agentId, (msg) => this._dispatch(msg));\n }\n\n onMessage(handler: MessageHandler): void {\n this._handler = handler;\n }\n\n async send(to: string, partial: { type: string; payload: unknown }): Promise<void> {\n return this._bus.send(this.agentId, to, partial);\n }\n\n async request(\n to: string,\n partial: { type: string; payload: unknown },\n opts?: RequestOptions,\n ): Promise<unknown> {\n return this._bus.request(this.agentId, to, partial, opts);\n }\n\n dispose(): void {\n this._bus.unregister(this.agentId);\n this._handler = null;\n }\n\n private _dispatch(msg: A2AMessage): unknown {\n if (this._handler) {\n return this._handler(msg);\n }\n }\n}\n","/**\n * MessageBus — in-process typed message router for A2A (T20.1, ADR D453).\n *\n * Routes messages between agents by ID. Supports fire-and-forget (send)\n * and request/response (request with timeout).\n *\n * @public\n */\n\nimport { diag } from \"../internal/diagnostics.js\";\nimport type { A2AMessage, MessageHandler } from \"./types.js\";\n\n/**\n * A peer did not answer a {@link MessageBus.request} within its timeout.\n *\n * Carries `code: \"a2a_request_timeout\"`, the peer's address and the limit as FIELDS, so a caller\n * branches on the contract rather than on prose — `docs/error-codes.md`: \"Branch on `code`, never\n * on the message: messages carry context (an id, a path, a limit) and change with it, while a code\n * is the contract.\" Until #380 this rejection was a plain `Error` with neither, and the message it\n * carried embeds both the address and the limit, so matching on it changed with context exactly as\n * that document warns.\n *\n * The distinction it restores is what a retry policy is built on. A peer that did not answer in\n * time is transient and worth retrying; a peer whose handler threw is likely deterministic and\n * retrying repeats the failure. A handler's own error propagates unchanged and is NOT this type —\n * an unattended agent can therefore tell the two apart without reading English.\n *\n * @public\n */\nexport class A2ARequestTimeoutError extends Error {\n readonly code = \"a2a_request_timeout\" as const;\n constructor(\n /** The peer that did not answer. */\n public readonly to: string,\n /** The limit it exceeded, in milliseconds. */\n public readonly timeoutMs: number,\n ) {\n super(`A2A request timeout: ${to} did not respond within ${timeoutMs}ms`);\n this.name = \"A2ARequestTimeoutError\";\n }\n}\n\n/**\n * Per-call knobs for {@link MessageBus.request} / `AgentMailbox.request`.\n */\nexport interface RequestOptions {\n /**\n * How long to wait for the peer handler to settle before rejecting.\n * Default `30_000` (30 s). The rejection is an {@link A2ARequestTimeoutError} carrying\n * `code: \"a2a_request_timeout\"`, `to` and `timeoutMs` (#380), so a caller distinguishes a\n * timeout from a handler failure by branching on the code — a handler's own error propagates\n * unchanged and is not that type.\n */\n timeoutMs?: number;\n}\n\n/**\n * In-process router that delivers A2A messages between agents keyed by string id.\n *\n * Purely in-memory and single-process: nothing is persisted and nothing crosses a\n * process or network boundary. Register one handler per agent id, then `send`\n * (fire-and-forget) or `request` (await the handler's return value).\n *\n * const bus = new MessageBus();\n * bus.register(\"worker\", (m) => `echo:${m.payload}`);\n * const reply = await bus.request(\"boss\", \"worker\", { type: \"ping\", payload: 1 });\n *\n * Callers supply only `{ type, payload }`; the bus stamps `from`, `to`,\n * `timestamp` and `origin` onto the delivered {@link A2AMessage}.\n *\n * How it fails: `send` and `request` both reject with a plain `Error`\n * (`Agent \"<to>\" not registered on MessageBus`) when `to` has no handler, and\n * `request` additionally rejects on timeout. No typed error class is exported for\n * either, so there is nothing to `instanceof`.\n *\n * Traps:\n * - `register` silently OVERWRITES an existing id; the previous handler simply\n * stops receiving anything. Call `has(id)` first when that matters.\n * - `send` is declared `async` but never awaits the handler. A handler that\n * rejects produces an UNHANDLED rejection that `await bus.send(...)` does not\n * observe — only the \"not registered\" failure reaches the caller. Use\n * `request` when the handler's failure has to be visible.\n * - `from` is whatever the caller passes; the bus never checks that the sender\n * is registered. It is self-asserted provenance, not authentication.\n */\nexport class MessageBus {\n private readonly _handlers = new Map<string, MessageHandler>();\n\n register(agentId: string, handler: MessageHandler): void {\n this._handlers.set(agentId, handler);\n }\n\n unregister(agentId: string): void {\n this._handlers.delete(agentId);\n }\n\n async send(from: string, to: string, partial: { type: string; payload: unknown }): Promise<void> {\n const handler = this._handlers.get(to);\n if (!handler) {\n throw new Error(`Agent \"${to}\" not registered on MessageBus`);\n }\n const message: A2AMessage = {\n ...partial,\n from,\n to,\n timestamp: Date.now(),\n // SE3 — provenance projection of the sender address (thin view over `from`).\n origin: { kind: \"peer\", from },\n };\n // Fire-and-forget: the SENDER does not wait for the result, which is the whole point of\n // `send`. It does not mean nobody is told when delivery fails — that is the difference\n // between asynchronous and silent (#365).\n //\n // The returned promise used to be dropped on the floor. `MessageHandler` may return one, so a\n // rejecting handler became an unhandled rejection: fatal under Node's default\n // `--unhandled-rejections=throw`, and invisible to the caller, whose `await send(...)`\n // resolved cleanly either way. Attaching a catch keeps the call non-blocking and reports the\n // failure instead of discarding it (`error-handling.md` § 5).\n void Promise.resolve(handler(message)).catch((cause: unknown) => {\n const reason = cause instanceof Error ? cause.message : String(cause);\n diag(`[theokit-sdk] a2a: handler for \"${to}\" failed on a fire-and-forget send: ${reason}\\n`);\n });\n }\n\n async request(\n from: string,\n to: string,\n partial: { type: string; payload: unknown },\n opts?: RequestOptions,\n ): Promise<unknown> {\n const handler = this._handlers.get(to);\n if (!handler) {\n throw new Error(`Agent \"${to}\" not registered on MessageBus`);\n }\n const timeoutMs = opts?.timeoutMs ?? 30_000;\n const message: A2AMessage = {\n ...partial,\n from,\n to,\n timestamp: Date.now(),\n // SE3 — provenance projection of the sender address (thin view over `from`).\n origin: { kind: \"peer\", from },\n };\n // Hold the timer so it can be cleared once the race settles — otherwise a\n // successful request leaks a live `setTimeout` that keeps the Node event loop\n // alive (the process hangs after the reply). Cleared in `finally`.\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n Promise.resolve(handler(message)),\n new Promise((_, reject) => {\n timer = setTimeout(() => reject(new A2ARequestTimeoutError(to, timeoutMs)), timeoutMs);\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n }\n\n has(agentId: string): boolean {\n return this._handlers.has(agentId);\n }\n\n listAgents(): string[] {\n return [...this._handlers.keys()];\n }\n}\n"]}
|
package/dist/a2a/index.d.cts
CHANGED
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export type { ToolContextMessage } from "../types/agent-prims.js";
|
|
7
7
|
export { AgentMailbox } from "./agent-mailbox.js";
|
|
8
|
-
export { MessageBus, type RequestOptions } from "./message-bus.js";
|
|
8
|
+
export { A2ARequestTimeoutError, MessageBus, type RequestOptions } from "./message-bus.js";
|
|
9
9
|
export { type DelegationCompleteContext, type DelegationCompleteDecision, type DelegationStartContext, type DelegationStartDecision, MaxDelegationDepthError, type MessageFilterArgs, SubAgent, type SubAgentSpec, } from "./subagent.js";
|
|
10
10
|
export type { A2AMessage, MessageHandler } from "./types.js";
|
package/dist/a2a/index.d.ts
CHANGED
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export type { ToolContextMessage } from "../types/agent-prims.js";
|
|
7
7
|
export { AgentMailbox } from "./agent-mailbox.js";
|
|
8
|
-
export { MessageBus, type RequestOptions } from "./message-bus.js";
|
|
8
|
+
export { A2ARequestTimeoutError, MessageBus, type RequestOptions } from "./message-bus.js";
|
|
9
9
|
export { type DelegationCompleteContext, type DelegationCompleteDecision, type DelegationStartContext, type DelegationStartDecision, MaxDelegationDepthError, type MessageFilterArgs, SubAgent, type SubAgentSpec, } from "./subagent.js";
|
|
10
10
|
export type { A2AMessage, MessageHandler } from "./types.js";
|
package/dist/a2a/index.js
CHANGED
|
@@ -33,6 +33,17 @@ var AgentMailbox = class {
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
// src/a2a/message-bus.ts
|
|
36
|
+
var A2ARequestTimeoutError = class extends Error {
|
|
37
|
+
constructor(to, timeoutMs) {
|
|
38
|
+
super(`A2A request timeout: ${to} did not respond within ${timeoutMs}ms`);
|
|
39
|
+
this.to = to;
|
|
40
|
+
this.timeoutMs = timeoutMs;
|
|
41
|
+
this.name = "A2ARequestTimeoutError";
|
|
42
|
+
}
|
|
43
|
+
to;
|
|
44
|
+
timeoutMs;
|
|
45
|
+
code = "a2a_request_timeout";
|
|
46
|
+
};
|
|
36
47
|
var MessageBus = class {
|
|
37
48
|
_handlers = /* @__PURE__ */ new Map();
|
|
38
49
|
register(agentId, handler) {
|
|
@@ -79,10 +90,7 @@ var MessageBus = class {
|
|
|
79
90
|
return await Promise.race([
|
|
80
91
|
Promise.resolve(handler(message)),
|
|
81
92
|
new Promise((_, reject) => {
|
|
82
|
-
timer = setTimeout(
|
|
83
|
-
() => reject(new Error(`A2A request timeout: ${to} did not respond within ${timeoutMs}ms`)),
|
|
84
|
-
timeoutMs
|
|
85
|
-
);
|
|
93
|
+
timer = setTimeout(() => reject(new A2ARequestTimeoutError(to, timeoutMs)), timeoutMs);
|
|
86
94
|
})
|
|
87
95
|
]);
|
|
88
96
|
} finally {
|
|
@@ -97,6 +105,6 @@ var MessageBus = class {
|
|
|
97
105
|
}
|
|
98
106
|
};
|
|
99
107
|
|
|
100
|
-
export { AgentMailbox, MessageBus };
|
|
108
|
+
export { A2ARequestTimeoutError, AgentMailbox, MessageBus };
|
|
101
109
|
//# sourceMappingURL=index.js.map
|
|
102
110
|
//# sourceMappingURL=index.js.map
|
package/dist/a2a/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/a2a/agent-mailbox.ts","../../src/a2a/message-bus.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * AgentMailbox — per-agent inbox for A2A communication (T20.1, ADR D453).\n *\n * Wraps MessageBus registration with a convenient API for sending,\n * receiving, and requesting messages.\n *\n * @public\n */\n\nimport type { MessageBus, RequestOptions } from \"./message-bus.js\";\nimport type { A2AMessage, MessageHandler } from \"./types.js\";\n\n/**\n * One agent's endpoint on a {@link MessageBus}: registers `agentId` on\n * construction and forwards inbound messages to the handler installed by\n * `onMessage`.\n *\n * const mailbox = new AgentMailbox(\"worker\", bus);\n * mailbox.onMessage((m) => `echo:${m.payload}`);\n * await mailbox.send(\"boss\", { type: \"ready\", payload: null });\n *\n * Needs an already-constructed `MessageBus` — the mailbox does not create one, and\n * two mailboxes reach each other only through the SAME bus instance.\n *\n * How it fails: `send` and `request` are thin forwards, so they carry the bus's\n * failures unchanged (plain `Error` for an unregistered peer, plus a timeout\n * rejection for `request`).\n *\n * Traps:\n * - The constructor registers IMMEDIATELY, before `onMessage` can be called. A\n * message arriving in that window is dropped silently, and a peer's `request`\n * RESOLVES WITH `undefined` instead of timing out — install the handler in the\n * same tick as construction.\n * - Constructing a second mailbox with the same `agentId` on the same bus takes\n * the id over silently (`MessageBus.register` overwrites), and the loser's\n * `dispose()` then unregisters the WINNER.\n * - `dispose()` only unregisters and clears the handler. Requests already in\n * flight are neither cancelled nor rejected; they time out on the caller's side.\n */\nexport class AgentMailbox {\n readonly agentId: string;\n private readonly _bus: MessageBus;\n private _handler: MessageHandler | null = null;\n\n constructor(agentId: string, bus: MessageBus) {\n this.agentId = agentId;\n this._bus = bus;\n this._bus.register(agentId, (msg) => this._dispatch(msg));\n }\n\n onMessage(handler: MessageHandler): void {\n this._handler = handler;\n }\n\n async send(to: string, partial: { type: string; payload: unknown }): Promise<void> {\n return this._bus.send(this.agentId, to, partial);\n }\n\n async request(\n to: string,\n partial: { type: string; payload: unknown },\n opts?: RequestOptions,\n ): Promise<unknown> {\n return this._bus.request(this.agentId, to, partial, opts);\n }\n\n dispose(): void {\n this._bus.unregister(this.agentId);\n this._handler = null;\n }\n\n private _dispatch(msg: A2AMessage): unknown {\n if (this._handler) {\n return this._handler(msg);\n }\n }\n}\n","/**\n * MessageBus — in-process typed message router for A2A (T20.1, ADR D453).\n *\n * Routes messages between agents by ID. Supports fire-and-forget (send)\n * and request/response (request with timeout).\n *\n * @public\n */\n\nimport { diag } from \"../internal/diagnostics.js\";\nimport type { A2AMessage, MessageHandler } from \"./types.js\";\n\n/**\n * Per-call knobs for {@link MessageBus.request} / `AgentMailbox.request`.\n */\nexport interface RequestOptions {\n /**\n * How long to wait for the peer handler to settle before rejecting.\n * Default `30_000` (30 s). The rejection is a plain `Error` reading\n * `A2A request timeout: <to> did not respond within <n>ms` — there is no typed\n * timeout class and no `code` field, so a caller that must distinguish a\n * timeout from a handler failure has to match on the message.\n */\n timeoutMs?: number;\n}\n\n/**\n * In-process router that delivers A2A messages between agents keyed by string id.\n *\n * Purely in-memory and single-process: nothing is persisted and nothing crosses a\n * process or network boundary. Register one handler per agent id, then `send`\n * (fire-and-forget) or `request` (await the handler's return value).\n *\n * const bus = new MessageBus();\n * bus.register(\"worker\", (m) => `echo:${m.payload}`);\n * const reply = await bus.request(\"boss\", \"worker\", { type: \"ping\", payload: 1 });\n *\n * Callers supply only `{ type, payload }`; the bus stamps `from`, `to`,\n * `timestamp` and `origin` onto the delivered {@link A2AMessage}.\n *\n * How it fails: `send` and `request` both reject with a plain `Error`\n * (`Agent \"<to>\" not registered on MessageBus`) when `to` has no handler, and\n * `request` additionally rejects on timeout. No typed error class is exported for\n * either, so there is nothing to `instanceof`.\n *\n * Traps:\n * - `register` silently OVERWRITES an existing id; the previous handler simply\n * stops receiving anything. Call `has(id)` first when that matters.\n * - `send` is declared `async` but never awaits the handler. A handler that\n * rejects produces an UNHANDLED rejection that `await bus.send(...)` does not\n * observe — only the \"not registered\" failure reaches the caller. Use\n * `request` when the handler's failure has to be visible.\n * - `from` is whatever the caller passes; the bus never checks that the sender\n * is registered. It is self-asserted provenance, not authentication.\n */\nexport class MessageBus {\n private readonly _handlers = new Map<string, MessageHandler>();\n\n register(agentId: string, handler: MessageHandler): void {\n this._handlers.set(agentId, handler);\n }\n\n unregister(agentId: string): void {\n this._handlers.delete(agentId);\n }\n\n async send(from: string, to: string, partial: { type: string; payload: unknown }): Promise<void> {\n const handler = this._handlers.get(to);\n if (!handler) {\n throw new Error(`Agent \"${to}\" not registered on MessageBus`);\n }\n const message: A2AMessage = {\n ...partial,\n from,\n to,\n timestamp: Date.now(),\n // SE3 — provenance projection of the sender address (thin view over `from`).\n origin: { kind: \"peer\", from },\n };\n // Fire-and-forget: the SENDER does not wait for the result, which is the whole point of\n // `send`. It does not mean nobody is told when delivery fails — that is the difference\n // between asynchronous and silent (#365).\n //\n // The returned promise used to be dropped on the floor. `MessageHandler` may return one, so a\n // rejecting handler became an unhandled rejection: fatal under Node's default\n // `--unhandled-rejections=throw`, and invisible to the caller, whose `await send(...)`\n // resolved cleanly either way. Attaching a catch keeps the call non-blocking and reports the\n // failure instead of discarding it (`error-handling.md` § 5).\n void Promise.resolve(handler(message)).catch((cause: unknown) => {\n const reason = cause instanceof Error ? cause.message : String(cause);\n diag(`[theokit-sdk] a2a: handler for \"${to}\" failed on a fire-and-forget send: ${reason}\\n`);\n });\n }\n\n async request(\n from: string,\n to: string,\n partial: { type: string; payload: unknown },\n opts?: RequestOptions,\n ): Promise<unknown> {\n const handler = this._handlers.get(to);\n if (!handler) {\n throw new Error(`Agent \"${to}\" not registered on MessageBus`);\n }\n const timeoutMs = opts?.timeoutMs ?? 30_000;\n const message: A2AMessage = {\n ...partial,\n from,\n to,\n timestamp: Date.now(),\n // SE3 — provenance projection of the sender address (thin view over `from`).\n origin: { kind: \"peer\", from },\n };\n // Hold the timer so it can be cleared once the race settles — otherwise a\n // successful request leaks a live `setTimeout` that keeps the Node event loop\n // alive (the process hangs after the reply). Cleared in `finally`.\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n Promise.resolve(handler(message)),\n new Promise((_, reject) => {\n timer = setTimeout(\n () =>\n reject(new Error(`A2A request timeout: ${to} did not respond within ${timeoutMs}ms`)),\n timeoutMs,\n );\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n }\n\n has(agentId: string): boolean {\n return this._handlers.has(agentId);\n }\n\n listAgents(): string[] {\n return [...this._handlers.keys()];\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/a2a/agent-mailbox.ts","../../src/a2a/message-bus.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * AgentMailbox — per-agent inbox for A2A communication (T20.1, ADR D453).\n *\n * Wraps MessageBus registration with a convenient API for sending,\n * receiving, and requesting messages.\n *\n * @public\n */\n\nimport type { MessageBus, RequestOptions } from \"./message-bus.js\";\nimport type { A2AMessage, MessageHandler } from \"./types.js\";\n\n/**\n * One agent's endpoint on a {@link MessageBus}: registers `agentId` on\n * construction and forwards inbound messages to the handler installed by\n * `onMessage`.\n *\n * const mailbox = new AgentMailbox(\"worker\", bus);\n * mailbox.onMessage((m) => `echo:${m.payload}`);\n * await mailbox.send(\"boss\", { type: \"ready\", payload: null });\n *\n * Needs an already-constructed `MessageBus` — the mailbox does not create one, and\n * two mailboxes reach each other only through the SAME bus instance.\n *\n * How it fails: `send` and `request` are thin forwards, so they carry the bus's\n * failures unchanged (plain `Error` for an unregistered peer, plus a timeout\n * rejection for `request`).\n *\n * Traps:\n * - The constructor registers IMMEDIATELY, before `onMessage` can be called. A\n * message arriving in that window is dropped silently, and a peer's `request`\n * RESOLVES WITH `undefined` instead of timing out — install the handler in the\n * same tick as construction.\n * - Constructing a second mailbox with the same `agentId` on the same bus takes\n * the id over silently (`MessageBus.register` overwrites), and the loser's\n * `dispose()` then unregisters the WINNER.\n * - `dispose()` only unregisters and clears the handler. Requests already in\n * flight are neither cancelled nor rejected; they time out on the caller's side.\n */\nexport class AgentMailbox {\n readonly agentId: string;\n private readonly _bus: MessageBus;\n private _handler: MessageHandler | null = null;\n\n constructor(agentId: string, bus: MessageBus) {\n this.agentId = agentId;\n this._bus = bus;\n this._bus.register(agentId, (msg) => this._dispatch(msg));\n }\n\n onMessage(handler: MessageHandler): void {\n this._handler = handler;\n }\n\n async send(to: string, partial: { type: string; payload: unknown }): Promise<void> {\n return this._bus.send(this.agentId, to, partial);\n }\n\n async request(\n to: string,\n partial: { type: string; payload: unknown },\n opts?: RequestOptions,\n ): Promise<unknown> {\n return this._bus.request(this.agentId, to, partial, opts);\n }\n\n dispose(): void {\n this._bus.unregister(this.agentId);\n this._handler = null;\n }\n\n private _dispatch(msg: A2AMessage): unknown {\n if (this._handler) {\n return this._handler(msg);\n }\n }\n}\n","/**\n * MessageBus — in-process typed message router for A2A (T20.1, ADR D453).\n *\n * Routes messages between agents by ID. Supports fire-and-forget (send)\n * and request/response (request with timeout).\n *\n * @public\n */\n\nimport { diag } from \"../internal/diagnostics.js\";\nimport type { A2AMessage, MessageHandler } from \"./types.js\";\n\n/**\n * A peer did not answer a {@link MessageBus.request} within its timeout.\n *\n * Carries `code: \"a2a_request_timeout\"`, the peer's address and the limit as FIELDS, so a caller\n * branches on the contract rather than on prose — `docs/error-codes.md`: \"Branch on `code`, never\n * on the message: messages carry context (an id, a path, a limit) and change with it, while a code\n * is the contract.\" Until #380 this rejection was a plain `Error` with neither, and the message it\n * carried embeds both the address and the limit, so matching on it changed with context exactly as\n * that document warns.\n *\n * The distinction it restores is what a retry policy is built on. A peer that did not answer in\n * time is transient and worth retrying; a peer whose handler threw is likely deterministic and\n * retrying repeats the failure. A handler's own error propagates unchanged and is NOT this type —\n * an unattended agent can therefore tell the two apart without reading English.\n *\n * @public\n */\nexport class A2ARequestTimeoutError extends Error {\n readonly code = \"a2a_request_timeout\" as const;\n constructor(\n /** The peer that did not answer. */\n public readonly to: string,\n /** The limit it exceeded, in milliseconds. */\n public readonly timeoutMs: number,\n ) {\n super(`A2A request timeout: ${to} did not respond within ${timeoutMs}ms`);\n this.name = \"A2ARequestTimeoutError\";\n }\n}\n\n/**\n * Per-call knobs for {@link MessageBus.request} / `AgentMailbox.request`.\n */\nexport interface RequestOptions {\n /**\n * How long to wait for the peer handler to settle before rejecting.\n * Default `30_000` (30 s). The rejection is an {@link A2ARequestTimeoutError} carrying\n * `code: \"a2a_request_timeout\"`, `to` and `timeoutMs` (#380), so a caller distinguishes a\n * timeout from a handler failure by branching on the code — a handler's own error propagates\n * unchanged and is not that type.\n */\n timeoutMs?: number;\n}\n\n/**\n * In-process router that delivers A2A messages between agents keyed by string id.\n *\n * Purely in-memory and single-process: nothing is persisted and nothing crosses a\n * process or network boundary. Register one handler per agent id, then `send`\n * (fire-and-forget) or `request` (await the handler's return value).\n *\n * const bus = new MessageBus();\n * bus.register(\"worker\", (m) => `echo:${m.payload}`);\n * const reply = await bus.request(\"boss\", \"worker\", { type: \"ping\", payload: 1 });\n *\n * Callers supply only `{ type, payload }`; the bus stamps `from`, `to`,\n * `timestamp` and `origin` onto the delivered {@link A2AMessage}.\n *\n * How it fails: `send` and `request` both reject with a plain `Error`\n * (`Agent \"<to>\" not registered on MessageBus`) when `to` has no handler, and\n * `request` additionally rejects on timeout. No typed error class is exported for\n * either, so there is nothing to `instanceof`.\n *\n * Traps:\n * - `register` silently OVERWRITES an existing id; the previous handler simply\n * stops receiving anything. Call `has(id)` first when that matters.\n * - `send` is declared `async` but never awaits the handler. A handler that\n * rejects produces an UNHANDLED rejection that `await bus.send(...)` does not\n * observe — only the \"not registered\" failure reaches the caller. Use\n * `request` when the handler's failure has to be visible.\n * - `from` is whatever the caller passes; the bus never checks that the sender\n * is registered. It is self-asserted provenance, not authentication.\n */\nexport class MessageBus {\n private readonly _handlers = new Map<string, MessageHandler>();\n\n register(agentId: string, handler: MessageHandler): void {\n this._handlers.set(agentId, handler);\n }\n\n unregister(agentId: string): void {\n this._handlers.delete(agentId);\n }\n\n async send(from: string, to: string, partial: { type: string; payload: unknown }): Promise<void> {\n const handler = this._handlers.get(to);\n if (!handler) {\n throw new Error(`Agent \"${to}\" not registered on MessageBus`);\n }\n const message: A2AMessage = {\n ...partial,\n from,\n to,\n timestamp: Date.now(),\n // SE3 — provenance projection of the sender address (thin view over `from`).\n origin: { kind: \"peer\", from },\n };\n // Fire-and-forget: the SENDER does not wait for the result, which is the whole point of\n // `send`. It does not mean nobody is told when delivery fails — that is the difference\n // between asynchronous and silent (#365).\n //\n // The returned promise used to be dropped on the floor. `MessageHandler` may return one, so a\n // rejecting handler became an unhandled rejection: fatal under Node's default\n // `--unhandled-rejections=throw`, and invisible to the caller, whose `await send(...)`\n // resolved cleanly either way. Attaching a catch keeps the call non-blocking and reports the\n // failure instead of discarding it (`error-handling.md` § 5).\n void Promise.resolve(handler(message)).catch((cause: unknown) => {\n const reason = cause instanceof Error ? cause.message : String(cause);\n diag(`[theokit-sdk] a2a: handler for \"${to}\" failed on a fire-and-forget send: ${reason}\\n`);\n });\n }\n\n async request(\n from: string,\n to: string,\n partial: { type: string; payload: unknown },\n opts?: RequestOptions,\n ): Promise<unknown> {\n const handler = this._handlers.get(to);\n if (!handler) {\n throw new Error(`Agent \"${to}\" not registered on MessageBus`);\n }\n const timeoutMs = opts?.timeoutMs ?? 30_000;\n const message: A2AMessage = {\n ...partial,\n from,\n to,\n timestamp: Date.now(),\n // SE3 — provenance projection of the sender address (thin view over `from`).\n origin: { kind: \"peer\", from },\n };\n // Hold the timer so it can be cleared once the race settles — otherwise a\n // successful request leaks a live `setTimeout` that keeps the Node event loop\n // alive (the process hangs after the reply). Cleared in `finally`.\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n Promise.resolve(handler(message)),\n new Promise((_, reject) => {\n timer = setTimeout(() => reject(new A2ARequestTimeoutError(to, timeoutMs)), timeoutMs);\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n }\n\n has(agentId: string): boolean {\n return this._handlers.has(agentId);\n }\n\n listAgents(): string[] {\n return [...this._handlers.keys()];\n }\n}\n"]}
|
|
@@ -7,16 +7,45 @@
|
|
|
7
7
|
* @public
|
|
8
8
|
*/
|
|
9
9
|
import type { MessageHandler } from "./types.js";
|
|
10
|
+
/**
|
|
11
|
+
* A peer did not answer a {@link MessageBus.request} within its timeout.
|
|
12
|
+
*
|
|
13
|
+
* Carries `code: "a2a_request_timeout"`, the peer's address and the limit as FIELDS, so a caller
|
|
14
|
+
* branches on the contract rather than on prose — `docs/error-codes.md`: "Branch on `code`, never
|
|
15
|
+
* on the message: messages carry context (an id, a path, a limit) and change with it, while a code
|
|
16
|
+
* is the contract." Until #380 this rejection was a plain `Error` with neither, and the message it
|
|
17
|
+
* carried embeds both the address and the limit, so matching on it changed with context exactly as
|
|
18
|
+
* that document warns.
|
|
19
|
+
*
|
|
20
|
+
* The distinction it restores is what a retry policy is built on. A peer that did not answer in
|
|
21
|
+
* time is transient and worth retrying; a peer whose handler threw is likely deterministic and
|
|
22
|
+
* retrying repeats the failure. A handler's own error propagates unchanged and is NOT this type —
|
|
23
|
+
* an unattended agent can therefore tell the two apart without reading English.
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export declare class A2ARequestTimeoutError extends Error {
|
|
28
|
+
/** The peer that did not answer. */
|
|
29
|
+
readonly to: string;
|
|
30
|
+
/** The limit it exceeded, in milliseconds. */
|
|
31
|
+
readonly timeoutMs: number;
|
|
32
|
+
readonly code: "a2a_request_timeout";
|
|
33
|
+
constructor(
|
|
34
|
+
/** The peer that did not answer. */
|
|
35
|
+
to: string,
|
|
36
|
+
/** The limit it exceeded, in milliseconds. */
|
|
37
|
+
timeoutMs: number);
|
|
38
|
+
}
|
|
10
39
|
/**
|
|
11
40
|
* Per-call knobs for {@link MessageBus.request} / `AgentMailbox.request`.
|
|
12
41
|
*/
|
|
13
42
|
export interface RequestOptions {
|
|
14
43
|
/**
|
|
15
44
|
* How long to wait for the peer handler to settle before rejecting.
|
|
16
|
-
* Default `30_000` (30 s). The rejection is
|
|
17
|
-
* `
|
|
18
|
-
* timeout
|
|
19
|
-
*
|
|
45
|
+
* Default `30_000` (30 s). The rejection is an {@link A2ARequestTimeoutError} carrying
|
|
46
|
+
* `code: "a2a_request_timeout"`, `to` and `timeoutMs` (#380), so a caller distinguishes a
|
|
47
|
+
* timeout from a handler failure by branching on the code — a handler's own error propagates
|
|
48
|
+
* unchanged and is not that type.
|
|
20
49
|
*/
|
|
21
50
|
timeoutMs?: number;
|
|
22
51
|
}
|
|
@@ -7,16 +7,45 @@
|
|
|
7
7
|
* @public
|
|
8
8
|
*/
|
|
9
9
|
import type { MessageHandler } from "./types.js";
|
|
10
|
+
/**
|
|
11
|
+
* A peer did not answer a {@link MessageBus.request} within its timeout.
|
|
12
|
+
*
|
|
13
|
+
* Carries `code: "a2a_request_timeout"`, the peer's address and the limit as FIELDS, so a caller
|
|
14
|
+
* branches on the contract rather than on prose — `docs/error-codes.md`: "Branch on `code`, never
|
|
15
|
+
* on the message: messages carry context (an id, a path, a limit) and change with it, while a code
|
|
16
|
+
* is the contract." Until #380 this rejection was a plain `Error` with neither, and the message it
|
|
17
|
+
* carried embeds both the address and the limit, so matching on it changed with context exactly as
|
|
18
|
+
* that document warns.
|
|
19
|
+
*
|
|
20
|
+
* The distinction it restores is what a retry policy is built on. A peer that did not answer in
|
|
21
|
+
* time is transient and worth retrying; a peer whose handler threw is likely deterministic and
|
|
22
|
+
* retrying repeats the failure. A handler's own error propagates unchanged and is NOT this type —
|
|
23
|
+
* an unattended agent can therefore tell the two apart without reading English.
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export declare class A2ARequestTimeoutError extends Error {
|
|
28
|
+
/** The peer that did not answer. */
|
|
29
|
+
readonly to: string;
|
|
30
|
+
/** The limit it exceeded, in milliseconds. */
|
|
31
|
+
readonly timeoutMs: number;
|
|
32
|
+
readonly code: "a2a_request_timeout";
|
|
33
|
+
constructor(
|
|
34
|
+
/** The peer that did not answer. */
|
|
35
|
+
to: string,
|
|
36
|
+
/** The limit it exceeded, in milliseconds. */
|
|
37
|
+
timeoutMs: number);
|
|
38
|
+
}
|
|
10
39
|
/**
|
|
11
40
|
* Per-call knobs for {@link MessageBus.request} / `AgentMailbox.request`.
|
|
12
41
|
*/
|
|
13
42
|
export interface RequestOptions {
|
|
14
43
|
/**
|
|
15
44
|
* How long to wait for the peer handler to settle before rejecting.
|
|
16
|
-
* Default `30_000` (30 s). The rejection is
|
|
17
|
-
* `
|
|
18
|
-
* timeout
|
|
19
|
-
*
|
|
45
|
+
* Default `30_000` (30 s). The rejection is an {@link A2ARequestTimeoutError} carrying
|
|
46
|
+
* `code: "a2a_request_timeout"`, `to` and `timeoutMs` (#380), so a caller distinguishes a
|
|
47
|
+
* timeout from a handler failure by branching on the code — a handler's own error propagates
|
|
48
|
+
* unchanged and is not that type.
|
|
20
49
|
*/
|
|
21
50
|
timeoutMs?: number;
|
|
22
51
|
}
|
|
@@ -551,6 +551,19 @@ interface ProviderProfile {
|
|
|
551
551
|
* Default off — only enable for routes/models known to leak (e.g. a qwen3-coder profile variant).
|
|
552
552
|
*/
|
|
553
553
|
extractToolCallsFromContent?: boolean;
|
|
554
|
+
/**
|
|
555
|
+
* Opt-in encrypted-reasoning carry for `apiMode: "responses_api"` (usetheokit/theokit-sdk#383).
|
|
556
|
+
* When `true`, the request adds `include: ["reasoning.encrypted_content"]` and
|
|
557
|
+
* `reasoning.context: "all_turns"`, and the transport replays the ciphertext the provider returned
|
|
558
|
+
* so the model does not re-derive its chain of thought on every round of a turn.
|
|
559
|
+
*
|
|
560
|
+
* Default off, and deliberately per-profile rather than per-`apiMode`: `include` is a documented
|
|
561
|
+
* Responses-API field but `reasoning.context` is not, so a provider that validates strictly
|
|
562
|
+
* answers it with `400`. Enable it only for a backend measured to accept both — the builtin
|
|
563
|
+
* `openai-chatgpt` profile is one, because issue #383 captured OpenAI Codex sending exactly these
|
|
564
|
+
* fields to that endpoint. Ignored by every other `apiMode`.
|
|
565
|
+
*/
|
|
566
|
+
encryptedReasoning?: boolean;
|
|
554
567
|
}
|
|
555
568
|
|
|
556
569
|
/**
|
|
@@ -799,6 +812,19 @@ type Plugin = (BasePlugin & {
|
|
|
799
812
|
* @public
|
|
800
813
|
*/
|
|
801
814
|
type SettingSource = "project" | "user" | "team" | "mdm" | "plugins" | "all";
|
|
815
|
+
/**
|
|
816
|
+
* A tool the SDK declares to the model on its own initiative — not one the consumer passed in
|
|
817
|
+
* {@link AgentOptions.tools}, and not one an MCP server exposed.
|
|
818
|
+
*
|
|
819
|
+
* These three names are also the ones the SDK reserves: a custom tool may not claim them. Listing
|
|
820
|
+
* one in {@link AgentOptions.withheldBuiltinTools} both stops it being declared and releases the
|
|
821
|
+
* name, because nothing of the SDK's is occupying it any more.
|
|
822
|
+
*
|
|
823
|
+
* Named for usetheokit/theokit-sdk#381, which is the report that the catalog had no opt-out.
|
|
824
|
+
*
|
|
825
|
+
* @public
|
|
826
|
+
*/
|
|
827
|
+
type BuiltinToolName = "shell" | "memory_search" | "memory_get";
|
|
802
828
|
/**
|
|
803
829
|
* Local agent configuration.
|
|
804
830
|
*
|
|
@@ -809,14 +835,17 @@ type SettingSource = "project" | "user" | "team" | "mdm" | "plugins" | "all";
|
|
|
809
835
|
* an evaluation invalidated this way: the working directory held the benchmark's answer key, and
|
|
810
836
|
* two transcripts show the model citing it. Deny it explicitly if that matters —
|
|
811
837
|
* `{ tool: "shell", action: "deny" }` on a {@link PermissionEngine} rule is terminal under every
|
|
812
|
-
* permission mode, including `bypass`.
|
|
813
|
-
* the model may attempt it and be refused
|
|
838
|
+
* permission mode, including `bypass`. A deny rule still leaves the tool in the advertised
|
|
839
|
+
* catalog, so the model may attempt it and be refused; to keep it out of the catalog entirely,
|
|
840
|
+
* pass `withheldBuiltinTools: ["shell"]` on {@link AgentOptions} (usetheokit/theokit-sdk#381).
|
|
814
841
|
*
|
|
815
842
|
* 2. **Finished runs write a transcript to disk**, at `.theokit/memory/sessions/<runId>.md` under
|
|
816
843
|
* the workspace `cwd`, with the full prompt and reply. This happens with no `memory` config and
|
|
817
|
-
* with `settingSources: []` — it is what `memory_search({ corpus: "sessions" })` reads.
|
|
818
|
-
*
|
|
819
|
-
*
|
|
844
|
+
* with `settingSources: []` — it is what `memory_search({ corpus: "sessions" })` reads. Opt out
|
|
845
|
+
* with `memory: { enabled: false }`, which suppresses the write entirely
|
|
846
|
+
* (usetheokit/theokit-sdk#382). Leaving `memory`
|
|
847
|
+
* unset still writes, so if the workspace is a git repository, add `.theokit/` to `.gitignore`:
|
|
848
|
+
* one report describes a transcript reaching a public repo before it was noticed.
|
|
820
849
|
*
|
|
821
850
|
* @public
|
|
822
851
|
*/
|
|
@@ -1220,6 +1249,32 @@ interface AgentOptions {
|
|
|
1220
1249
|
* See {@link CustomTool}.
|
|
1221
1250
|
*/
|
|
1222
1251
|
tools?: CustomTool[];
|
|
1252
|
+
/**
|
|
1253
|
+
* Builtin tools this agent must NOT declare to the model. Absent or empty ⇒ every builtin the
|
|
1254
|
+
* rest of the configuration would register is declared, exactly as before this option existed.
|
|
1255
|
+
*
|
|
1256
|
+
* WHY WITHHOLDING IS NOT THE SAME AS DENYING. A consumer that cannot allow `shell` — because it
|
|
1257
|
+
* reaches outside their own sandbox scope — can already refuse the call in a `pre_tool_call` hook
|
|
1258
|
+
* or with a {@link PermissionEngine} deny rule. That stops the execution and pays for the offer
|
|
1259
|
+
* twice over: the schema rides in EVERY request of EVERY round (measured at 267 characters for
|
|
1260
|
+
* `shell`, 1,462 for `memory_search` + `memory_get` together — usetheokit/theokit-sdk#381), and
|
|
1261
|
+
* the model can spend a whole round discovering a refusal it had no way to anticipate. Declaring
|
|
1262
|
+
* a tool that is guaranteed to be refused is the wrong shape; withholding removes it from the
|
|
1263
|
+
* catalog, so the model is never offered what it cannot have.
|
|
1264
|
+
*
|
|
1265
|
+
* WITHHOLDING RELEASES THE NAME. `withheldBuiltinTools: ["shell"]` lets {@link AgentOptions.tools}
|
|
1266
|
+
* declare a tool called `shell` without the `tool_reserved_name` error — the reservation exists to
|
|
1267
|
+
* stop a collision with the SDK's own tool, and there is no longer one to collide with. Every
|
|
1268
|
+
* builtin still declared stays reserved.
|
|
1269
|
+
*
|
|
1270
|
+
* This governs DECLARATION, not authorization. A withheld builtin is simply absent from the
|
|
1271
|
+
* catalog: a model that invents the name anyway gets `Unknown tool <name>` (exit 127) rather than
|
|
1272
|
+
* an execution, but nothing here evaluates a policy. Keep the deny rule if you need one that a
|
|
1273
|
+
* per-send `tools` override cannot reopen.
|
|
1274
|
+
*
|
|
1275
|
+
* @public
|
|
1276
|
+
*/
|
|
1277
|
+
withheldBuiltinTools?: readonly BuiltinToolName[];
|
|
1223
1278
|
/**
|
|
1224
1279
|
* SE37 — opt-in reasoning. When `true`, the agent gets a chain-of-thought
|
|
1225
1280
|
* preamble prepended to its system prompt AND the `think` reasoning tool
|
|
@@ -1583,4 +1638,4 @@ interface ListResult<T> {
|
|
|
1583
1638
|
nextCursor?: string;
|
|
1584
1639
|
}
|
|
1585
1640
|
|
|
1586
|
-
export { type
|
|
1641
|
+
export { type SystemPromptMemoryFact as $, type AgentOptions as A, type BudgetTracker as B, type CloudOptions as C, type PluginContext as D, type PostAssistantReplyContext as E, type PostToolCallContext as F, type GetAgentOptions as G, type HookName as H, type InlineSkill as I, type PreToolCallContext as J, type PreUserSendContext as K, type LocalOptions as L, type MemorySettings as M, type PreUserSendResult as N, type ProviderTransform as O, type Plugin as P, type ProviderTransformContext as Q, type RecordSessionSummaryArgs as R, type SystemPromptResolver as S, type SessionLifecycleContext as T, type SessionRecord as U, type SessionStore as V, type SettingSource as W, Skill as X, type SkillsResolver as Y, type SkillsResolverContext as Z, type SystemPromptContext as _, type AgentDefinition as a, type TelemetrySettings as a0, type ToolCallSummary as a1, type ToolResultTransformContext as a2, type TransformContext as a3, type SkillsSettings as b, type ListAgentsOptions as c, type ListResult as d, type SDKAgentInfo as e, type ListRunsOptions as f, type GetRunOptions as g, type AgentOperationOptions as h, type AgentDescription as i, type ProviderProfile as j, type MemoryProvider as k, type PreToolCallDecision as l, type ActiveMemoryPassArgs as m, type ActiveMemoryPassResult as n, type AgentSubagentDescription as o, type AgentToolDescription as p, type BudgetCheck as q, type BudgetTotal as r, type BudgetUsageEvent as s, type BuiltinToolName as t, type CloudEnv as u, type CloudRepo as v, type CreateSkillSpec as w, type MemoryProviderFactory as x, type MemoryProviderHandle as y, type MemoryProviderInitOptions as z };
|