@theokit/agents 10.0.0 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +324 -0
  2. package/LICENSE +2 -2
  3. package/README.md +6 -5
  4. package/dist/{agent-compiler-CIPQkehU.d.ts → agent-compiler-tetgj6zR.d.ts} +3 -172
  5. package/dist/{agent-handle-Dgi4ZGbg.d.ts → agent-handle-rEWdERuv.d.ts} +113 -2
  6. package/dist/auth.js +1 -1
  7. package/dist/{bridge-entry-emr2PSXC.d.ts → bridge-entry-DRAzQ7UA.d.ts} +32 -200
  8. package/dist/bridge.d.ts +7 -6
  9. package/dist/bridge.js +3 -3
  10. package/dist/{chunk-CKRM5Q2K.js → chunk-4EHZG6KN.js} +122 -16
  11. package/dist/chunk-4EHZG6KN.js.map +1 -0
  12. package/dist/{chunk-M6HMASZC.js → chunk-7PNUTDBQ.js} +109 -14
  13. package/dist/chunk-7PNUTDBQ.js.map +1 -0
  14. package/dist/{chunk-QXGSF6WX.js → chunk-D2EFYZBV.js} +1 -1
  15. package/dist/{chunk-QXGSF6WX.js.map → chunk-D2EFYZBV.js.map} +1 -1
  16. package/dist/{chunk-4VHCH6IZ.js → chunk-LLIERPF3.js} +14 -1
  17. package/dist/chunk-LLIERPF3.js.map +1 -0
  18. package/dist/{chunk-QJN2LLPF.js → chunk-T5MBTKA2.js} +275 -164
  19. package/dist/chunk-T5MBTKA2.js.map +1 -0
  20. package/dist/client-react.d.ts +24 -2
  21. package/dist/client-react.js +2 -1
  22. package/dist/client-react.js.map +1 -1
  23. package/dist/client.d.ts +99 -5
  24. package/dist/client.js +3 -1
  25. package/dist/config.d.ts +2 -2
  26. package/dist/config.js +2 -2
  27. package/dist/{define-agent-BO5QSjV8.d.ts → define-agent-BnH1MBxs.d.ts} +16 -1
  28. package/dist/{delegation-scoring-CDvtrYKd.d.ts → delegation-scoring-CQtF2Zaf.d.ts} +345 -11
  29. package/dist/hooks.js +2 -2
  30. package/dist/hooks.js.map +1 -1
  31. package/dist/index.d.ts +22 -9
  32. package/dist/index.js +8 -3
  33. package/dist/index.js.map +1 -1
  34. package/dist/mcp-health.d.ts +66 -1
  35. package/dist/mcp-health.js +32 -1
  36. package/dist/mcp-health.js.map +1 -1
  37. package/dist/pty.js.map +1 -1
  38. package/dist/session.d.ts +75 -1
  39. package/dist/session.js +43 -4
  40. package/dist/session.js.map +1 -1
  41. package/dist/testing.d.ts +3 -2
  42. package/dist/testing.js +1 -1
  43. package/dist/tools.d.ts +4 -2
  44. package/dist/tools.js +4 -4
  45. package/dist/tools.js.map +1 -1
  46. package/dist/types-C16Wuh9E.d.ts +173 -0
  47. package/package.json +23 -10
  48. package/dist/chunk-4VHCH6IZ.js.map +0 -1
  49. package/dist/chunk-CKRM5Q2K.js.map +0 -1
  50. package/dist/chunk-M6HMASZC.js.map +0 -1
  51. package/dist/chunk-QJN2LLPF.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,329 @@
1
1
  # @theokit/agents
2
2
 
