@theokit/agents 13.0.0-next.9 → 13.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 (52) hide show
  1. package/CHANGELOG.md +1682 -0
  2. package/README.md +31 -0
  3. package/dist/{agent-compiler-DZorqtK2.d.ts → agent-compiler-B0hb6HCo.d.ts} +177 -198
  4. package/dist/ask.d.ts +1 -0
  5. package/dist/auth.d.ts +148 -1
  6. package/dist/auth.js +36 -0
  7. package/dist/auth.js.map +1 -1
  8. package/dist/{bridge-entry-B0FqqPlt.d.ts → bridge-entry-DBkqwe6b.d.ts} +72 -6
  9. package/dist/bridge.d.ts +6 -4
  10. package/dist/bridge.js +9 -4
  11. package/dist/{chunk-TZCHACY7.js → chunk-G7QBDGZ4.js} +93 -18
  12. package/dist/chunk-G7QBDGZ4.js.map +1 -0
  13. package/dist/chunk-HGVT4VCE.js +97 -0
  14. package/dist/chunk-HGVT4VCE.js.map +1 -0
  15. package/dist/{chunk-6WFRR24F.js → chunk-KTQID5V3.js} +560 -342
  16. package/dist/chunk-KTQID5V3.js.map +1 -0
  17. package/dist/chunk-M5J3Q6YC.js +17 -0
  18. package/dist/chunk-M5J3Q6YC.js.map +1 -0
  19. package/dist/{chunk-RKWCXVYG.js → chunk-MJ6FRILJ.js} +67 -5
  20. package/dist/chunk-MJ6FRILJ.js.map +1 -0
  21. package/dist/{chunk-LPS65NGG.js → chunk-PMMOOXR6.js} +33 -10
  22. package/dist/chunk-PMMOOXR6.js.map +1 -0
  23. package/dist/chunk-U72XTMYB.js +7 -0
  24. package/dist/chunk-U72XTMYB.js.map +1 -0
  25. package/dist/client-react.d.ts +1 -0
  26. package/dist/client.d.ts +1 -0
  27. package/dist/config.d.ts +163 -36
  28. package/dist/config.js +119 -7
  29. package/dist/config.js.map +1 -1
  30. package/dist/{define-agent-D9b3h3VU.d.ts → define-agent-DhwNmdej.d.ts} +27 -3
  31. package/dist/{delegation-scoring-MbnqL68u.d.ts → delegation-scoring-BzJEheml.d.ts} +1 -1
  32. package/dist/hooks.d.ts +0 -32
  33. package/dist/hooks.js +42 -14
  34. package/dist/hooks.js.map +1 -1
  35. package/dist/index.d.ts +191 -16
  36. package/dist/index.js +43 -5
  37. package/dist/index.js.map +1 -1
  38. package/dist/sandbox.js.map +1 -1
  39. package/dist/setting-sources-gate-DFu51i50.d.ts +278 -0
  40. package/dist/testing.d.ts +5 -2
  41. package/dist/testing.js +1 -1
  42. package/dist/tools.d.ts +4 -2
  43. package/dist/tools.js +22 -4
  44. package/dist/tools.js.map +1 -1
  45. package/dist/usage.d.ts +30 -0
  46. package/dist/usage.js +3 -0
  47. package/dist/usage.js.map +1 -1
  48. package/package.json +3 -3
  49. package/dist/chunk-6WFRR24F.js.map +0 -1
  50. package/dist/chunk-LPS65NGG.js.map +0 -1
  51. package/dist/chunk-RKWCXVYG.js.map +0 -1
  52. package/dist/chunk-TZCHACY7.js.map +0 -1
package/README.md CHANGED
@@ -90,6 +90,37 @@ shipped the symbol is the answer — every entry names the version it landed in.
90
90
  - Web Standards over Node APIs inside `src/` — `Request`/`Response`, `fetch`, `crypto.randomUUID`.
91
91
  Node APIs live in adapters.
92
92
 