3
+ ## 11.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - bbdfc15: The server's raw error text no longer reaches the browser by default.
8
+
9
+ Every failure the framework reported to a browser carried the server's own words: a tool handler's
10
+ stderr verbatim in `tool-output-error.errorText`, a run failure's message verbatim in
11
+ `error.errorText` — whatever a driver, an HTTP client or a filesystem call put in the exception.
12
+ `ai@7`, speaking the same UIMessage protocol, masks by default and says why in its own comment:
13
+ "prevent leaking server error details to the client by default". There was no equivalent here, and
14
+ no seam to add one.
15
+
16
+ Both are masked now, through one `onError` hook on the serving boundary
17
+ (`streamAgentUIMessages`, `streamAgentTurnInProcess`, and `mountAgent` by pass-through), defaulting
18
+ to a fixed string. The full text is not lost: it still reaches the server's logs and the
19
+ `agent.run` span, and the hook receives it — what stops is it reaching a browser unless the host
20
+ decides otherwise.
21
+
22
+ **A tool's error text masks by the same default as a run's**, which the report that raised this
23
+ deliberately left open. The deciding fact is that masking costs the model nothing: the presenter is
24
+ downstream of the SDK loop, observing events the model has already consumed, so the copy being
25
+ masked is the browser's and only the browser's. Two different defaults for "server text reaching a
26
+ browser" would be a rule nobody could hold.
27
+
28
+ The failure `code` keeps travelling on its own data part, so consumers still distinguish failures
29
+ without matching on text — masking that removed the discriminator would push them back into the
30
+ habit that part exists to have removed.
31
+
32
+ **Breaking** for `@theokit/agents`: an application that read the server's message out of
33
+ `errorText` now reads `'An error occurred.'`. Pass `onError: (e) => e.message` to restore the old
34
+ behaviour explicitly, which is the point — it becomes a decision instead of a default.
35
+
36
+ - d4da51b: The agent route `generateAgentRoutes` mounts now speaks the wire this framework's clients read.
37
+
38
+ There were TWO SSE encoders for agent runs and they did not agree. The durable one writes
39
+ `data: <UIMessageChunk>` and a terminal `data: [DONE]`; this one wrote
40
+ `event: <type>` + `data: <framework StreamEvent>` — snake_case agent events rather than kebab-case
41
+ wire chunks — and no terminator at all.
42
+
43
+ `parseWireStream` validates each `data:` payload against `wireChunkSchema` and drops what fails
44
+ through a `warn` whose default sink is a no-op. So a `TheoApp` app mounted with `agentRuntime`
45
+ served `POST {route}/chat` in a format none of its own clients could read: zero chunks, no
46
+ assistant message, and a run reporting success with an empty answer — silent at every layer.
47
+
48
+ The events go through `presentUIMessageStream` now, the same translator `mountAgent` uses, so there
49
+ is one wire and one place that produces it. It also terminates: the missing `finish` chunk is what
50
+ a client keys "completed" on, so without it a finished run and a dropped connection were
51
+ indistinguishable there too.
52
+
53
+ **Breaking** for anyone who built their own reader against the old framework-event format on this
54
+ route. That is the trade the fix makes: a wire only a bespoke consumer could read, for the one every
55
+ client in this framework already speaks.
56
+
57
+ ### Minor Changes
58
+
59
+ - a896e4a: A conversation survives a reload: `chatId` can be supplied and read.
60
+
61
+ `AgentClient` drew `#chatId` in its field declaration and offered no way to supply one or to read
62
+ the one it drew. The id is not decorative — the HTTP transport sends it as the top-level `id`, which
63
+ the server reads as the session id — so every `new AgentClient(...)` started a new conversation, and
64
+ reloading the page silently abandoned the thread the server still held.
65
+
66
+ ```ts
67
+ const client = new AgentClient(transport, undefined, {
68
+ chatId: localStorage.getItem('chat') ?? undefined,
69
+ })
70
+ localStorage.setItem('chat', client.chatId)
71
+ ```
72
+
73
+ Both halves matter. Reading without supplying lets an application persist an id it can never
74
+ restore; supplying without reading leaves it nothing to persist.
75
+
76
+ The default is unchanged and deliberately so: two clients built with no id are still two
77
+ conversations. Sharing one by default would let two unrelated tabs write into the same thread, which
78
+ is the opposite defect and the more dangerous one.
79
+
80
+ - d9e98e0: A model that takes no credential can delegate.
81
+
82
+ `createDelegateTool` refused to construct when any target was a `SubAgentSpec` and
83
+ `defaults.apiKey` was empty, and `delegate()` refused the same way deeper in its own call stack.
84
+ Both read "non-empty string" as the definition of authenticated — a safe reading while every
85
+ provider held a key, and no longer one now that a keyless provider (a model on the developer's own
86
+ machine) is reachable.
87
+
88
+ `apiKey: null` says the provider takes no credential. It is a distinct value from `''` on purpose:
89
+ an empty string is also what an unset environment variable produces, so accepting THAT would turn a
90
+ typo into an unauthenticated run. `undefined` still means the caller supplied nothing and is still
91
+ refused — at startup rather than at the model's first call, which is what the guard was for.
92
+
93
+ The refusal now names the option, so a reader who hits it is not left choosing between a fabricated
94
+ value and giving up.
95
+
96
+ - da4db56: A run the server still holds can be reached after a page reload.
97
+
98
+ The whole durable-reconnect machinery — sequence ids on every frame, the `RunEventCache`, the
99
+ `Last-Event-ID` replay, the `x-theokit-run-id` header — was built and reachable, and one link made
100
+ it unusable in the case with the highest user cost. The reconnect key lived in a private in-memory
101
+ field, so a reloaded page built a fresh transport with an empty cell and `reconnectToStream`
102
+ returned `null` before it reached the network. The run was alive, cached, replayable, and
103
+ unreachable; the user got an empty thread instead of the answer the server had already finished.
104
+
105
+ `HttpTransport` takes a `runIdStore` now — `{ get(): string | undefined; set(id): void }` —
106
+ defaulting to an in-memory cell, which is exactly what the private field was. Nothing changes for a
107
+ caller who passes nothing, including the reconnect-within-one-page-lifetime case that already
108
+ worked.
109
+
110
+ The MEDIUM is deliberately the consumer's decision. `sessionStorage` matches a run's lifetime better
111
+ than `localStorage`, and either would be a client library writing to browser storage nobody asked it
112
+ to write to, with privacy and SSR consequences. So the seam is injected and the package stores
113
+ nothing it was not handed a place for.
114
+
115
+ Deliberately NOT included: reconnecting automatically on load. This makes a cached run _reachable_;
116
+ reaching for it is a product decision nobody has asked for.
117
+
118
+ - 3762c7d: An agent can declare a ceiling on the tool-calling turns of a single run, and the served agent obeys
119
+ it. `AgentBuilder.create().maxIterations(5)` and `defineAgent({ maxIterations: 5 })` are new; the
120
+ ceiling `@Agent({ maxIterations })` and `@MainLoop({ maxIterations })` already accepted now reaches
121
+ the runtime as well.
122
+
123
+ The number was written by every authoring path and read by none of them once the agent was served:
124
+ the only code enforcing a ceiling was the reflective loop, which no served path calls. The adapter
125
+ now lowers `CompiledAgentOptions.maxIterations` to the SDK's `SendOptions.maxIterations` — its
126
+ documented per-send ceiling — on both the streaming path and the handle `toAgentFactory` serves,
127
+ where a caller's own value still wins for that turn.
128
+
129
+ An agent that declares no ceiling is untouched: the key is omitted entirely, so the SDK's own default
130
+ still applies and nothing about that run changes. A value that is not a positive integer is refused
131
+ where it was written rather than at the first send.
132
+
133
+ - 5f90ddd: A run that was cut short says so. The terminal `done` frame and the turn metadata a client reads off
134
+ `UIMessage.metadata` now carry an optional `stopReason` — `'step_limit'` when the loop ran out of
135
+ tool-calling turns while the model still wanted more, `'no_progress'` when the doom-loop guard
136
+ stopped it repeating identical tool calls. The observability span `agent.run` records the same value
137
+ as `stop.reason`.
138
+
139
+ Both outcomes reached the caller as an ordinary `done` before this, identical in every field to a run
140
+ that finished on its own, so a surface could not tell "the agent answered" from "the agent was cut off
141
+ with a tool call still pending". The SDK reported both on its `RunResult`; the adapter's locally-typed
142
+ `wait()` declared no field to read them from, so nothing read them.
143
+
144
+ This is not the rare case it looks like: the SDK's iteration budget defaults to 8, so every served run
145
+ needing a ninth tool-calling turn was being truncated and reported as finished — including runs of
146
+ agents that never declared a ceiling.
147
+
148
+ Two reasons rather than a `truncated` flag, because they demand opposite reactions: `step_limit` means
149
+ re-sending continues the work, `no_progress` means re-sending repeats the loop that was just cut.
150
+ Nothing here re-sends — the SDK owns continuation; this reports the outcome.
151
+
152
+ A run that finishes on its own is unchanged: the field is absent, not `undefined`, so absence keeps
153
+ meaning "the agent finished" and a consumer that has never heard of `stopReason` receives exactly what
154
+ it received before.
155
+
156
+ - c131170: A run whose connection drops mid-answer is reported as interrupted instead of finished. The agent
157
+ client used to settle a dropped stream in `status: 'done'` with `error` undefined and half a sentence
158
+ on screen — the spinner stopped, the error surface stayed empty, and the truncated turn was committed
159
+ to the thread as a completed one. `reconnect()` and the durable replay route were fully built and
160
+ unreachable, because the only trigger a consumer has for them is a status that never arrived.
161
+
162
+ `consumeChunkStream` (and `consumeUIMessageStream`) now return a `ChunkStreamOutcome` saying whether
163
+ the stream carried its terminal `finish` chunk and how many chunks crossed. When it did not,
164
+ `AgentClient` settles `status: 'error'` with an `AgentStreamInterruptedError` — a `TheokitAgentError`
165
+ with `code: 'AGENT_STREAM_INTERRUPTED'` and `isRetryable: true`, so `isTransientError` sees it and a
166
+ consumer decides on the type instead of on message text. The text already received stays on screen,
167
+ and `send()`'s existing rule keeps the truncated turn out of history.
168
+
169
+ The status is `'error'` rather than a new `'interrupted'` member on purpose: a new member fixes the
170
+ lie only for consumers who update their switch, while every other surface keeps rendering a finished
171
+ turn. Reusing `'error'` fixes it for all of them at once, and the reason for it lives in the typed
172
+ error where this framework already puts error discrimination.
173
+
174
+ This is a different axis from `stopReason` (#379), not another member of it. `stopReason` says why the
175
+ RUN stopped and rides the terminal frame's metadata; an interruption is the absence of that frame,
176
+ where the client cannot know why the run stopped because it never heard.
177
+
178
+ A stream that ends on its terminal `finish` chunk is unchanged, down to the fields on the snapshot.
179
+ A custom transport that never emitted `finish` — which no framework producer does, since
180
+ `presentUIMessageStream` emits it on every path including the error one — will now be reported as
181
+ interrupted, which is what it always was.
182
+
183
+ - e29e22e: `mcpInventory()`, from `@theokit/agents/mcp-health`: the per-server status of the agent's MCP
184
+ servers — `loaded`, `failed` or `ignored`, each with its reason.
185
+
186
+ `loadMcpJson` reads the configuration file; this reads what was observed. A server that failed its
187
+ handshake and a server the loader refused both appear, which is what a `/mcp`-style command needs and
188
+ what a configuration read cannot give.
189
+
190
+ Tool-level enumeration is not included and is not planned here: the resolved tool table lives inside
191
+ `@theokit/sdk`'s agent loop and no run event carries it.
192
+
193
+ - a5c6353: `readThreadHistory()` from `@theokit/agents/session`: read one thread's stored history with three
194
+ answers — `present`, `absent`, or `unreadable` with the reason.
195
+
196
+ Applications had two. Catching for a brand-new thread (which has no transcript yet) is mandatory, and
197
+ that catch also swallowed parse and permission failures, so a damaged conversation rendered as an
198
+ empty successful one.
199
+
200
+ `absent` still does not distinguish a lost conversation from a new one, and the type says so: the
201
+ thread id is minted client-side and nothing records that it was issued. That distinction belongs to
202
+ the caller who knows whether the id was restored from storage or freshly minted.
203
+
204
+ ### Patch Changes
205
+
206
+ - c8022db: Four separate defects the SAST gate was reporting, each fixed at its cause.
207
+
208
+ **A generated property key could not contain a backslash.** The typed app-client emits a route
209
+ segment that is not a plain identifier as a quoted key, escaping the quote but not the escape
210
+ character — so a segment ending in `\` produced `'trail\'`, whose trailing backslash escapes the
211
+ closing quote and swallows the rest of the emitted line. A backslash is a legal POSIX filename
212
+ character, so it reaches this code from `server/routes/`.
213
+
214
+ **An internal error could forge log entries.** `sendError` logs an `INTERNAL_ERROR` with its
215
+ message and request id, and an exception message can be built from request data. A newline inside
216
+ it reached the log verbatim, which is enough to append lines of one's own — a fabricated entry
217
+ sitting in the log looking exactly like a real one. Both values are now rendered as one line.
218
+
219
+ **Stripping TOTP padding was quadratic.** `base32Decode` removed trailing `=` with an anchored
220
+ `/=+$/`, which retries from every start position, so a long run of `=` followed by anything else
221
+ costs O(n²) — on an authentication path. The comment defending it argued the input was short
222
+ enough ("10..50 chars typical"), which is an expectation rather than a bound. A scan back from the
223
+ end is linear and needs no such argument.
224
+
225
+ **The hook-output fence escaped only the first `<`.** `fenceHookOutput` neutralises an early
226
+ fence-close by escaping its `<`, using a form of `replace` that stops at the first occurrence. The
227
+ fence contains exactly one today, so nothing was wrong — and nothing said so, which made the
228
+ correctness of a prompt-injection guard depend on a property of a string literal several lines
229
+ away. `replaceAll` removes the dependency.
230
+
231
+ Behaviour is otherwise unchanged: an identifier-safe key, a message without newlines, a normal
232
+ base32 secret and a well-formed hook output all produce exactly what they produced before.
233
+
234
+ - 0e9e6dc: A human-in-the-loop tool call is one call on the wire again. A `@HumanInTheLoop` tool used to cross
235
+ as TWO `tool-input-available` chunks under two different `toolCallId`s — the approval id the HITL
236
+ plugin mints for its `approve/${approvalId}` callback, and the runtime tool-call id the SDK mints
237
+ when it dispatches the tool. Neither producer can adopt the other's id: the SDK's `pre_tool_call`
238
+ context carries `name`, `args`, `agentId` and `runId` and no call id at all, so the plugin has
239
+ nothing to key on, and the approval has to be published before the tool exists.
240
+
241
+ The translator correlates them now, so one logical call is announced once and its result carries the
242
+ same id. `tool-approval-request` keeps the plugin's id in `approvalId` — the callback URL is
243
+ unchanged and the same value still resolves the pause — and names the call it gates in `toolCallId`,
244
+ which is what that field was always for.
245
+
246
+ What this was costing: a consumer counting tool calls counted two, a UI grouping blocks by
247
+ `toolCallId` rendered two cards for one call and left a permanently pending approval part next to the
248
+ completed one, and the `agent.hitl` observability span opened on the approval id was never closed by
249
+ a result arriving under the runtime id — so its duration approximated the whole run instead of the
250
+ human's wait. That span now closes at the resume and carries `hitl.resume_observed: true`; the
251
+ end-of-run sweep that marks the opposite is back to being the exceptional path it describes, reached
252
+ when a pause genuinely never resumes (the client disconnected, the run failed mid-pause).
253
+
254
+ Ungated tools are untouched — the correlation is identity for a call no approval ever claims.
255
+
256
+ - 4411a59: A web application can now render a human-in-the-loop approval prompt. `useAgent` returns
257
+ `pendingApprovals` — one entry per decision the run is parked on, carrying the `approvalId` that
258
+ `approve()` takes, the gated tool's name, the arguments it is about to run with, the question
259
+ declared on the gate, and the window before it settles itself.
260
+
261
+ Before this the hook exposed the settle half of the gate and no way to reach the other half. The
262
+ store dropped the `tool-approval-request` frame on the way in, so its whole snapshot while a human
263
+ was deciding was `messages`, `thread`, `status: 'streaming'` and `error` — and the paused tool sat in
264
+ `state: 'input-available'`, which is exactly what an ungated tool looks like while it runs. An
265
+ application could not tell "working" from "waiting for you", and could not have named the decision if
266
+ it could. The only path left was polling `GET /api/agents/<name>/approvals` out of band.
267
+
268
+ The transcript carries it too: the gated call's own part moves to `state: 'approval-requested'` with
269
+ the id under `approval.id` while the decision is outstanding, and leaves that state when it is
270
+ settled. That is the ai-sdk reader's own vocabulary, not a new one — the differential oracle compares
271
+ the two readers on the paused run and the denied run and they reconstruct identically.
272
+
273
+ What the gate is asking travels as a transient `data-approval` part rather than on the approval frame
274
+ itself. The frame is shared vocabulary and `ai`'s validator for it is strict: a `question` added
275
+ there would not give an ai-sdk client a poorer prompt, it would delete the whole approval frame for
276
+ that client and re-create this defect on the other side of the wire. The tool's name and its
277
+ resolved input are not repeated anywhere — the `tool-input-available` frame already announces both
278
+ under the same call id, and both readers fold the frames into one part.
279
+
280
+ `approve(approvalId, decision)` is unchanged; what changes is that the store now hands the id over.
281
+ A tool with no gate produces exactly the same frames and exactly the same snapshot as before, with
282
+ `pendingApprovals` empty.
283
+
284
+ - 3126e58: A tool that failed reaches the caller as a tool that failed.
285
+
286
+ A tool whose handler threw — including one that threw on every attempt until its retries ran out —
287
+ crossed the wire as `tool-output-available`, the SUCCESS part of the UIMessage protocol, with the
288
+ error message sitting in the field a UI renders as the tool's answer, on a run that terminated with
289
+ an ordinary `done`. Nothing on the wire told a failed call from a call that worked, so a consumer
290
+ watching for a failure never fired, and a UI printed the failure as the result.
291
+
292
+ The failure signal was in hand the whole time. `@theokit/sdk` catches whatever a handler throws and
293
+ reports the call with `{stdout, stderr, exitCode}` — a non-zero code for a throw, a hook block, a
294
+ human denial, a timeout or an unknown tool — under `status: 'completed'`, which is the SDK's word
295
+ for "the call is over", not for "the call worked". Both translation sites read the status and
296
+ hardcoded `isError: false`, and the timeline dedup then dropped the only report carrying the exit
297
+ code as a duplicate of the report that structurally cannot carry one: the completion delta's payload
298
+ is a rendered string, and the message carrying the code always arrives second.
299
+
300
+ The exit code now travels. A failed call reaches the wire as `tool-output-error` with the message in
301
+ `errorText` — the presenter branch that emits it already existed and was never reachable from a
302
+ served run. A completion is held for one report rather than emitted immediately, so the second report
303
+ can contribute its exit code to the first instead of being discarded; exactly one result per call
304
+ still reaches the wire, and one that ends the run is flushed rather than held forever.
305
+
306
+ A call that succeeded is unchanged, chunk for chunk: it emits `tool-output-available` with the same
307
+ rendered output, under the same id, exactly once. A completion nobody reported an exit code for is
308
+ not called a failure — the `[stderr]` prefix in the rendered text is a string convention, and
309
+ classifying failures by matching error text is a mistake this codebase has already paid for once.
310
+
311
+ - Updated dependencies [bbdfc15]
312
+ - Updated dependencies [4411a59]
313
+ - @theokit/presenter@0.8.0
314
+
315
+ ## 10.1.0
316
+
317
+ ### Minor Changes
318
+
319
+ - c227a8d: `LivenessVerdict` now carries the `cwd` it is about, so a caller can act on the verdict instead of parsing a sentence.
320
+
321
+ `classifyProjects` PROBES a path to decide `alive` — it has it in hand at the moment it returns — and kept only a prose `reason`. That made the verdict unable to replace the function it was absorbed from: the consumer's GC uses the resolved cwd to consult the agent registry and the resumable pointer for that project (`all-sessions.ts:161,175`). Recovering it by string-matching `reason` would be exactly the fragile coupling this module exists to remove.
322
+
323
+ `alive` reports the member of the collision class that was found to EXIST, not the first one read — the class can hold a gone path and a live one, and sending a registry lookup to the gone sibling defeats the point. `dead` reports the recorded cwd that was checked and found missing. `undetermined` established no path, so the field is absent rather than an empty string a caller might mistake for one.
324
+
325
+ Additive and optional: no existing call site changes.
326
+
3
327
  ## 10.0.0
4
328
 
5
329
  ### Major Changes
package/LICENSE CHANGED
@@ -137,8 +137,8 @@
137
137
 
138
138
  6. Trademarks. This License does not grant permission to use the trade
139
139
  names, trademarks, service marks, or product names of the Licensor,
140
- except as required for describing the origin of the Work and
141
- reproducing the content of the NOTICE file.
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
142
 
143
143
  7. Disclaimer of Warranty. Unless required by applicable law or
144
144
  agreed to in writing, Licensor provides the Work (and each
package/README.md CHANGED
@@ -14,7 +14,7 @@ there is state or orchestration to hold, and forwarding the rest unchanged.
14
14
  > **Enriching never reduces.** A symbol the SDK exposes and this layer does not forward is
15
15
  > unreachable to whoever consumes the layer — and the only legal way out for them is to reimplement
16
16
  > it. That happened: when `./auth` exported one value against the SDK's nineteen, a downstream
17
- > product rewrote ~120 lines of credential mechanics. `scripts/check-surface-parity.mjs` in the
17
+ > product rewrote ~120 lines of credential mechanics in the
18
18
  > repository root now requires a written decision per SDK symbol, so the next gap breaks CI instead
19
19
  > of quietly costing someone a week.
20
20
 
@@ -29,11 +29,11 @@ you mount HTTP surfaces).
29
29
 
30
30
  ## Subpath map
31
31
 
32
- Nineteen entry points. Import the one you need — the barrel is not the API.
32
+ Twenty entry points. Import the one you need — the barrel is not the API.
33
33
 
34
34
  | Subpath | What lives there |
35
35
  |---|---|
36
- | `.` | The fluent `agent()` / `tool()` builders, the error hierarchy, shared types |
36
+ | `.` | `AgentBuilder.create()` the authoring surface — plus the error hierarchy and shared types |
37
37
  | `./bridge` | The SDK seam — `createSdkAgentStream`, event translation, the agent builder internals |
38
38
  | `./testing` | Test seams: compiled-agent inspection, mock streams |
39
39
  | `./sandbox` | Sandbox backends, postures, `sandboxWritePolicy` |
@@ -41,6 +41,7 @@ Nineteen entry points. Import the one you need — the barrel is not the API.
41
41
  | `./interactive` | The interactive-shell backend contract |
42
42
  | `./pty` | The node-pty implementation of that contract |
43
43
  | `./auth` | Credential store, OAuth/device flow, `resolveCredential`, `assertSecureModes` |
44
+ | `./config` | Agent configuration, trust posture, and the instruction tree (`loadInstructionTree`) |
44
45
  | `./tools` | Built-in tool factories (read, list, grep, git, patch, edit, shell, …) |
45
46
  | `./client` | Transports for driving an agent from a client |
46
47
  | `./client/react` | `useAgent` and the React bindings |
@@ -78,8 +79,8 @@ data, and a user cannot tell an explicit choice from a precedence fallback.
78
79
  See [`CHANGELOG.md`](./CHANGELOG.md) — shipped inside this package, so `node_modules` answers the
79
80
  question without a round trip to the repository.
80
81
 
81
- For "which symbol delivers capability X, and in which version did it land", the repository publishes
82
- a capability index at `wiki/capability-index.md`.
82
+ For "which symbol delivers capability X, and in which version did it land", the CHANGELOG entry that
83
+ shipped the symbol is the answer — every entry names the version it landed in.
83
84
 
84
85
  ## Boundaries this package keeps
85
86
 
@@ -1,175 +1,6 @@
1
- import { McpServerConfig, SystemPromptResolver, InlineSkill, SettingSource, MemorySettings, SkillsSettings, ContextSettings } from '@theokit/sdk';
1
+ import { InlineSkill, SystemPromptResolver, SettingSource, MemorySettings, SkillsSettings, ContextSettings } from '@theokit/sdk';
2
2
  import { TheokitAgentError } from '@theokit/sdk/errors';
3
- import { z } from 'zod';
4
-
5
- /**
6
- * Provider-agnostic extended-thinking knob (M1 reasoning-visibility). The common set autocompletes;
7
- * `(string & {})` accepts provider-specific values forward-compat (mirrors `AgentRunErrorCode`) — the
8
- * SDK validates the value against the model's catalog. Defined in this leaf module so every layer
9
- * (`@Agent` config, compiler, runner, sdk-adapter) imports it without an import cycle.
10
- */
11
- type ReasoningEffort = 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | (string & {});
12
- /** Scalar agent configuration. */
13
- interface AgentOptions {
14
- /** Unique agent name (kebab-case). */
15
- name: string;
16
- /** HTTP route prefix (e.g., '/api/agents/support'). */
17
- route: string;
18
- /** LLM model identifier (e.g., 'claude-sonnet-4-5-20250929'). */
19
- model?: string;
20
- /** Extended-thinking effort; mapped to the SDK `ModelSelection.params` so the provider reasons. */
21
- reasoningEffort?: ReasoningEffort;
22
- /**
23
- * Opt-in (default false): convert inline `<think>…</think>` in the text stream into `thinking`
24
- * events (M2) — for models that emit reasoning as inline tags (qwen/deepseek) rather than via a
25
- * native reasoning param. Off by default since a code assistant may emit literal `<think>` in text.
26
- */
27
- parseThinkTags?: boolean;
28
- /**
29
- * Opt-in (default false): strip a leaked Hermes `<function=…></tool_call>` tool-call dialect out of
30
- * the visible text (theocode#32) — for models (qwen/qwen3-coder) that intermittently emit tool calls
31
- * as text instead of native `tool_calls`. Off by default since a code assistant may emit a literal
32
- * `<function=` in answer/code text. Sibling of {@link parseThinkTags}.
33
- */
34
- stripToolDialect?: boolean;
35
- /**
36
- * Opt-in (default false): recover a leaked Hermes `<function=…></tool_call>` tool-call dialect so the
37
- * call actually EXECUTES (theokit#58 follow-up). Where {@link stripToolDialect} only hides the leaked
38
- * block from the visible text, this enables the SDK's `extractToolCallsFromContent` on the chat route,
39
- * so a `chat_completions` finish with ZERO native `tool_calls` has its text scanned for the dialect and
40
- * any recovered calls are dispatched by the loop. For models (qwen/qwen3-coder via OpenRouter) that
41
- * leak tool calls as text. Off by default (a code assistant may print a literal `<function=`); fail-open.
42
- * Has effect only when {@link AgentOptions} routes a provider via `providers.routes`. Sibling of
43
- * {@link stripToolDialect} — typically enabled together.
44
- */
45
- recoverLeakedToolCalls?: boolean;
46
- /** Enable SSE streaming (default: true). */
47
- stream?: boolean;
48
- /** Maximum loop iterations before forcing a terminal response. */
49
- maxIterations?: number;
50
- /** Timeout in milliseconds for the entire agent run. */
51
- timeoutMs?: number;
52
- /**
53
- * System prompt for the agent. Either a static string OR a
54
- * {@link SystemPromptResolver} computed per request (V4-L.1, Axis-B) — the SDK
55
- * invokes the resolver each send with the run's `SystemPromptContext` (cwd, etc.).
56
- */
57
- systemPrompt?: string | SystemPromptResolver;
58
- }
59
- /** Configuration stored by @MainLoop() decorator. */
60
- interface MainLoopOptions {
61
- /** Execution strategy. */
62
- strategy?: 'simple-chat' | 'plan-act-reflect' | 'react';
63
- /** Maximum iterations for this loop. */
64
- maxIterations?: number;
65
- /** Timeout in milliseconds. */
66
- timeoutMs?: number;
67
- }
68
- /** Internal representation of a resolved @MainLoop. */
69
- interface MainLoopMeta {
70
- propertyKey: string | symbol;
71
- strategy: 'simple-chat' | 'plan-act-reflect' | 'react';
72
- maxIterations?: number;
73
- timeoutMs?: number;
74
- }
75
- /** Configuration stored by @Toolbox() decorator. */
76
- interface ToolboxOptions {
77
- /** Namespace prefix for all tools in this toolbox (e.g., 'support'). */
78
- namespace?: string;
79
- }
80
- /** Configuration stored by @Tool() decorator. */
81
- interface ToolOptions {
82
- /** Tool name (surfaced to LLM). */
83
- name: string;
84
- /** LLM-facing description. */
85
- description: string;
86
- /** Zod input schema — compiled to JSON Schema via defineTool(). */
87
- input: z.ZodType;
88
- /** Risk level (informational — feeds manifest + UI). */
89
- risk?: 'low' | 'medium' | 'high';
90
- }
91
- /** Budget configuration for @Budget() decorator. */
92
- interface BudgetOptions {
93
- /** Maximum cost in USD for this scope. */
94
- maxCostUsd: number;
95
- /** Rolling window for budget tracking. */
96
- window?: 'daily' | 'monthly';
97
- }
98
- /** Approval configuration for @RequiresApproval() decorator. */
99
- interface ApprovalOptions {
100
- /** Reason shown to the approver. */
101
- reason: string;
102
- }
103
- /** Policy handler function type. */
104
- type PolicyHandler = (user: {
105
- roles: string[];
106
- }) => boolean;
107
- /**
108
- * M53 — moved here from the `@HumanInTheLoop` decorator, which is being deleted: the type is
109
- * consumed by `compileHitlGates` and the toolbox capability, not by the decorator alone.
110
- */
111
- type TimeoutAction = 'abort' | 'proceed' | 'retry';
112
- interface HumanInTheLoopOptions {
113
- /** Question shown to the human approver. */
114
- question: string;
115
- /** Timeout in milliseconds before onTimeout fires (default: 300_000 = 5 min). */
116
- timeout?: number;
117
- /** Action when timeout expires (default: 'abort'). */
118
- onTimeout?: TimeoutAction;
119
- /** Show the tool input to the approver (default: true). */
120
- showInput?: boolean;
121
- /**
122
- * M20 — an optional JSON-schema descriptor of the custom payload the approver may attach (edited
123
- * args, a review note). Carried into the `approval_required` event + `GET /approvals` so the UI
124
- * knows what to collect. A plain JSON object, not a live Zod schema (keeps the wire serializable).
125
- */
126
- payloadSchema?: Record<string, unknown>;
127
- }
128
-
129
- type McpServersMap = Record<string, McpServerConfig>;
130
- /** M53 — moved from the `@ProjectContext` decorator being deleted; read by the compiler. */
131
- type IndexStrategy = 'tree-sitter' | 'regex' | 'none';
132
- type RelevanceStrategy = 'git-history' | 'import-graph' | 'semantic' | 'manual';
133
- interface ProjectContextOptions {
134
- /** Files that mark the project root (searched upward from cwd). */
135
- rootMarkers?: string[];
136
- /** How to index the codebase for structural understanding. */
137
- indexStrategy?: IndexStrategy;
138
- /** Maximum files to include in context per request. */
139
- maxFilesInContext?: number;
140
- /** How to rank file relevance when selecting context. */
141
- relevanceStrategy?: RelevanceStrategy;
142
- /** Glob patterns to exclude from indexing and context. */
143
- ignorePatterns?: string[];
144
- /** File extensions to include in indexing (default: all text files). */
145
- includeExtensions?: string[];
146
- }
147
- type CheckpointStrategy = 'after-tool-call' | 'after-iteration' | 'manual';
148
- type CheckpointStorage = 'memory' | 'filesystem' | 'drizzle' | 'redis';
149
- interface CheckpointOptions {
150
- /** Where to persist checkpoints. */
151
- storage?: CheckpointStorage;
152
- /** When to auto-checkpoint (default: 'after-tool-call'). */
153
- strategy?: CheckpointStrategy;
154
- /** Maximum checkpoints to retain per run (rolling window). */
155
- maxCheckpoints?: number;
156
- /** Time-to-live in ms before checkpoints expire (default: 3_600_000 = 1h). */
157
- ttl?: number;
158
- }
159
- type MemoryProvider = 'built-in' | 'honcho' | 'supermemory' | 'mem0';
160
- type MemoryScope = 'per-user' | 'per-agent' | 'per-tenant' | 'global';
161
- interface MemoryOptions {
162
- /** Memory provider backend. */
163
- provider?: MemoryProvider;
164
- /** Enable semantic search via embeddings. */
165
- embeddings?: boolean;
166
- /** Enable full-text search (FTS5). */
167
- fts?: boolean;
168
- /** Memory isolation scope (default: 'per-user'). */
169
- scope?: MemoryScope;
170
- /** Maximum facts to retain per scope (0 = unlimited). */
171
- maxFacts?: number;
172
- }
3
+ import { R as ReasoningEffort, a as MemoryOptions, P as ProjectContextOptions, M as McpServersMap, H as HumanInTheLoopOptions, C as CheckpointOptions, T as ToolOptions, A as ApprovalOptions, B as BudgetOptions } from './types-C16Wuh9E.js';
173
4
 
174
5
  /**
175
6
  * M9 (theokit-ai-first) — guardrail contract + typed errors.
@@ -400,4 +231,4 @@ interface CompiledAgentOptions {
400
231
  skillsResolver?: SkillsSelection;
401
232
  }
402
233
 
403
- export { type ApprovalOptions as A, type BudgetOptions as B, type CompiledAgentOptions as C, type Guardrail as G, type HumanInTheLoopOptions as H, type McpServersMap as M, type PolicyHandler as P, type ReasoningEffort as R, type SkillsSelection as S, type ToolOptions as T, type MainLoopMeta as a, type CompiledTool as b, type AgentOptions as c, CostBudgetExceededError as d, type GuardrailAction as e, type GuardrailPhase as f, type GuardrailResult as g, GuardrailViolationError as h, type MainLoopOptions as i, type SkillsRequestContext as j, type TimeoutAction as k, type ToolWalkResult as l, type ToolboxOptions as m, type ToolboxWalkResult as n, compileTools as o, type ProjectContextOptions as p, resolveEnabledSkills as r };
234
+ export { type CompiledAgentOptions as C, type Guardrail as G, type SkillsSelection as S, type ToolWalkResult as T, type CompiledTool as a, CostBudgetExceededError as b, type GuardrailAction as c, type GuardrailPhase as d, type GuardrailResult as e, GuardrailViolationError as f, type SkillsRequestContext as g, type ToolboxWalkResult as h, compileTools as i, resolveEnabledSkills as r };