93
+ ## Who decides policy
94
+
95
+ **An operator who did not write the code can impose policy on it.** That is a decision, recorded
96
+ here because it is the one a team evaluating this framework for deployment needs before anything
97
+ else.
98
+
99
+ It was not always true. Hooks, MCP servers, permissions and skill execution were each a value the
100
+ *programmer* passed at build time — a constructor argument, decided in code, by whoever wrote the
101
+ agent. That is a defensible design for a framework and an indefensible one for anything an
102
+ organisation deploys: it means the person responsible for what an agent may do on a machine has no
103
+ way to say so.
104
+
105
+ Policy is read from disk, and the layers have a fixed precedence:
106
+
107
+ | Layer | Who writes it | Wins against |
108
+ |---|---|---|
109
+ | `managed-settings.json` | the operator / the organisation | everything below |
110
+ | `.claude/settings.json`, `.theokit/settings.json` | the project | the code |
111
+ | `defineAgent({ … })` | the programmer | nothing |
112
+
113
+ A programmer can still decide everything, and in a single-author project nothing above them exists.
114
+ What changed is that they are no longer the *only* one who can.
115
+
116
+ Two consequences worth stating, because they are the cost:
117
+
118
+ - A value declared in code can be **overridden by a file the programmer does not control**. That is
119
+ the point, and it means a build-time guarantee is not one.
120
+ - An operator restriction is refused loudly rather than silently narrowed. A policy that quietly
121
+ did less than it said would be worse than none — the failure this repository keeps finding under
122
+ other names.
123
+
93
124
  ## Licence
94
125
 
95
126
  See `LICENSE`.
@@ -1,6 +1,8 @@
1
- import { InlineSkill, TrustPosture, SettingSource, SystemPromptResolver, MemorySettings, SkillsSettings, ContextSettings } from '@theokit/sdk';
1
+ import { InlineSkill, SystemPromptResolver, SessionStore, PermissionGate, MemorySettings, SkillsSettings, ContextSettings, TelemetrySettings } from '@theokit/sdk';
2
+ import { AgentDefinition } from '@theokit/sdk/subagents-loader';
2
3
  import { TheokitAgentError } from '@theokit/sdk/errors';
3
4
  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';
5
+ import { G as GatedSettingSource, a as GatedCompatSource } from './setting-sources-gate-DFu51i50.js';
4
6
 
5
7
  /**
6
8
  * M9 (theokit-ai-first) — guardrail contract + typed errors.
@@ -35,23 +37,87 @@ interface Guardrail {
35
37
  }
36
38
  /** Which boundary phase a violation happened in. */
37
39
  type GuardrailPhase = 'input' | 'output';
38
- /** Thrown (fail-fast) when a guard returns `action: 'block'`. Typed per error-handling.md. */
39
40
  /**
40
- * M80 — extends {@link TheokitAgentError}, not plain `Error`.
41
+ * A guard declared `redact` and supplied no replacement text.
41
42
  *
42
- * `isTransientError` is defined over `TheokitAgentError`, so a class outside that hierarchy is
43
- * INVISIBLE to it and the only recourse left to a consumer is matching on message text — a regex
44
- * over an eight-level `cause` chain, which is what one actually wrote. `code` is stable across a
45
- * rename of the class; `isRetryable` is DECLARED rather than defaulted, because a default would be a
46
- * retry policy nobody chose.
43
+ * Distinct from {@link GuardrailViolationError} on purpose: that one says the guard REFUSED
44
+ * something, which is a decision working as designed. This says the guard is MALFORMED — it asked
45
+ * for a redaction and gave nothing to redact with, so nothing was redacted.
46
+ *
47
+ * Until B-008 this condition was silent: `pipeline.ts` tested `r.text !== undefined` and moved on, so
48
+ * the caller received the original text and believed a guard had run on it. That is the shape this
49
+ * package's hook engine calls "worse than no hook at all" — a belief in a protection that is not
50
+ * there. Throwing is fail-fast per `rules/error-handling.md § 2`, and the alternative was leaving
51
+ * unredacted output to reach a model because a guard was written wrong.
52
+ *
53
+ * `''` is NOT this case. An empty replacement is a guard choosing to erase everything, which is the
54
+ * strongest redaction available, and treating it as absent would invert the defect.
55
+ */
56
+ /**
57
+ * The base every guardrail error shares, so the seams that must treat them alike can do so BY
58
+ * CONSTRUCTION rather than by remembering a list.
59
+ *
60
+ * The list is how B-020 happened. `run-reflective-loop.ts` let `GuardrailViolationError` pass
61
+ * through unwrapped, and its sibling in this same file was not added — so a malformed result was
62
+ * wrapped in a `DelegationError`, whose message interpolates its cause and whose code is on the
63
+ * delegate tool's message allowlist. The guard's name crossed to the model, and a guard DEFECT was
64
+ * reported as a delegation failure.
65
+ *
66
+ * A base is not airtight on its own: a new class can still extend `TheokitAgentError` directly.
67
+ * `tests/unit/a-guardrail-defect-does-not-name-its-guard.test.ts` walks this module's barrel and
68
+ * fails on any exported error class that skipped it. The two together are the construction; either
69
+ * alone is a convention.
70
+ *
71
+ * Abstract because there is nothing to throw at this level — every guardrail failure is one of the
72
+ * specific kinds below, and a bare `GuardrailError` would say only that something guard-shaped
73
+ * happened.
47
74
  */
48
- declare class GuardrailViolationError extends TheokitAgentError {
75
+ declare abstract class GuardrailError extends TheokitAgentError {
76
+ }
77
+ declare class MalformedGuardrailResultError extends GuardrailError {
78
+ readonly guardName: string;
79
+ readonly phase: GuardrailPhase;
80
+ readonly name = "MalformedGuardrailResultError";
81
+ constructor(guardName: string, phase: GuardrailPhase);
82
+ }
83
+ /**
84
+ * Thrown (fail-fast) when a guard returns `action: 'block'`. Typed per error-handling.md.
85
+ *
86
+ * M80 — extends {@link TheokitAgentError}, not plain `Error`. `isTransientError` is defined over
87
+ * `TheokitAgentError`, so a class outside that hierarchy is INVISIBLE to it and the only recourse
88
+ * left to a consumer is matching on message text — a regex over an eight-level `cause` chain, which
89
+ * is what one actually wrote. `code` is stable across a rename of the class; `isRetryable` is
90
+ * DECLARED rather than defaulted, because a default would be a retry policy nobody chose.
91
+ */
92
+ declare class GuardrailViolationError extends GuardrailError {
49
93
  readonly guardName: string;
50
94
  readonly phase: GuardrailPhase;
51
95
  readonly reason: string;
52
96
  readonly name = "GuardrailViolationError";
53
97
  constructor(guardName: string, phase: GuardrailPhase, reason: string);
54
98
  }
99
+ /**
100
+ * A text-carrying event arrived with a `content` that is not text.
101
+ *
102
+ * Distinct from the two above on purpose: they say a guard REFUSED something or was WRITTEN WRONG.
103
+ * This says the STREAM is malformed — the event announces itself as text and carries something a
104
+ * guard cannot read.
105
+ *
106
+ * Until B-021 this was silent. Both extractors tested `typeof e.content === 'string'` and returned
107
+ * `undefined` otherwise, which `moderateOutputStream` reads as "this event carries no text" — so the
108
+ * payload was never accumulated, never shown to a guard, and yielded VERBATIM. The failure direction
109
+ * is DELIVER: a guard declared to stop that payload never saw it, and the run reported green.
110
+ *
111
+ * Refused rather than coerced. Coercing would moderate `"[object Object]"` — a guard consulted about
112
+ * a string the model never produced, returning a verdict about nothing, while the real payload rides
113
+ * along underneath. That is the redaction-computed-and-discarded shape with an extra step.
114
+ */
115
+ declare class UnreadableTextPayloadError extends GuardrailError {
116
+ readonly eventType: string;
117
+ readonly received: unknown;
118
+ readonly name = "UnreadableTextPayloadError";
119
+ constructor(eventType: string, received: unknown);
120
+ }
55
121
  /** Thrown when {@link costGuard}'s cumulative token budget is exceeded. */
56
122
  /**
57
123
  * M80 — extends {@link TheokitAgentError}, not plain `Error`.
@@ -62,7 +128,7 @@ declare class GuardrailViolationError extends TheokitAgentError {
62
128
  * rename of the class; `isRetryable` is DECLARED rather than defaulted, because a default would be a
63
129
  * retry policy nobody chose.
64
130
  */
65
- declare class CostBudgetExceededError extends TheokitAgentError {
131
+ declare class CostBudgetExceededError extends GuardrailError {
66
132
  readonly usedTokens: number;
67
133
  readonly maxTokens: number;
68
134
  readonly name = "CostBudgetExceededError";
@@ -98,181 +164,16 @@ type SkillsSelection = readonly (string | InlineSkill)[] | ((ctx: SkillsRequestC
98
164
  declare function resolveEnabledSkills(selection: SkillsSelection | undefined, ctx: SkillsRequestContext): Promise<string[] | undefined>;
99
165
 
100
166
  /**
101
- * M68 — the trust gate for `settingSources`.
102
- *
103
- * ## The defect this module closes
104
- *
105
- * `settingSources` enables on-disk config discovery. `'user'` reads `~/.theokit/` — the operator's
106
- * own machine, which no third party controls. `'project'` reads `<cwd>/.theokit/`, **including
107
- * `hooks.json`, which executes shell**.
108
- *
109
- * The previous API took `readonly SettingSource[]`, and its JSDoc justified the risk this way:
110
- * *"it is opt-in because `.theokit/` is the app's own repo (informed consent)"*. That premise holds
111
- * for a web app whose `cwd` is its own deploy. It does **not** hold for the class of product this
112
- * framework addresses — an agent whose `cwd` is a repository the user just cloned. There `.theokit/`
113
- * is attacker-controlled content, and enabling `'project'` is remote code execution on the first
114
- * `build()`.
115
- *
116
- * Documenting it did not prevent it. The measured consumer (TheoCode) did not trust the API: it
117
- * gated from the outside, with a `posture.allows` of its own (`chat.ts:386`, comment B-008). It
118
- * already **had** the right decision and could not pass it through, because the API only accepted
119
- * strings. The gate existed on its side and evaporated at the boundary.
120
- *
121
- * ## The evidence is the SDK's, not one invented here
122
- *
123
- * `TrustPosture` is `@theokit/sdk`'s own trust primitive, and `recordWiring`'s doc says *"a posture
124
- * is the only thing in this package that retains a capability"*. A bespoke type would make two trust
125
- * grammars coexist and drift apart (ADR 0063).
126
- */
127
- /**
128
- * The framework's capability vocabulary — deliberately a single name (ADR 0065).
129
- *
130
- * `allows` is all-or-nothing in the SDK: every declared `K` gets the same boolean. A finer
131
- * vocabulary (`hooks`, `skills`, `subagents`, `mcp`) would promise the consumer it can gate one
132
- * without gating the other, and the primitive does not deliver that. An API that suggests a
133
- * distinction the runtime does not make teaches the wrong thing, and the error only surfaces when
134
- * somebody depends on the distinction.
135
- */
136
- type SettingSourceCapability = 'projectSettings';
137
- /** Authorization to read config from the working directory. Requires the posture, never a claim. */
138
- interface ProjectSettingsGrant {
139
- /**
140
- * Typically the output of `resolveTrustPosture` — which is what gives it `source` (`'env' |
141
- * 'store' | 'default'`) and therefore a refusal that says WHERE the decision came from instead of
142
- * merely denying.
143
- */
144
- readonly trustedBy: TrustPosture<SettingSourceCapability>;
145
- }
146
- /**
147
- * Which on-disk config roots the agent may read.
148
- *
149
- * The asymmetry is the design: `user` is a boolean because `~/.theokit/` belongs to the operator;
150
- * `project` requires evidence because `<cwd>/.theokit/` may not. Omitting a root is not enabling it
151
- * — never "enabling without a gate". The asymmetry is inherited from the SDK itself, whose
152
- * `TrustPostureInput.envOverride` documents that `false` and `undefined` both mean "the operator did
153
- * not turn it on", not "turned it off".
154
- */
155
- interface SettingSourcesSelection {
156
- /** `~/.theokit/` — the operator's machine. No gate: no third party controls it. */
157
- readonly user?: boolean;
158
- /** `<cwd>/.theokit/` — controlled by whoever wrote the open repository. Requires evidence. */
159
- readonly project?: ProjectSettingsGrant;
160
- /**
161
- * `<cwd>/.claude/` — a FOREIGN configuration dialect, read only once declared
162
- * (`usetheokit/theokit-sdk#524`).
163
- *
164
- * ## Two questions, and which half of this field answers each
165
- *
166
- * The SDK's docblock separates them, and the separation is the whole point of `compatSources`:
167
- * a trust gate answers *"do I trust the code in this directory?"*; importing another product's
168
- * configuration answers *"do I want it imported into this one?"*. They come apart in the ordinary
169
- * case, because `.claude/` is populated in exactly the repository one trusts most — for a
170
- * different tool, by a teammate who never heard of this runtime.
171
- *
172
- * So the two are answered by two different things here, and it matters which:
173
- *
174
- * | Question | Answered by |
175
- * |---|---|
176
- * | do I want the foreign dialect imported? | **declaring this field at all** — omitting is not enabling |
177
- * | do I trust this directory's code to run? | the `TrustPosture` inside the grant |
178
- *
179
- * ## Why the grant is `ProjectSettingsGrant` and not a vocabulary of its own
180
- *
181
- * Not because the two questions are the same — they are not. Because a separate grant could not
182
- * carry the distinction even if it existed: `TrustPosture.allows` is `Record<K, boolean>` and the
183
- * SDK documents every value as moving together with the level, so a `'foreignDialects'` capability
184
- * beside `'projectSettings'` would promise an operator they can grant one and withhold the other,
185
- * and `resolveTrustPosture` would hand back the same boolean for both. That is precisely the
186
- * failure ADR 0065 exists to prevent, and inventing the second name would commit it while looking
187
- * like rigour.
188
- *
189
- * The consent half is therefore carried by the declaration, which is a real and sufficient
190
- * boundary: an operator who trusts a repository completely still reads no `.claude/` until they
191
- * write this field. What the grant adds on top is stricter than the SDK — there, listing a dialect
192
- * is enough — and the extra strictness is deliberate: this reads a `hooks.json` that executes
193
- * shell out of a directory that usually arrived with the clone.
194
- */
195
- readonly claudeCode?: ProjectSettingsGrant & {
196
- /**
197
- * #686 — WHICH surfaces of the foreign root to import. Absent means all of them, which is what
198
- * every caller before this meant and still means.
199
- *
200
- * The distinction is the reason the grant exists. `.claude/` usually arrives with the clone and
201
- * its `hooks.json` executes shell, so "take the skills, refuse the hooks" is the ordinary thing
202
- * to want — and before this the only choices were all of it or none of it.
203
- *
204
- * Requires `@theokit/sdk >= 5.4.0`, which is where the narrowed form landed. On an older SDK the
205
- * runtime drops an unrecognised shape in SILENCE, so declaring it there would import nothing at
206
- * all rather than importing less — refused at resolve time instead.
207
- */
208
- readonly import?: readonly CompatSurface[];
209
- };
210
- }
211
- /**
212
- * The surfaces a foreign configuration root can contribute.
167
+ * The shape this layer registers with the SDK's lifecycle-hook seam.
213
168
  *
214
- * Written out rather than imported, for the same reason as the `claude-code` literal below:
215
- * `CompatSurface` does not exist in `@theokit/sdk@4.52.1`, this package's declared floor, and a gate
216
- * that cannot build against its own minimum dependency is worse than a constant that has been
217
- * checked. Verified against the published 5.4.0 `.d.ts`, where the union is
218
- * `"hooks" | "plugins" | "skills" | "subagents"` — note `subagents`, not `agents`.
169
+ * Deliberately structural and minimal: the SDK owns the full `Plugin` contract, and restating it
170
+ * here would be a second declaration to drift from. What this needs to know is the one thing that
171
+ * tells a code plugin from a bundle reference.
219
172
  */
220
- type CompatSurface = 'hooks' | 'plugins' | 'skills' | 'subagents';
221
- /** What `resolveCompatSources` returns: the whole root, or the root narrowed to some surfaces. */
222
- type ResolvedCompatSource = 'claude-code' | {
223
- readonly kind: 'claude-code';
224
- readonly import: readonly CompatSurface[];
225
- };
226
- /**
227
- * Refusal to read the working directory for lack of trust.
228
- *
229
- * Descends from `TheokitAgentError` because typed errors are an unbreakable rule here — and because
230
- * `isTransientError` only sees this hierarchy. A class extending plain `Error` would be invisible to
231
- * the predicate that separates recoverable from unrecoverable (the defect M67 fixed in five
232
- * classes).
233
- */
234
- declare class UntrustedSettingSourceError extends TheokitAgentError {
235
- /** Where the trust decision came from: `'env' | 'store' | 'default'`. */
236
- readonly trustSource: string;
237
- /** The refused capability. */
238
- readonly capability: SettingSourceCapability;
239
- readonly name = "UntrustedSettingSourceError";
240
- constructor(message: string,
241
- /** Where the trust decision came from: `'env' | 'store' | 'default'`. */
242
- trustSource: string,
243
- /** The refused capability. */
244
- capability: SettingSourceCapability);
173
+ interface CodePlugin {
174
+ readonly name: string;
175
+ readonly register: (...args: never[]) => unknown;
245
176
  }
246
- /**
247
- * Translate the declared selection into the `SettingSource`s the SDK accepts, refusing what the
248
- * posture does not authorize.
249
- *
250
- * Refuses rather than ignores (ADR 0064). Ignoring would leave the product running in the belief
251
- * that the repository's hooks are active — a silent failure mode, on the wrong side. The SDK already
252
- * picked that side for the same problem: `recordWiring` throws `UngatedCapabilityError` when
253
- * somebody registers a capability the posture does not gate.
254
- *
255
- * @throws {UntrustedSettingSourceError} when `project` is requested and the posture does not grant it.
256
- */
257
- declare function resolveSettingSources(selection: SettingSourcesSelection | undefined): readonly SettingSource[];
258
- /**
259
- * The foreign configuration dialects this layer forwards, once the posture authorises them.
260
- *
261
- * ## Why it is a separate function and the same vocabulary
262
- *
263
- * Separate because the SDK takes them on a separate option (`local.compatSources`); the same
264
- * `ProjectSettingsGrant` because the thing being authorised is identical — reading a `hooks.json`
265
- * that executes shell out of a directory the operator does not necessarily control.
266
- *
267
- * ## What it deliberately does NOT do
268
- *
269
- * Validate the source NAME. The SDK DROPS an unrecognised name rather than turning it into
270
- * `<cwd>/<name>`, so a typo fails closed there; turning that into a throw here would convert a safe
271
- * default into a crash. This gate decides authorisation, never vocabulary.
272
- *
273
- * @throws {UntrustedSettingSourceError} when a source is requested and the posture does not grant it.
274
- */
275
- declare function resolveCompatSources(selection: SettingSourcesSelection | undefined): readonly ResolvedCompatSource[];
276
177
 
277
178
  /**
278
179
  * Project the M8 fields from `CompiledAgentOptions` into `Agent.create()` arguments. Only the async
@@ -325,6 +226,33 @@ declare class HookGateUnsupportedError extends TheokitAgentError {
325
226
  readonly name = "HookGateUnsupportedError";
326
227
  constructor(version: string | undefined);
327
228
  }
229
+ /**
230
+ * A narrowed `import` on an SDK that cannot read it.
231
+ *
232
+ * Refuses rather than warns, and the asymmetry with {@link warnIfSdkCannotReadCompatSources} is
233
+ * deliberate: an unrecognised `compatSources` shape means the foreign root is not read, so a
234
+ * consumer who asked for "the skills but not the hooks" silently gets NOTHING — strictly further
235
+ * from what they asked for than the un-narrowed form, which at least reads something. Failing loud
236
+ * is recoverable; a silent nothing is discovered by wondering why a skill is missing.
237
+ *
238
+ * ## The cost, which this file argues against two functions above
239
+ *
240
+ * An unreadable version is refused too, on the principle {@link assertSdkCanGateHooks} states:
241
+ * "cannot tell" and "is supported" must not collapse. The sibling WARNING takes the opposite view
242
+ * for itself — *"a bundled or vendored SDK may not resolve that subpath, and refusing to create an
243
+ * agent over a diagnostic would be the cure being worse than the disease."*
244
+ *
245
+ * Both are right for what they guard, and the difference is what the check IS. A diagnostic that
246
+ * cannot read a version should stay quiet; a GATE that cannot read one has not established the
247
+ * thing it exists to establish. But the cost is real and belongs here rather than in a reviewer's
248
+ * report: a consumer who bundles the SDK so `@theokit/sdk/package.json` does not resolve cannot
249
+ * create an agent with a narrowed `import`, even on 5.4.0+. Their exit is to omit `import` and read
250
+ * the whole root.
251
+ */
252
+ declare class CompatImportUnsupportedError extends TheokitAgentError {
253
+ readonly name = "CompatImportUnsupportedError";
254
+ constructor(version: string | undefined);
255
+ }
328
256
 
329
257
  /**
330
258
  * Agent compiler — transforms decorator metadata into SDK calls.
@@ -385,18 +313,23 @@ interface CompiledTool {
385
313
  * @param toolboxInstances - Map of Toolbox class → instantiated object (for `this` binding)
386
314
  */
387
315
  declare function compileTools(toolboxes: ToolboxWalkResult[], toolboxInstances: Map<ClassToken, object>): CompiledTool[];
388
- /** Compiled sub-agent definition matching SDK AgentDefinition shape. */
389
- interface CompiledSubAgent {
390
- model?: string;
391
- /**
392
- * V4-L.1: typed as the union for consistency with `AgentOptions.systemPrompt`,
393
- * so `compileSubAgents` carries whatever the sub-agent declared. Sub-agent
394
- * resolver EXECUTION is out of scope this slice (ADR D3): `compiled.agents` is
395
- * not spread into `Agent.create` by `createSdkAgentStream`; a resolver here is
396
- * carried, not invoked. Top-level agent resolvers are the supported path.
397
- */
398
- systemPrompt?: string | SystemPromptResolver;
399
- }
316
+ /**
317
+ * A compiled sub-agent IS the SDK's own `AgentDefinition`, re-exported here under the name the
318
+ * public barrel already uses for it.
319
+ *
320
+ * It used to be a narrower local type, `CompiledSubAgent { model?, systemPrompt? }`, and ADR D3
321
+ * deferred projecting it: "a resolver here is carried, not invoked". **That deferral has ended** —
322
+ * `assembleM8CreateOptions` now projects `agents` into `Agent.create`.
323
+ *
324
+ * The narrow type could not have been projected as it stood. `AgentDefinition` requires
325
+ * `description` and `prompt`, and the local shape carried neither; a sub-agent with no description
326
+ * is one the parent model has no basis to delegate to. Every other surface already agreed on the
327
+ * SDK shape — `RuntimeOverrides.agents` (the per-run door that always worked) is
328
+ * `Record<string, AgentDefinition>`, and the same type crosses the barrel as `SubagentDefinition`.
329
+ * The local type was referenced in exactly two places, both of them its own declaration and the
330
+ * field that held it, so adopting the SDK shape removed a mismatch rather than migrating users.
331
+ */
332
+ type CompiledSubAgent = AgentDefinition;
400
333
  /** Compiled agent options ready for SDK Agent.create(). */
401
334
  interface CompiledAgentOptions {
402
335
  model?: string;
@@ -415,14 +348,14 @@ interface CompiledAgentOptions {
415
348
  * Projected into `Agent.create({ local: { settingSources } })` by `assembleM8CreateOptions`
416
349
  * (merged with `cwd`, decoupled from inline skills). Absent ⇒ inline (code) config only.
417
350
  */
418
- settingSources?: readonly SettingSource[];
351
+ settingSources?: readonly GatedSettingSource[];
419
352
  /**
420
353
  * Foreign configuration dialects, already authorised (usetheokit/theokit#634).
421
354
  *
422
355
  * Resolved at compile time by `resolveCompatSources`, exactly like `settingSources`: a value here
423
356
  * can only hold a source some posture granted, so the adapter projects rather than decides.
424
357
  */
425
- compatSources?: readonly ResolvedCompatSource[];
358
+ compatSources?: readonly GatedCompatSource[];
426
359
  /**
427
360
  * #686 — the consumer's pre-spawn approval gate, forwarded to `Agent.create({ local: { hooks } })`.
428
361
  *
@@ -432,12 +365,58 @@ interface CompiledAgentOptions {
432
365
  */
433
366
  hookApproval?: HookApprovalGate;
434
367
  /** Code `Plugin` objects forwarded to `Agent.create({ plugins })` (lifecycle-hook seam). */
435
- plugins?: readonly unknown[];
368
+ /**
369
+ * Code plugins — `{ name, register }` objects registered with the SDK's lifecycle-hook seam.
370
+ *
371
+ * `readonly unknown[]` is what let the WRONG shape through silently: a consumer who read the
372
+ * Claude Code documentation passed `[{ type: 'local', path: './p' }]`, the compiler accepted it,
373
+ * and the agent ran with the plugin absent. `assertCodePlugins` refuses it at the projection, and
374
+ * the type says what belongs here.
375
+ *
376
+ * NOT the filesystem-bundle form. A bundle is declared by living in a `plugins/` directory under
377
+ * `.theokit/` or `.claude/`, where its `skills/` and `agents/` are discovered.
378
+ */
379
+ plugins?: readonly CodePlugin[];
380
+ /**
381
+ * B-060 — an external session store (Postgres / Redis / KV / durable object), used by the SDK as
382
+ * the PRIMARY session store and resume source.
383
+ *
384
+ * Without it a serverless deployment resumed from a filesystem that no longer exists, and a
385
+ * multi-pod one resumed from whichever host happened to take the request. The only way to reach
386
+ * it was importing `@theokit/sdk` directly — the one thing this layer's doctrine forbids, so the
387
+ * doctrine and the capability disagreed and the consumer paid.
388
+ *
389
+ * Typed against the SDK's own `SessionStore` rather than restated here: a hand-written copy that
390
+ * drifts by one method stops fitting, which the mirrored `permissionMode` field measured one item
391
+ * earlier.
392
+ */
393
+ sessionStore?: SessionStore;
394
+ /**
395
+ * B-056 — the callback that sees every tool call the earlier steps did not resolve.
396
+ *
397
+ * The SDK's engine is fail-closed: an unmatched call resolves to `ask`, and an ABSENT gate blocks
398
+ * it. So the value of declaring one is not that unresolved calls stop being approved — they never
399
+ * were — it is that they reach somebody who can decide instead of being refused with nobody to
400
+ * consult. A tool added after the approvals were written keeps defaulting to asking.
401
+ *
402
+ * Typed against the SDK's `PermissionGate`, not restated: its decision shape is veto-or-allow, and
403
+ * a hand-written copy would be the place an `updatedInput` field gets invented for a seam that
404
+ * discards it.
405
+ */
406
+ canUseTool?: PermissionGate;
436
407
  tools: CompiledTool[];
437
408
  agents: Record<string, CompiledSubAgent>;
438
409
  memory?: MemoryOptions | MemorySettings;
439
410
  skills?: SkillsSettings;
440
411
  context?: ContextSettings;
412
+ /**
413
+ * B-072 — OpenTelemetry settings, projected onto `Agent.create({ telemetry })`.
414
+ *
415
+ * Typed against the SDK's `TelemetrySettings` rather than restated, for the reason `canUseTool`
416
+ * above gives about `PermissionGate`: a hand-written copy is where a field gets invented for a
417
+ * seam that discards it, and this one has six keys with real defaults behind them.
418
+ */
419
+ telemetry?: TelemetrySettings;
441
420
  /**
442
421
  * M7 — run-context injected into every tool handler's `ctx.context` by the theokit adapter
443
422
  * (`buildSdkTools` wrapper). Populated by `defineAgent({ context })` (functional surface).
@@ -475,4 +454,4 @@ interface CompiledAgentOptions {
475
454
  skillsResolver?: SkillsSelection;
476
455
  }
477
456
 
478
- export { type CompiledAgentOptions as C, type Guardrail as G, type HookApprovalGate as H, type ProjectSettingsGrant as P, type ResolvedCompatSource as R, type SkillsSelection as S, type ToolWalkResult as T, UntrustedSettingSourceError as U, type SettingSourcesSelection as a, type CompiledTool as b, type CompatSurface as c, CostBudgetExceededError as d, type GuardrailAction as e, type GuardrailPhase as f, type GuardrailResult as g, GuardrailViolationError as h, type HookApprovalRequest as i, HookGateUnsupportedError as j, type SettingSourceCapability as k, type SkillsRequestContext as l, type ToolboxWalkResult as m, compileTools as n, resolveEnabledSkills as o, resolveSettingSources as p, resolveCompatSources as r };
457
+ export { type CodePlugin as C, type Guardrail as G, type HookApprovalGate as H, MalformedGuardrailResultError as M, type SkillsSelection as S, type ToolWalkResult as T, UnreadableTextPayloadError as U, type CompiledAgentOptions as a, type CompiledTool as b, CompatImportUnsupportedError as c, CostBudgetExceededError as d, type GuardrailAction as e, GuardrailError as f, type GuardrailPhase as g, type GuardrailResult as h, GuardrailViolationError as i, type HookApprovalRequest as j, HookGateUnsupportedError as k, type SkillsRequestContext as l, type ToolboxWalkResult as m, compileTools as n, resolveEnabledSkills as r };
package/dist/ask.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { TheokitAgentError } from '@theokit/sdk/errors';
2
+ export { TheokitAgentError } from '@theokit/sdk/errors';
2
3
 
3
4
  /**
4
5
  * M77 — the ask channel: the agent asks, a human answers, the turn waits.