theorum 0.1.14 → 1.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 (229) hide show
  1. package/README.md +178 -89
  2. package/esm/mod.d.ts +21 -11
  3. package/esm/mod.js +15 -8
  4. package/esm/src/cli/commands/bench.js +6 -3
  5. package/esm/src/cli/commands/fuzz-canary.d.ts +13 -0
  6. package/esm/src/cli/commands/fuzz-canary.js +195 -0
  7. package/esm/src/cli/commands/fuzz-guardrails.d.ts +3 -5
  8. package/esm/src/cli/commands/fuzz-guardrails.js +4 -581
  9. package/esm/src/cli/commands/profile.js +25 -14
  10. package/esm/src/cli/commands/run.d.ts +3 -0
  11. package/esm/src/cli/commands/run.js +22 -30
  12. package/esm/src/cli/commands/test.d.ts +10 -1
  13. package/esm/src/cli/commands/test.js +31 -31
  14. package/esm/src/cli/event-log.d.ts +19 -0
  15. package/esm/src/cli/event-log.js +147 -0
  16. package/esm/src/cli/index.js +45 -11
  17. package/esm/src/cli/matrix/synthesizer.d.ts +7 -9
  18. package/esm/src/cli/matrix/synthesizer.js +32 -106
  19. package/esm/src/guardrails/canary-gate.d.ts +20 -0
  20. package/esm/src/guardrails/canary-gate.js +31 -0
  21. package/esm/src/guardrails/canary.d.ts +26 -0
  22. package/esm/src/guardrails/canary.js +139 -0
  23. package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +16 -0
  24. package/esm/src/guardrails/corpus/canary-egress-attacks.js +151 -0
  25. package/esm/src/guardrails/corpus/fuzz-inbound.d.ts +11 -0
  26. package/esm/src/guardrails/corpus/fuzz-inbound.js +216 -0
  27. package/esm/src/guardrails/corpus/inbound-payloads.d.ts +10 -0
  28. package/esm/src/guardrails/corpus/inbound-payloads.js +124 -0
  29. package/esm/src/guardrails/corpus/live-attacks.d.ts +20 -0
  30. package/esm/src/guardrails/corpus/live-attacks.js +232 -0
  31. package/esm/src/guardrails/corpus/mod.d.ts +13 -0
  32. package/esm/src/guardrails/corpus/mod.js +11 -0
  33. package/esm/src/guardrails/corpus/secrets.d.ts +16 -0
  34. package/esm/src/guardrails/corpus/secrets.js +16 -0
  35. package/esm/src/guardrails/corpus/strings.d.ts +27 -0
  36. package/esm/src/guardrails/corpus/strings.js +33 -0
  37. package/esm/src/guardrails/corpus/types.d.ts +37 -0
  38. package/esm/src/guardrails/corpus/types.js +6 -0
  39. package/esm/src/guardrails/egress.d.ts +9 -0
  40. package/esm/src/guardrails/egress.js +36 -0
  41. package/esm/src/guardrails/error.js +6 -4
  42. package/esm/src/guardrails/injection.js +28 -5
  43. package/esm/src/guardrails/live-outbound-gate.d.ts +39 -0
  44. package/esm/src/guardrails/live-outbound-gate.js +180 -0
  45. package/esm/src/guardrails/mod.d.ts +13 -4
  46. package/esm/src/guardrails/mod.js +10 -4
  47. package/esm/src/guardrails/quota.js +1 -1
  48. package/esm/src/guardrails/sanitize.d.ts +11 -15
  49. package/esm/src/guardrails/sanitize.js +40 -49
  50. package/esm/src/guardrails/sensitive.js +2 -1
  51. package/esm/src/guardrails/testing.d.ts +10 -0
  52. package/esm/src/guardrails/testing.js +9 -0
  53. package/esm/src/host/client-turn.d.ts +19 -0
  54. package/esm/src/host/client-turn.js +32 -0
  55. package/esm/src/host/mod.d.ts +5 -3
  56. package/esm/src/host/mod.js +4 -3
  57. package/esm/src/interface/blocks.d.ts +20 -0
  58. package/esm/src/interface/blocks.js +180 -0
  59. package/esm/src/interface/from-profile.d.ts +14 -0
  60. package/esm/src/interface/from-profile.js +104 -0
  61. package/esm/src/interface/inputs.d.ts +8 -0
  62. package/esm/src/interface/inputs.js +127 -0
  63. package/esm/src/interface/mod.d.ts +10 -0
  64. package/esm/src/interface/mod.js +9 -0
  65. package/esm/src/interface/types.d.ts +153 -0
  66. package/esm/src/interface/types.js +13 -0
  67. package/esm/src/kernel/engine/delta.d.ts +24 -2
  68. package/esm/src/kernel/engine/delta.js +519 -29
  69. package/esm/src/kernel/engine/live-inbound.d.ts +9 -0
  70. package/esm/src/kernel/engine/live-inbound.js +17 -0
  71. package/esm/src/kernel/engine/repair.js +1 -1
  72. package/esm/src/kernel/engine/runner/gates.d.ts +1 -1
  73. package/esm/src/kernel/engine/runner/gates.js +7 -7
  74. package/esm/src/kernel/engine/runner/mod.js +13 -13
  75. package/esm/src/kernel/engine/runner/state.d.ts +7 -0
  76. package/esm/src/kernel/engine/runner/steps.d.ts +1 -1
  77. package/esm/src/kernel/engine/runner/steps.js +171 -37
  78. package/esm/src/kernel/engine/runner/stream.d.ts +1 -2
  79. package/esm/src/kernel/engine/runner/stream.js +66 -29
  80. package/esm/src/kernel/engine/session/mod.d.ts +23 -0
  81. package/esm/src/kernel/engine/session/mod.js +205 -0
  82. package/esm/src/kernel/mod.d.ts +9 -10
  83. package/esm/src/kernel/mod.js +6 -8
  84. package/esm/src/kernel/registry/attachments.d.ts +4 -2
  85. package/esm/src/kernel/registry/attachments.js +6 -3
  86. package/esm/src/kernel/registry/catalog.d.ts +3 -16
  87. package/esm/src/kernel/registry/catalog.js +5 -81
  88. package/esm/src/kernel/registry/ingress.d.ts +9 -4
  89. package/esm/src/kernel/registry/ingress.js +73 -63
  90. package/esm/src/kernel/registry/profiles.d.ts +35 -12
  91. package/esm/src/kernel/registry/profiles.js +159 -66
  92. package/esm/src/kernel/registry/provider-request.js +11 -7
  93. package/esm/src/kernel/registry/resolve.d.ts +5 -6
  94. package/esm/src/kernel/registry/resolve.js +100 -70
  95. package/esm/src/kernel/registry/vault.d.ts +12 -7
  96. package/esm/src/kernel/registry/vault.js +30 -8
  97. package/esm/src/kernel/schema.d.ts +145 -0
  98. package/esm/src/kernel/schema.js +462 -0
  99. package/esm/src/kernel/stop.d.ts +15 -10
  100. package/esm/src/kernel/stop.js +5 -5
  101. package/esm/src/kernel/tools/execute.d.ts +45 -0
  102. package/esm/src/kernel/tools/execute.js +363 -0
  103. package/esm/src/kernel/tools/harness.d.ts +8 -0
  104. package/esm/src/kernel/tools/harness.js +44 -0
  105. package/esm/src/kernel/tools/invoke.d.ts +10 -0
  106. package/esm/src/kernel/tools/invoke.js +83 -0
  107. package/esm/src/kernel/tools/mod.d.ts +11 -0
  108. package/esm/src/kernel/tools/mod.js +10 -0
  109. package/esm/src/kernel/tools/project.d.ts +12 -0
  110. package/esm/src/kernel/tools/project.js +34 -0
  111. package/esm/src/kernel/tools/registry.d.ts +23 -0
  112. package/esm/src/kernel/tools/registry.js +71 -0
  113. package/esm/src/kernel/tools/resolve.d.ts +29 -0
  114. package/esm/src/kernel/tools/resolve.js +262 -0
  115. package/esm/src/kernel/tools/schema.d.ts +13 -0
  116. package/esm/src/kernel/tools/schema.js +159 -0
  117. package/esm/src/kernel/tools/types.d.ts +216 -0
  118. package/esm/src/kernel/tools/types.js +9 -0
  119. package/esm/src/kernel/types.d.ts +338 -193
  120. package/esm/src/observability/trace-attach.d.ts +6 -4
  121. package/esm/src/observability/trace-attach.js +39 -25
  122. package/esm/src/observability/trace-record.d.ts +11 -9
  123. package/esm/src/observability/trace-record.js +36 -23
  124. package/esm/src/observability/trace-usage.d.ts +10 -3
  125. package/esm/src/observability/trace-usage.js +70 -17
  126. package/esm/src/observability/trace.d.ts +9 -1
  127. package/esm/src/observability/trace.js +11 -3
  128. package/esm/src/presets/google/speech-voices.d.ts +11 -0
  129. package/esm/src/presets/google/speech-voices.js +41 -0
  130. package/esm/src/presets/google.d.ts +36 -24
  131. package/esm/src/presets/google.js +50 -63
  132. package/esm/src/presets/mod.d.ts +2 -2
  133. package/esm/src/presets/mod.js +1 -1
  134. package/esm/src/providers/create-provider.d.ts +14 -14
  135. package/esm/src/providers/create-provider.js +55 -23
  136. package/esm/src/providers/google/interactions/framing.d.ts +15 -0
  137. package/esm/src/providers/google/interactions/framing.js +208 -0
  138. package/esm/src/providers/google/interactions/mod.d.ts +7 -0
  139. package/esm/src/providers/google/interactions/mod.js +7 -0
  140. package/esm/src/providers/google/interactions/stream.d.ts +83 -0
  141. package/esm/src/providers/google/interactions/stream.js +588 -0
  142. package/esm/src/providers/google/keys.d.ts +26 -0
  143. package/esm/src/providers/{keys.js → google/keys.js} +19 -31
  144. package/esm/src/providers/google/live/framing.d.ts +46 -0
  145. package/esm/src/providers/google/live/framing.js +515 -0
  146. package/esm/src/providers/google/live/openapi-schema.d.ts +6 -0
  147. package/esm/src/providers/google/live/openapi-schema.js +45 -0
  148. package/esm/src/providers/google/live/session.d.ts +25 -0
  149. package/esm/src/providers/google/live/session.js +134 -0
  150. package/esm/src/providers/google/live/stream.d.ts +36 -0
  151. package/esm/src/providers/google/live/stream.js +201 -0
  152. package/esm/src/providers/google/urls.d.ts +6 -0
  153. package/esm/src/providers/google/urls.js +6 -0
  154. package/esm/src/providers/local/local.d.ts +30 -0
  155. package/esm/src/providers/{local.js → local/local.js} +66 -126
  156. package/esm/src/providers/local/mod.d.ts +9 -0
  157. package/esm/src/providers/local/mod.js +9 -0
  158. package/esm/src/providers/mod.d.ts +6 -3
  159. package/esm/src/providers/mod.js +3 -1
  160. package/esm/src/providers/openrouter/chat.d.ts +87 -0
  161. package/esm/src/providers/{openrouter.js → openrouter/chat.js} +70 -229
  162. package/esm/src/providers/openrouter/image.d.ts +34 -0
  163. package/esm/src/providers/openrouter/image.js +286 -0
  164. package/esm/src/providers/openrouter/openai/chat-payload.d.ts +24 -0
  165. package/esm/src/providers/openrouter/openai/chat-payload.js +60 -0
  166. package/esm/src/providers/openrouter/openai/compat.d.ts +47 -0
  167. package/esm/src/providers/openrouter/openai/compat.js +194 -0
  168. package/esm/src/providers/openrouter/openai/image-payload.d.ts +18 -0
  169. package/esm/src/providers/openrouter/openai/image-payload.js +84 -0
  170. package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +22 -0
  171. package/esm/src/providers/openrouter/openai/sdk-messages.js +95 -0
  172. package/esm/src/providers/openrouter/resolve-api-key.d.ts +9 -0
  173. package/esm/src/providers/openrouter/resolve-api-key.js +24 -0
  174. package/esm/src/providers/openrouter/speech.d.ts +23 -0
  175. package/esm/src/providers/{speech.js → openrouter/speech.js} +32 -55
  176. package/esm/src/providers/probe.d.ts +1 -0
  177. package/esm/src/providers/probe.js +22 -0
  178. package/esm/src/providers/shared/pcm.d.ts +12 -0
  179. package/esm/src/providers/{pcm.js → shared/pcm.js} +16 -3
  180. package/esm/src/providers/shared/sse.d.ts +18 -0
  181. package/esm/src/providers/shared/sse.js +87 -0
  182. package/esm/src/providers/shared/tool-args.d.ts +17 -0
  183. package/esm/src/providers/shared/tool-args.js +45 -0
  184. package/esm/src/providers/shared/upstream-tap.d.ts +5 -0
  185. package/esm/src/providers/{google-tap.js → shared/upstream-tap.js} +4 -7
  186. package/esm/src/providers/shared/upstream-tape.d.ts +6 -0
  187. package/esm/src/providers/{gemini-tape.js → shared/upstream-tape.js} +12 -22
  188. package/esm/src/providers/types.d.ts +27 -0
  189. package/esm/src/providers/types.js +1 -0
  190. package/package.json +11 -7
  191. package/docs/cli.md +0 -97
  192. package/docs/guardrails.md +0 -178
  193. package/docs/host.md +0 -97
  194. package/docs/kernel.md +0 -404
  195. package/docs/observability.md +0 -105
  196. package/docs/openrouter.md +0 -125
  197. package/docs/presets-google.md +0 -91
  198. package/docs/presets.md +0 -88
  199. package/docs/providers.md +0 -201
  200. package/docs/streaming.md +0 -96
  201. package/esm/src/kernel/engine/boundary.d.ts +0 -10
  202. package/esm/src/kernel/engine/boundary.js +0 -55
  203. package/esm/src/kernel/engine/runner/tools.d.ts +0 -13
  204. package/esm/src/kernel/engine/runner/tools.js +0 -198
  205. package/esm/src/kernel/registry/tools.d.ts +0 -12
  206. package/esm/src/kernel/registry/tools.js +0 -36
  207. package/esm/src/providers/expose-for-tests.d.ts +0 -1
  208. package/esm/src/providers/expose-for-tests.js +0 -25
  209. package/esm/src/providers/gemini-tape.d.ts +0 -2
  210. package/esm/src/providers/google-tap.d.ts +0 -3
  211. package/esm/src/providers/interactions.d.ts +0 -5
  212. package/esm/src/providers/interactions.js +0 -169
  213. package/esm/src/providers/keys.d.ts +0 -19
  214. package/esm/src/providers/local.d.ts +0 -29
  215. package/esm/src/providers/openrouter-mod.d.ts +0 -13
  216. package/esm/src/providers/openrouter-mod.js +0 -12
  217. package/esm/src/providers/openrouter-payload.d.ts +0 -39
  218. package/esm/src/providers/openrouter-payload.js +0 -195
  219. package/esm/src/providers/openrouter.d.ts +0 -15
  220. package/esm/src/providers/pcm.d.ts +0 -7
  221. package/esm/src/providers/provider.d.ts +0 -15
  222. package/esm/src/providers/provider.js +0 -176
  223. package/esm/src/providers/speech.d.ts +0 -23
  224. package/esm/src/providers/sse.d.ts +0 -7
  225. package/esm/src/providers/sse.js +0 -55
  226. package/esm/src/streaming/mod.d.ts +0 -9
  227. package/esm/src/streaming/mod.js +0 -8
  228. /package/esm/src/{streaming → host}/readStreamingJsonStringField.d.ts +0 -0
  229. /package/esm/src/{streaming → host}/readStreamingJsonStringField.js +0 -0
package/README.md CHANGED
@@ -10,9 +10,11 @@
10
10
 
11
11
  # THEORUM: The Flat Agent Kernel
12
12
 
13
+ **Current release: `1.0.0`** (`jsr:@theorum/core` / npm `theorum`).
14
+
13
15
  > **"Profiles describe the contract. Providers move bytes. The runner enforces the turn."**
14
16
 
15
- THEORUM is a compact TypeScript agent kernel for apps that need deterministic agent execution without embedding product logic inside the runtime. It gives a host application one runner, typed profiles, multimodal input normalization, dynamic tool dispatch, provider adapters, trace sinks, and guardrail hooks.
17
+ THEORUM is a compact TypeScript agent kernel for apps that need deterministic agent execution without embedding product logic inside the runtime. It gives a host application one runner, typed profiles, multimodal input normalization, a registered tool system with per-turn gating, provider adapters, trace sinks, and guardrail hooks.
16
18
 
17
19
  The package is intentionally **not** an agent product. It ships no app profiles, no prompts, no secrets, no database policy, no business rules, and no channel-specific UX. Those belong in the host application.
18
20
 
@@ -27,7 +29,7 @@ OpenRouter chat transport is powered by Vercel AI SDK Core under the adapter. TH
27
29
  profiles = "Host-owned declarations for model, inputs, outputs, tools, and guardrails"
28
30
  runner = "Single deterministic execution path for one agent turn"
29
31
  providers = "createProvider routes protocol/provider; adapters stay internal"
30
- tools = "Profile allowlist ceiling plus per-turn dynamic declarations"
32
+ tools = "Profile allowlist ceiling plus per-turn opt-in gates"
31
33
  egress = "Typed host hook for outbound disclosure checks and repair loops"
32
34
  traces = "Host-injected sinks; no environment variables or bundled destinations"
33
35
 
@@ -59,7 +61,7 @@ flowchart TD
59
61
  Resolve["resolveTurn"]
60
62
  Guard["sanitize + canary + egress"]
61
63
  Runner["runTurn"]
62
- ToolLoop["dynamic tool loop"]
64
+ ToolLoop["registered tool loop"]
63
65
  Repair["repair attempts"]
64
66
  end
65
67
 
@@ -82,27 +84,66 @@ flowchart TD
82
84
  Runner --> TraceSink
83
85
  ```
84
86
 
85
- Hosts bind transports with `createProvider(profile, { gemini, openRouter })`. One door; protocol/provider (and speech role) pick the adapter.
87
+ Hosts bind transports with `createProvider(profile, { gemini, openAiGateway })`. One door; protocol/provider (and speech role) pick the adapter.
88
+
89
+ ### Turn execution and tools
86
90
 
87
- ### Turn Lifecycle
91
+ One turn is a single pipeline. Tools share `executeRegisteredTool` with `invokeTool`; compaction,
92
+ guardrails, and streaming attach at different layers.
88
93
 
89
94
  ```mermaid
90
- stateDiagram-v2
91
- [*] --> ResolveProfile: host sends TurnRequest
92
- ResolveProfile --> NormalizeInput: profile input rules
93
- NormalizeInput --> BindBoundary: canary + user data fencing
94
- BindBoundary --> ProviderStream: ModelProvider.complete
95
- ProviderStream --> ToolDispatch: tool event
96
- ToolDispatch --> ProviderStream: autonomous loop continues
97
- ProviderStream --> EgressGate: final candidate
98
- EgressGate --> RepairTurn: blocked + retry budget
99
- RepairTurn --> ProviderStream
100
- EgressGate --> ValidateOutput: clear
101
- ValidateOutput --> EmitEvents: text/media/structured/tokens/done
102
- EmitEvents --> Trace: host sink receives audit record
103
- Trace --> [*]
95
+ flowchart TD
96
+ subgraph Host["Host application"]
97
+ REG["registerTool at startup"]
98
+ REQ["TurnRequest<br/>(tools gate · continueFrom · …)"]
99
+ UI["Pause UI"]
100
+ INV["invokeTool(resume)"]
101
+ end
102
+
103
+ subgraph Ingress["runTurn ingress"]
104
+ SAN["sanitizeTurnRequest"]
105
+ RES["resolveTurn TurnToolSnapshot"]
106
+ CB{"timing: before<br/>compact history?"}
107
+ SYS["system + canary<br/>(+ CONTINUE_INSTRUCTION if continueFrom)"]
108
+ end
109
+
110
+ subgraph Attempt["Attempt (egress / validation retries)"]
111
+ subgraph Steps["maxSteps loop"]
112
+ PL["provider.complete<br/>(wire schemas + history)"]
113
+ TE["executeRegisteredTool"]
114
+ HK["formatToolResult → history<br/>or Interactions continuation"]
115
+ end
116
+ EG["egress + validation<br/>(assistant text in attempt)"]
117
+ end
118
+
119
+ OUT["done<br/>(stop · tokens · compaction signal?)"]
120
+ TR["trace record"]
121
+
122
+ REG -.-> TE
123
+ REQ --> SAN --> RES --> CB --> SYS --> Steps
124
+ PL -->|model tool calls| TE
125
+ TE -->|complete| HK --> PL
126
+ TE -->|pause · exit step loop| EG
127
+ UI --> INV --> TE
128
+ Steps -->|loop ends| EG
129
+ EG -->|repair retry| SAN
130
+ EG --> OUT --> TR
131
+
132
+ INV -.->|separate entry · no provider| TE
104
133
  ```
105
134
 
135
+ **How the verticals meet tools:**
136
+
137
+ | Vertical | Where it runs | Tool interaction |
138
+ | --- | --- | --- |
139
+ | **Compaction** | Before turn (`timing: 'before'`) or signal on `done` (`timing: 'after'`) | Summarizes `TurnHistoryMessage` history — including `tool_calls` and `role: 'tool'` rows — not the live registry or mid-turn wire snapshot |
140
+ | **Guardrails** | Ingress sanitize; egress/validation after the step loop | Sanitizes user text and history content; tool catalog descriptions and model-emitted arguments are host/registration concerns. Egress inspects assistant **text** in the attempt, not tool progress events |
141
+ | **Streaming** | Provider stream + tool handler generators | Provider tool-call events buffer until execution; handler `progress` / `trace` / `artifact` / `warning` phases stream during `executeRegisteredTool`. `streamThoughts: false` filters thoughts only |
142
+ | **Resumption** | Two paths — do not mix | **`stop.kind: 'tool'`** → host UI → `invokeTool` with `resume` (skips turn gate). **`length` / `stream_incomplete` / …** → new `runTurn` with `continueFrom` (+ `CONTINUE_INSTRUCTION` in system); host must re-gate tools |
143
+
144
+ On tool pause the `maxSteps` loop exits (`stop.kind: 'tool'`), egress may still evaluate
145
+ buffered assistant text from that attempt, then the turn emits terminal `done`.
146
+
106
147
  ---
107
148
 
108
149
  ## Install
@@ -143,6 +184,7 @@ import {
143
184
  } from "jsr:@theorum/core";
144
185
 
145
186
  const profile = defineProfile({
187
+ type: "text",
146
188
  id: "assistant.basic",
147
189
  identity: {
148
190
  handle: "assistant",
@@ -155,18 +197,19 @@ const profile = defineProfile({
155
197
  config: {
156
198
  hostFastModel: {
157
199
  apiId: "perplexity/sonar",
158
- openRouterId: "perplexity/sonar",
159
200
  thinking: { on: "high", off: "minimal" },
160
201
  thinkingLevels: ["minimal", "low", "medium", "high"],
161
202
  summaries: { on: "auto", off: "none" },
162
203
  maxOutputTokens: 8192,
163
204
  temperature: 1,
164
- keyBuiltins: [],
205
+ builtInTools: [],
165
206
  },
166
207
  },
167
208
  thinking: "minimal",
168
209
  maxSteps: 1,
169
210
  },
211
+ tools: { allow: [] },
212
+ inputs: { text: true },
170
213
  outputs: {
171
214
  streaming: { streamThoughts: false },
172
215
  },
@@ -195,38 +238,52 @@ for await (const event of runTurn(
195
238
 
196
239
  ---
197
240
 
198
- ## Dynamic Tools
241
+ ## Registered Tools
199
242
 
200
- THEORUM separates tool concerns into three layers.
243
+ THEORUM separates tool concerns into four layers.
201
244
 
202
245
  | Layer | Owner | Purpose |
203
246
  | :--- | :--- | :--- |
204
- | **Access** | Profile | Hard ceiling: the agent cannot use a tool outside `profile.tools.allow`. |
205
- | **Visibility** | Turn request | Per-turn declarations: T0/T1/T2 schemas can be passed or loaded dynamically. |
206
- | **Permission** | Host app | `auto`, `session_consent`, and `always_confirm` determine whether execution pauses. |
247
+ | **Catalog** | Host (startup) | `registerTool` schema, handler, access, loadTier, permission |
248
+ | **Allow** | Profile | Custom: `tools.allow`. Builtins: `model.config.*.builtInTools` |
249
+ | **Visibility** | Registry + profile | `loadTier` on tool; T1 via `tools.t1Policy`; T2 via `tools.t2Loader` |
250
+ | **Permission** | Host app | `auto`, `session_consent`, and `always_confirm` determine whether execution pauses |
207
251
 
208
252
  ```ts
209
- const dynamicTools = [
210
- {
211
- name: "lookup_order",
212
- description: "Fetch order state from the host application.",
213
- loadTier: "T1",
214
- permissionTier: "session_consent",
215
- parameters: {
216
- type: "object",
217
- properties: { orderId: { type: "string" } },
218
- required: ["orderId"],
219
- },
220
- handler: async (args) => ({
221
- status: "ok",
222
- finding: "Order is in transit.",
223
- data: { orderId: args.orderId, state: "in_transit" },
224
- }),
225
- },
226
- ] as const;
253
+ import { z } from 'zod';
254
+ import { registerTool, invokeTool, runTurn } from 'theorum';
255
+
256
+ registerTool({
257
+ type: 'function',
258
+ name: 'lookup_order',
259
+ description: 'Fetch order state from the host application.',
260
+ category: 'operations',
261
+ access: 'read-only',
262
+ paths: ['*'],
263
+ loadTier: 'T0',
264
+ permission: 'session_consent',
265
+ input: z.object({ orderId: z.string() }),
266
+ output: z.object({ finding: z.string() }),
267
+ handler: async (input) => ({
268
+ finding: `Order ${input.orderId} is in transit.`,
269
+ }),
270
+ });
271
+
272
+ // Profile allow
273
+ tools: { allow: ['lookup_order', 'load_tools'] }
274
+
275
+ runTurn({ profile, input: { text: '…' } }, provider);
276
+
277
+ // Host resume (interactive, confirmation, permission)
278
+ invokeTool({ profile, name: 'ask_user', input: { kind: 'confirm', prompt: 'Proceed?' }, resume: { value: true } });
227
279
  ```
228
280
 
229
- The host owns the handler and authorization state. The kernel only enforces the declared contract.
281
+ The host owns handlers and authorization state. The kernel enforces the declared contract
282
+ via shared `executeRegisteredTool` for model tool calls and `invokeTool` for host resumes.
283
+
284
+ Function tools require **Zod** input/output schemas at registration time.
285
+
286
+ **Migration:** [`docs/MIGRATION-tool-system.md`](docs/MIGRATION-tool-system.md) (breaking changes from `dynamicTools` / `ToolEnvelope`).
230
287
 
231
288
  ---
232
289
 
@@ -236,22 +293,28 @@ Inbound and outbound safety are generic kernel hooks.
236
293
 
237
294
  ```ts
238
295
  const guardedProfile = defineProfile({
296
+ type: "text",
239
297
  id: "assistant.guarded",
298
+ identity: { handle: "guarded", system: "You are a careful assistant." },
240
299
  model: {
300
+ protocol: "openAi",
301
+ provider: "openrouter",
241
302
  allow: ["hostFastModel"],
242
303
  config: {
243
304
  hostFastModel: {
244
305
  apiId: "perplexity/sonar",
245
- openRouterId: "perplexity/sonar",
246
306
  thinking: { on: "high", off: "minimal" },
247
307
  thinkingLevels: ["minimal", "low", "medium", "high"],
248
308
  summaries: { on: "auto", off: "none" },
249
309
  maxOutputTokens: 8192,
250
310
  temperature: 1,
251
- keyBuiltins: [],
311
+ builtInTools: [],
252
312
  },
253
313
  },
314
+ thinking: "minimal",
254
315
  },
316
+ tools: { allow: [] },
317
+ inputs: { text: true },
255
318
  guardrails: {
256
319
  egress: {
257
320
  onBlock: "reject_to_agent",
@@ -287,7 +350,7 @@ import { createProvider, runTurn } from "jsr:@theorum/core";
287
350
 
288
351
  const provider = createProvider(profile, {
289
352
  gemini: { vault: hostGeminiKeyVault, fetch },
290
- openRouter: { apiKey: hostSecrets.openRouterApiKey },
353
+ openAiGateway: { apiKey: hostSecrets.openRouterApiKey },
291
354
  // openAi + local — optional; default baseUrl http://127.0.0.1:11434
292
355
  local: { baseUrl: hostResolvedLocalBaseUrl },
293
356
  });
@@ -297,7 +360,7 @@ for await (const event of runTurn({ profile: profile.id, input: { text: "…" }
297
360
  }
298
361
  ```
299
362
 
300
- `createProvider` routes from `profile.model.protocol` / `provider`. Speech roles use the same call — Interactions when Google, `/audio/speech` when openAi/openrouter (same `openRouter` credentials).
363
+ `createProvider` routes from `profile.model.protocol` / `provider`. Speech roles use the same call — Interactions when Google, `/audio/speech` when openAi/openrouter (same `openAiGateway` credentials).
301
364
 
302
365
  | Profile | Transport |
303
366
  | :--- | :--- |
@@ -308,17 +371,14 @@ for await (const event of runTurn({ profile: profile.id, input: { text: "…" }
308
371
 
309
372
  Local adapters take an optional `baseUrl` (default `http://127.0.0.1:11434`). THEORUM does not read `OLLAMA_HOST`; hosts that honor that env should resolve it and pass `local.baseUrl`. History `parts` (including images) are mapped on the wire; `done` events include a normalized `stop` from the OpenAI `finish_reason`.
310
373
 
311
- OpenRouter uses Vercel AI SDK Core inside THEORUM's provider adapter. That stack
312
- loads **lazily on the first `complete` call** for `openAi` + `openrouter` chat
313
- not when importing THEORUM, and not for Google or local providers. The adapter
314
- still emits THEORUM `TurnEvent` values and preserves raw provider evidence for
315
- citations/provenance where the normalized SDK stream does not expose enough detail.
316
-
317
- Advanced OpenRouter exports live under `theorum/openrouter` (`createOpenRouterProvider`,
318
- `toOpenRouterPayload`, …). Prefer `createProvider` for turns unless the host needs
319
- to wire the OpenRouter adapter directly. Direct local construction is also available
320
- as `createLocalProvider` from the main / providers entrypoints. Importing
321
- `theorum/openrouter` loads the Vercel SDK immediately.
374
+ OpenRouter uses Vercel AI SDK Core inside THEORUM's provider adapter. Provider
375
+ adapters load **lazily on the first `complete` call** for the selected transport
376
+ not when importing THEORUM. Importing `createProvider` alone does not pull in
377
+ Google Interactions, OpenRouter/AI SDK, speech, or local adapter graphs.
378
+ The OpenRouter adapter still emits THEORUM `TurnEvent` values and preserves raw
379
+ provider evidence for citations/provenance where the normalized SDK stream does
380
+ not expose enough detail. Use `createProvider` for all turns; adapter modules
381
+ stay internal to the providers package.
322
382
 
323
383
  ---
324
384
 
@@ -328,14 +388,16 @@ as `createLocalProvider` from the main / providers entrypoints. Importing
328
388
  | :--- | :--- |
329
389
  | `jsr:@theorum/core` / `theorum` | Main kernel API: profiles, schemas, runner, core types, provider constructors. |
330
390
  | `jsr:@theorum/core/kernel` / `theorum/kernel` | Profile/turn types, tool catalog, `requireModelSpec`, thinking clamps over host model maps. |
331
- | `jsr:@theorum/core/providers` / `theorum/providers` | `createProvider` + Gemini vault types. |
332
- | `jsr:@theorum/core/openrouter` / `theorum/openrouter` | Direct OpenRouter provider adapter and payload helpers (advanced). |
333
- | `jsr:@theorum/core/guardrails` / `theorum/guardrails` | Sanitization, public error mapping, inbound injection/sensitive-data primitives. |
391
+ | `jsr:@theorum/core/providers` / `theorum/providers` | `createProvider` + Gemini vault types + host option bags. |
392
+ | `jsr:@theorum/core/providers/local` / `theorum/providers/local` | Direct local OpenAI-compat adapter (`createLocalProvider`, `DEFAULT_LOCAL_BASE_URL`). |
393
+ | `jsr:@theorum/core/guardrails` / `theorum/guardrails` | Sanitization, canary/egress gates, public error mapping, inbound injection/sensitive-data primitives. |
394
+ | `jsr:@theorum/core/guardrails/testing` / `theorum/guardrails/testing` | Adversarial corpus + fuzz helpers (test/harness only). |
334
395
  | `jsr:@theorum/core/observability` / `theorum/observability` | Trace sinks and trace record helpers. |
335
396
  | `jsr:@theorum/core/host` / `theorum/host` | Optional Deno HTTP helpers (`json`, status mapping, cutout mint flush). |
336
397
  | `jsr:@theorum/core/cli` / `theorum/cli` | Profile inspection and stress-test CLI (`theorum` binary on npm). |
337
398
  | `jsr:@theorum/core/presets` / `theorum/presets` | Optional convenience packs (`registerGooglePreset`, …). |
338
- | `jsr:@theorum/core/presets/google` / `theorum/presets/google` | Google builtins (search/maps/urlContext) + Interactions/OpenRouter wire metadata. |
399
+ | `jsr:@theorum/core/presets/google` / `theorum/presets/google` | Google builtins (search/maps/urlContext/codeExecution) + Interactions/OpenRouter wire metadata. |
400
+ | `jsr:@theorum/core/interface` / `theorum/interface` | Headless profile-driven runtime UI spec (`interfaceFromProfile`, `foldTurnEvents`, input validation). |
339
401
 
340
402
  Internal files remain present in source for maintainability, but package consumers should use the public entrypoints above.
341
403
 
@@ -346,39 +408,55 @@ Named exports from the root barrel (same symbols hosts get from `theorum` /
346
408
 
347
409
  | Group | Symbols |
348
410
  | --- | --- |
349
- | Guardrails errors | `describeError`, `isAbortError`, `publicError`, `TheorumError`, `throwIfAborted`, `toErrorEvent` |
411
+ | Guardrails errors | `describeError`, `isAbortError`, `publicError`, `TheorumError`, `throwIfAborted`, `toErrorEvent`, `PUBLIC_CANARY` |
350
412
  | Quota | `QuotaSlotStatus`, `clientIp`, `quotaMessage`, `releaseSlot`, `resetSlots`, `skipQuota`, `takeSlot` |
351
- | Sanitize | `PROJECT_ID_MAX`, `sanitizeProjectId`, `sanitizeText`, `sanitizeTurnRequest` |
413
+ | Sanitize | `PROJECT_ID_MAX`, `sanitizeProjectId`, `sanitizeText`, `sanitizeTurnRequest`, `sanitizeTurnRequestForTrace`, `redactSensitiveOnly` |
414
+ | Canary / egress | `mintCanary`, `bindCanary`, `wrapUserData`, `scanTextForCanaryLeak`, `redactCanary`, `OMIT_CANARY`, `createCanaryStreamGate`, `eventHasCanary`, `createCanaryGateSession`, `filterCanaryGatedEvents`, `CanaryGateResult`, `CanaryGateSession`, `CanaryStreamGate`, `standardEgressEnforce`, `createLiveOutboundGateSession`, `processLiveOutboundBatch`, `finalizeLiveOutboundTurn`, `LiveOutboundBatchResult`, `LiveOutboundGateSession` |
352
415
  | Compaction | `CompactionSplit`, `CompactionTokens`, `compactionMeter`, `compactionNeeded`, `estimateHistoryTokens`, `HISTORY_MEDIA_TOKENS`, `HISTORY_TEXT_ENCODING`, `resolveCompactionTokens`, `resolveHistoryTokens`, `shouldCompact`, `splitForCompaction` |
353
- | Runner | `runTurn` |
354
- | Catalog | `CATALOG`, `clampThinkingLevel`, `clampThinkingLevelForApiId`, `mediaKindForMime`, `getTool`, `listBuiltinIds`, `mimeAllowed`, `mimeEssence`, `modelEntryByApiId`, `registerTools`, `requireModelSpec`, `resetTools` |
355
- | Profiles | `ProfileDefinition`, `clearProfiles`, `defineProfile`, `getProfile`, `hasProfile`, `listProfiles`, `registerProfile`, `registerProfiles`, `projectProfile`, `resolveTurn` |
356
- | Structured | `getStructured`, `registerStructured`, `executeTool` |
357
- | Stop / resume | `ProfileResumeSpec`, `TurnContinueFrom`, `TurnStop`, `TurnStopKind`, `AUTO_CONTINUE_DELAY_MS`, `CONTINUE_INSTRUCTION`, `DEFAULT_AUTO_CONTINUE`, `GenerationStopError`, `isGenerationStopError`, `isResumeableStop`, `isUserCancelledStop`, `shouldAutoContinue`, `turnStopFromClientStreamEnd`, `turnStopFromInteractionStatus`, `turnStopFromOpenRouter` |
416
+ | Runner | `runTurn`, `runSession`, `RunSessionOptions`, `prepareLiveInboundText` |
417
+ | Attachments | `assertAttachmentLimits`, `fileTooLargeMessage`, `maxBytesForMime`, `requireMediaLimits`, `resolveMediaLimits`, `sanitizeCsvText`, `sanitizeTurnBlobs`, `sanitizeTurnBlobsForProfile`, `tooManyFilesMessage`, `turnTooLargeMessage` |
418
+ | Interface (headless) | `interfaceFrom`, `interfaceFromProfile`, `interfaceFromProjected`, `inputsFromSpec`, `attachmentAcceptAttr`, `validateProfileInputs`, `pickMediaRecorderMime`, `buildUserTurnBlocks`, `foldTurnEvents`, `foldConversationTurn`, `resetBlockIds`, `streamThoughtsEnabled`, `AttachmentValidationCode`, `AttachmentValidationIssue`, `AttachmentValidationResult`, `FoldTurnEventsOptions`, `ImageProfileInterface`, `LiveProfileInterface`, `NormalizeModel`, `NormalizedModel`, `PendingAttachment`, `ProfileGuardrailsView`, `ProfileInputsInterface`, `ProfileInterface`, `ProfileInterfaceSource`, `ResolvedTools`, `SpeechProfileInterface`, `TextProfileInterface`, `TranscriptBlock`, `TranscriptBlockKind`, `UserTurnDraft` |
419
+ | Catalog | `clampThinkingLevel`, `clampThinkingLevelForApiId`, `mediaKindForMime`, `mimeAllowed`, `mimeEssence`, `modelEntryByApiId`, `requireModelSpec` |
420
+ | Schema | `PROFILE_FIELDS`, `PROFILE_TYPES`, `PROFILE_TYPE_PROTOCOLS`, `protocolsForProfileType`, `isValidProfileProtocol`, `EXTRA_FIELDS`, `fieldMeta`, `catalogPathFor`, `DYNAMIC_FIELD_PARENTS`, `PROTOCOLS`, `PROVIDERS`, `PROTOCOL_PROVIDERS`, `providersFor`, `protocolsFor`, `isValidPair`, `coerceProvider`, `coerceProtocol`, `THINKING_LEVELS`, `CONTROL_IDS`, `KEY_SLOTS`, `OVERFLOW_KEY_SLOTS`, `MEDIA_INPUT_KINDS`, `MEDIA_INPUT_KIND_VALUES`, `MEDIA_WILDCARDS`, `ATTACHMENT_ACCEPT_MIMES`, `VOICE_ACCEPT_MIMES`, `SUMMARY_MODES`, `STREAM_MODES`, `SPEECH_AUDIO_FORMATS`, `SCHEMA_ENFORCEMENTS`, `COMPACTION_METERS`, `COMPACTION_TIMINGS`, `EGRESS_ON_BLOCK`, `TURN_STOP_KINDS`, `TOOL_LOAD_TIERS`, `TOOL_ACCESS`, `TOOL_PERMISSION`, `TOOL_TYPES`, `LIVE_ACTIVITY_HANDLINGS`, `LIVE_CONTEXT_COMPRESSIONS`, `LIVE_SPEECH_SENSITIVITIES` |
421
+ | Profiles | `ProfileDefinition`, `ProfileDefinitionBase`, `TextProfileDefinition`, `ImageProfileDefinition`, `SpeechProfileDefinition`, `LiveProfileDefinition`, `clearProfiles`, `defineProfile`, `getProfile`, `hasProfile`, `listProfiles`, `registerProfile`, `registerProfiles`, `projectProfile`, `resolveTurn`, `pickModel` |
422
+ | Tools | `registerTool`, `registerTools`, `invokeTool`, `registerHarnessTools`, `getTool`, `hasTool`, `requireTool`, `listTools`, `listBuiltinIds`, `listFunctionIds`, `resetTools`, `formatToolResult`, `prepareTurnToolSnapshot` |
423
+ | Structured | `getStructured`, `registerStructured` |
424
+ | Stop / resume | `ProfileTurnResumptionSpec`, `TurnContinueFrom`, `TurnStop`, `TurnStopKind`, `AUTO_CONTINUE_DELAY_MS`, `CONTINUE_INSTRUCTION`, `DEFAULT_AUTO_CONTINUE`, `GenerationStopError`, `isGenerationStopError`, `isResumeableStop`, `isUserCancelledStop`, `shouldAutoContinue`, `turnStopFromClientStreamEnd`, `turnStopFromInteractionStatus`, `turnStopFromOpenAiFinishReason` |
358
425
  | Observability | `jsonlSink`, `memorySink`, `noopSink`, `resolveTraceDir`, `sinkFromDir`, `writeTrace`, `TraceRecord` |
359
- | Providers | `CreateProviderOptions`, `GeminiTransport`, `GeminiVault`, `LocalProviderConfig`, `createLocalProvider`, `createProvider`, `DEFAULT_LOCAL_BASE_URL` |
426
+ | Providers | `CreateProviderOptions`, `GeminiTransport`, `KeyVault`, `LocalProviderConfig`, `OpenAiGatewayConfig`, `createProvider` (local: `theorum/providers/local` → `createLocalProvider`, `DEFAULT_LOCAL_BASE_URL`) |
360
427
 
361
428
  Kernel types re-exported through this barrel follow `export type *` from
362
- `src/kernel/types.ts` (see `src/kernel/CONTRACT.md`).
429
+ `src/kernel/types.ts` (behavioral detail for contributors: repo
430
+ `docs/contracts/kernel.md`).
363
431
 
364
432
  ---
365
433
 
366
434
  ## Documentation
367
435
 
368
- Package docs are co-located with each public export (plus this README for `.`):
436
+ THEORUM keeps **package docs** and **repo contracts** separate.
437
+
438
+ | Surface | What it is | In the published package? |
439
+ | --- | --- | --- |
440
+ | **This README** | How hosts use THEORUM (API, boundaries, examples) | Yes |
441
+ | **Repo contracts** (`docs/contracts/*.md`) | Maintainer ownership + behavioral specs for docs-truth | **No** — GitHub / clone only |
442
+ | **Docs-truth** (`docs/DOCS_TRUTH.md`, `docs/_map.mjs`) | Lint graph that enforces those contracts | **No** |
369
443
 
370
- | Doc | Export |
444
+ On GitHub, module contracts:
445
+
446
+ | Doc (repo only) | Export |
371
447
  | :--- | :--- |
372
- | [`src/kernel/CONTRACT.md`](src/kernel/CONTRACT.md) | `theorum/kernel` — profiles, runner, compaction, stop/resume |
373
- | [`src/providers/CONTRACT.md`](src/providers/CONTRACT.md) | `theorum/providers` — `createProvider`, secrets boundary |
374
- | [`src/providers/OPENROUTER.md`](src/providers/OPENROUTER.md) | `theorum/openrouter` |
375
- | [`src/guardrails/CONTRACT.md`](src/guardrails/CONTRACT.md) | `theorum/guardrails` |
376
- | [`src/observability/CONTRACT.md`](src/observability/CONTRACT.md) | `theorum/observability` |
377
- | [`src/host/CONTRACT.md`](src/host/CONTRACT.md) | `theorum/host` |
378
- | [`src/cli/CONTRACT.md`](src/cli/CONTRACT.md) | `theorum/cli` |
379
- | [`src/presets/CONTRACT.md`](src/presets/CONTRACT.md) | `theorum/presets` |
380
- | [`src/presets/GOOGLE.md`](src/presets/GOOGLE.md) | `theorum/presets/google` |
381
- | [`src/streaming/CONTRACT.md`](src/streaming/CONTRACT.md) | `theorum/streaming` |
448
+ | [`docs/contracts/kernel.md`](docs/contracts/kernel.md) | `theorum/kernel` |
449
+ | [`docs/contracts/providers.md`](docs/contracts/providers.md) | `theorum/providers` |
450
+ | [`docs/contracts/guardrails.md`](docs/contracts/guardrails.md) | `theorum/guardrails` |
451
+ | [`docs/contracts/observability.md`](docs/contracts/observability.md) | `theorum/observability` |
452
+ | [`docs/contracts/host.md`](docs/contracts/host.md) | `theorum/host` |
453
+ | [`docs/contracts/kernel.md`](docs/contracts/kernel.md) (Headless interface) | `theorum/interface` |
454
+ | [`docs/contracts/cli.md`](docs/contracts/cli.md) | `theorum/cli` |
455
+ | [`docs/contracts/presets.md`](docs/contracts/presets.md) | `theorum/presets` |
456
+ | [`docs/contracts/presets-google.md`](docs/contracts/presets-google.md) | `theorum/presets/google` |
457
+
458
+ Migrating from per-turn `dynamicTools`? See
459
+ [`docs/MIGRATION-tool-system.md`](docs/MIGRATION-tool-system.md).
382
460
 
383
461
  Document health is enforced by `npm run lint:docs` — the **first** step of
384
462
  `npm run lint` / `deno task lint` (`docs/_map.mjs`):
@@ -387,6 +465,9 @@ Document health is enforced by `npm run lint:docs` — the **first** step of
387
465
  - Export parity with `package.json` and export-drift vs entry `mod.ts` files
388
466
  - Doc + **section** freshness on every code change (no Export-only gaming)
389
467
  - Behavioral sections require `contract_test` evidence (≥2 supports each)
468
+ - Publish gates keep `docs/` and `src/**/*.md` out of npm/JSR (`verify-publish-bundle`)
469
+ - Freshness diffs use a 32 MiB `git` buffer so large `origin/main...HEAD` patches
470
+ are not silently dropped (`ENOBUFS`)
390
471
  - Pre-commit runs `lint:docs` automatically (`prepare` installs the hook on `npm install`)
391
472
 
392
473
  ---
@@ -416,16 +497,16 @@ cd npm
416
497
  npm pack
417
498
  ```
418
499
 
419
- Run a live OpenRouter smoke test with a host-resolved key. The key is passed as an argument and is never read from a Theorum `.env` file.
500
+ Run an OpenRouter provider smoke test with a host-resolved key. The key is passed as an argument and is never read from a Theorum `.env` file.
420
501
 
421
502
  ```bash
422
- deno run --allow-net scripts/verify-live.ts --api-key "$OPENROUTER_API_KEY"
503
+ deno run --allow-net scripts/verify-provider-smoke.ts --api-key "$OPENROUTER_API_KEY"
423
504
  ```
424
505
 
425
- The default live verifier uses `perplexity/sonar` because it is broadly available on OpenRouter. Hosts can override both the profile-facing model id and provider-native id:
506
+ The default smoke uses `perplexity/sonar` because it is broadly available on OpenRouter. Hosts can override both the profile-facing model id and provider-native id:
426
507
 
427
508
  ```bash
428
- deno run --allow-net scripts/verify-live.ts \
509
+ deno run --allow-net scripts/verify-provider-smoke.ts \
429
510
  --api-key "$OPENROUTER_API_KEY" \
430
511
  --model hostFastModel \
431
512
  --api-id perplexity/sonar
@@ -444,10 +525,17 @@ env_files_in_package = false
444
525
  ambient_secret_reads = false
445
526
  business_logic_in_kernel = false
446
527
  provider_keys_host_owned = true
528
+ provider_adapters_lazy = true
447
529
  trace_sinks_host_injected = true
448
530
  realtime_duplex_voice = "out of scope"
449
531
  ```
450
532
 
533
+ Provider adapters load **lazily** on the first `complete` for that transport —
534
+ `createProvider` and `theorum/providers` stay a thin barrel (`src/providers/mod.ts`);
535
+ implementation modules (e.g. `google/interactions/`, `openrouter/`, `local/`) are
536
+ not pulled in at import time. `trace-attach` lazy-loads Interactions wire helpers
537
+ only for `geminiInteractions` traces.
538
+
451
539
  If an app needs domain rules, platform delivery policy, product copy, database access, or session memory, that belongs outside THEORUM.
452
540
 
453
541
  ---
@@ -485,6 +573,7 @@ MIT License. Copyright (c) ORCHID AI LLC.
485
573
  },
486
574
  "Package Boundary": {
487
575
  "supports": [
576
+ { "kind": "source", "path": "src/providers/mod.ts" },
488
577
  { "kind": "source", "path": "src/providers/create-provider.ts" },
489
578
  { "kind": "contract_test", "path": "tests/providers/create-provider.test.ts" }
490
579
  ]
package/esm/mod.d.ts CHANGED
@@ -21,7 +21,7 @@
21
21
  * summaries: { on: "auto", off: "none" },
22
22
  * maxOutputTokens: 8192,
23
23
  * temperature: 1,
24
- * keyBuiltins: [],
24
+ * builtInTools: [],
25
25
  * },
26
26
  * },
27
27
  * },
@@ -37,23 +37,33 @@
37
37
  * @module
38
38
  */
39
39
  import "./_dnt.polyfills.js";
40
- export { describeError, isAbortError, publicError, TheorumError, throwIfAborted, toErrorEvent, } from './src/guardrails/error.js';
40
+ export { describeError, isAbortError, PUBLIC_CANARY, publicError, TheorumError, throwIfAborted, toErrorEvent, } from './src/guardrails/error.js';
41
+ export type { CanaryGateResult, CanaryGateSession, CanaryStreamGate, LiveOutboundBatchResult, LiveOutboundGateSession, } from './src/guardrails/mod.js';
42
+ export { bindCanary, createCanaryGateSession, createCanaryStreamGate, createLiveOutboundGateSession, eventHasCanary, filterCanaryGatedEvents, finalizeLiveOutboundTurn, mintCanary, OMIT_CANARY, processLiveOutboundBatch, redactCanary, scanTextForCanaryLeak, standardEgressEnforce, wrapUserData, } from './src/guardrails/mod.js';
41
43
  export type { QuotaSlotStatus } from './src/guardrails/quota.js';
42
44
  export { clientIp, quotaMessage, releaseSlot, resetSlots, skipQuota, takeSlot, } from './src/guardrails/quota.js';
43
- export { PROJECT_ID_MAX, sanitizeProjectId, sanitizeText, sanitizeTurnRequest, } from './src/guardrails/sanitize.js';
45
+ export { PROJECT_ID_MAX, redactSensitiveOnly, sanitizeProjectId, sanitizeText, sanitizeTurnRequest, sanitizeTurnRequestForTrace, } from './src/guardrails/sanitize.js';
44
46
  export type { CompactionSplit, CompactionTokens } from './src/kernel/engine/compaction.js';
45
47
  export { compactionMeter, compactionNeeded, estimateHistoryTokens, HISTORY_MEDIA_TOKENS, HISTORY_TEXT_ENCODING, resolveCompactionTokens, resolveHistoryTokens, shouldCompact, splitForCompaction, } from './src/kernel/engine/compaction.js';
48
+ export { prepareLiveInboundText } from './src/kernel/engine/live-inbound.js';
46
49
  export { runTurn } from './src/kernel/engine/runner.js';
47
- export { CATALOG, clampThinkingLevel, clampThinkingLevelForApiId, getTool, listBuiltinIds, mediaKindForMime, mimeAllowed, mimeEssence, modelEntryByApiId, registerTools, requireModelSpec, resetTools, } from './src/kernel/registry/catalog.js';
48
- export type { ProfileDefinition } from './src/kernel/registry/profiles.js';
50
+ export type { RunSessionOptions } from './src/kernel/engine/session/mod.js';
51
+ export { runSession } from './src/kernel/engine/session/mod.js';
52
+ export { assertAttachmentLimits, fileTooLargeMessage, maxBytesForMime, requireMediaLimits, resolveMediaLimits, sanitizeCsvText, sanitizeTurnBlobs, sanitizeTurnBlobsForProfile, tooManyFilesMessage, turnTooLargeMessage, } from './src/kernel/registry/attachments.js';
53
+ export { clampThinkingLevel, clampThinkingLevelForApiId, mediaKindForMime, mimeAllowed, mimeEssence, modelEntryByApiId, requireModelSpec, } from './src/kernel/registry/catalog.js';
54
+ export type { ImageProfileDefinition, LiveProfileDefinition, ProfileDefinition, ProfileDefinitionBase, SpeechProfileDefinition, TextProfileDefinition, } from './src/kernel/registry/profiles.js';
49
55
  export { clearProfiles, defineProfile, getProfile, hasProfile, listProfiles, registerProfile, registerProfiles, } from './src/kernel/registry/profiles.js';
50
- export { projectProfile, resolveTurn } from './src/kernel/registry/resolve.js';
56
+ export { pickModel, projectProfile, resolveTurn } from './src/kernel/registry/resolve.js';
51
57
  export { getStructured, registerStructured } from './src/kernel/registry/schemas.js';
52
- export { executeTool } from './src/kernel/registry/tools.js';
53
- export type { ProfileResumeSpec, TurnContinueFrom, TurnStop, TurnStopKind, } from './src/kernel/stop.js';
54
- export { AUTO_CONTINUE_DELAY_MS, CONTINUE_INSTRUCTION, DEFAULT_AUTO_CONTINUE, GenerationStopError, isGenerationStopError, isResumeableStop, isUserCancelledStop, shouldAutoContinue, turnStopFromClientStreamEnd, turnStopFromInteractionStatus, turnStopFromOpenRouter, } from './src/kernel/stop.js';
58
+ export type { TurnStopKind } from './src/kernel/schema.js';
59
+ export { ATTACHMENT_ACCEPT_MIMES, COMPACTION_METERS, COMPACTION_TIMINGS, CONTROL_IDS, catalogPathFor, coerceProtocol, coerceProvider, DYNAMIC_FIELD_PARENTS, EGRESS_ON_BLOCK, EXTRA_FIELDS, fieldMeta, isValidPair, isValidProfileProtocol, KEY_SLOTS, LIVE_ACTIVITY_HANDLINGS, LIVE_CONTEXT_COMPRESSIONS, LIVE_SPEECH_SENSITIVITIES, MEDIA_INPUT_KIND_VALUES, MEDIA_INPUT_KINDS, MEDIA_WILDCARDS, OVERFLOW_KEY_SLOTS, PROFILE_FIELDS, PROFILE_TYPE_PROTOCOLS, PROFILE_TYPES, PROTOCOL_PROVIDERS, PROTOCOLS, PROVIDERS, protocolsFor, protocolsForProfileType, providersFor, SCHEMA_ENFORCEMENTS, SPEECH_AUDIO_FORMATS, STREAM_MODES, SUMMARY_MODES, THINKING_LEVELS, TOOL_ACCESS, TOOL_LOAD_TIERS, TOOL_PERMISSION, TOOL_TYPES, TURN_STOP_KINDS, VOICE_ACCEPT_MIMES, } from './src/kernel/schema.js';
60
+ export type { ProfileTurnResumptionSpec, TurnContinueFrom, TurnStop, } from './src/kernel/stop.js';
61
+ export { AUTO_CONTINUE_DELAY_MS, CONTINUE_INSTRUCTION, DEFAULT_AUTO_CONTINUE, GenerationStopError, isGenerationStopError, isResumeableStop, isUserCancelledStop, shouldAutoContinue, turnStopFromClientStreamEnd, turnStopFromInteractionStatus, turnStopFromOpenAiFinishReason, } from './src/kernel/stop.js';
62
+ export { formatToolResult, getTool, hasTool, invokeTool, listBuiltinIds, listFunctionIds, listTools, prepareTurnToolSnapshot, registerHarnessTools, registerTool, registerTools, requireTool, resetTools, } from './src/kernel/tools/mod.js';
55
63
  export type * from './src/kernel/types.js';
56
64
  export { jsonlSink, memorySink, noopSink, resolveTraceDir, sinkFromDir, writeTrace, } from './src/observability/trace.js';
57
65
  export type { TraceRecord } from './src/observability/trace-record.js';
58
- export type { CreateProviderOptions, GeminiTransport, GeminiVault, LocalProviderConfig, } from './src/providers/mod.js';
59
- export { createLocalProvider, createProvider, DEFAULT_LOCAL_BASE_URL, } from './src/providers/mod.js';
66
+ export * from './src/presets/mod.js';
67
+ export type { CreateProviderOptions, GeminiTransport, KeyVault, LocalProviderConfig, OpenAiGatewayConfig, } from './src/providers/mod.js';
68
+ export { createProvider } from './src/providers/mod.js';
69
+ export * from './src/interface/mod.js';
package/esm/mod.js CHANGED
@@ -21,7 +21,7 @@
21
21
  * summaries: { on: "auto", off: "none" },
22
22
  * maxOutputTokens: 8192,
23
23
  * temperature: 1,
24
- * keyBuiltins: [],
24
+ * builtInTools: [],
25
25
  * },
26
26
  * },
27
27
  * },
@@ -37,16 +37,23 @@
37
37
  * @module
38
38
  */
39
39
  import "./_dnt.polyfills.js";
40
- export { describeError, isAbortError, publicError, TheorumError, throwIfAborted, toErrorEvent, } from './src/guardrails/error.js';
40
+ export { describeError, isAbortError, PUBLIC_CANARY, publicError, TheorumError, throwIfAborted, toErrorEvent, } from './src/guardrails/error.js';
41
+ export { bindCanary, createCanaryGateSession, createCanaryStreamGate, createLiveOutboundGateSession, eventHasCanary, filterCanaryGatedEvents, finalizeLiveOutboundTurn, mintCanary, OMIT_CANARY, processLiveOutboundBatch, redactCanary, scanTextForCanaryLeak, standardEgressEnforce, wrapUserData, } from './src/guardrails/mod.js';
41
42
  export { clientIp, quotaMessage, releaseSlot, resetSlots, skipQuota, takeSlot, } from './src/guardrails/quota.js';
42
- export { PROJECT_ID_MAX, sanitizeProjectId, sanitizeText, sanitizeTurnRequest, } from './src/guardrails/sanitize.js';
43
+ export { PROJECT_ID_MAX, redactSensitiveOnly, sanitizeProjectId, sanitizeText, sanitizeTurnRequest, sanitizeTurnRequestForTrace, } from './src/guardrails/sanitize.js';
43
44
  export { compactionMeter, compactionNeeded, estimateHistoryTokens, HISTORY_MEDIA_TOKENS, HISTORY_TEXT_ENCODING, resolveCompactionTokens, resolveHistoryTokens, shouldCompact, splitForCompaction, } from './src/kernel/engine/compaction.js';
45
+ export { prepareLiveInboundText } from './src/kernel/engine/live-inbound.js';
44
46
  export { runTurn } from './src/kernel/engine/runner.js';
45
- export { CATALOG, clampThinkingLevel, clampThinkingLevelForApiId, getTool, listBuiltinIds, mediaKindForMime, mimeAllowed, mimeEssence, modelEntryByApiId, registerTools, requireModelSpec, resetTools, } from './src/kernel/registry/catalog.js';
47
+ export { runSession } from './src/kernel/engine/session/mod.js';
48
+ export { assertAttachmentLimits, fileTooLargeMessage, maxBytesForMime, requireMediaLimits, resolveMediaLimits, sanitizeCsvText, sanitizeTurnBlobs, sanitizeTurnBlobsForProfile, tooManyFilesMessage, turnTooLargeMessage, } from './src/kernel/registry/attachments.js';
49
+ export { clampThinkingLevel, clampThinkingLevelForApiId, mediaKindForMime, mimeAllowed, mimeEssence, modelEntryByApiId, requireModelSpec, } from './src/kernel/registry/catalog.js';
46
50
  export { clearProfiles, defineProfile, getProfile, hasProfile, listProfiles, registerProfile, registerProfiles, } from './src/kernel/registry/profiles.js';
47
- export { projectProfile, resolveTurn } from './src/kernel/registry/resolve.js';
51
+ export { pickModel, projectProfile, resolveTurn } from './src/kernel/registry/resolve.js';
48
52
  export { getStructured, registerStructured } from './src/kernel/registry/schemas.js';
49
- export { executeTool } from './src/kernel/registry/tools.js';
50
- export { AUTO_CONTINUE_DELAY_MS, CONTINUE_INSTRUCTION, DEFAULT_AUTO_CONTINUE, GenerationStopError, isGenerationStopError, isResumeableStop, isUserCancelledStop, shouldAutoContinue, turnStopFromClientStreamEnd, turnStopFromInteractionStatus, turnStopFromOpenRouter, } from './src/kernel/stop.js';
53
+ export { ATTACHMENT_ACCEPT_MIMES, COMPACTION_METERS, COMPACTION_TIMINGS, CONTROL_IDS, catalogPathFor, coerceProtocol, coerceProvider, DYNAMIC_FIELD_PARENTS, EGRESS_ON_BLOCK, EXTRA_FIELDS, fieldMeta, isValidPair, isValidProfileProtocol, KEY_SLOTS, LIVE_ACTIVITY_HANDLINGS, LIVE_CONTEXT_COMPRESSIONS, LIVE_SPEECH_SENSITIVITIES, MEDIA_INPUT_KIND_VALUES, MEDIA_INPUT_KINDS, MEDIA_WILDCARDS, OVERFLOW_KEY_SLOTS, PROFILE_FIELDS, PROFILE_TYPE_PROTOCOLS, PROFILE_TYPES, PROTOCOL_PROVIDERS, PROTOCOLS, PROVIDERS, protocolsFor, protocolsForProfileType, providersFor, SCHEMA_ENFORCEMENTS, SPEECH_AUDIO_FORMATS, STREAM_MODES, SUMMARY_MODES, THINKING_LEVELS, TOOL_ACCESS, TOOL_LOAD_TIERS, TOOL_PERMISSION, TOOL_TYPES, TURN_STOP_KINDS, VOICE_ACCEPT_MIMES, } from './src/kernel/schema.js';
54
+ export { AUTO_CONTINUE_DELAY_MS, CONTINUE_INSTRUCTION, DEFAULT_AUTO_CONTINUE, GenerationStopError, isGenerationStopError, isResumeableStop, isUserCancelledStop, shouldAutoContinue, turnStopFromClientStreamEnd, turnStopFromInteractionStatus, turnStopFromOpenAiFinishReason, } from './src/kernel/stop.js';
55
+ export { formatToolResult, getTool, hasTool, invokeTool, listBuiltinIds, listFunctionIds, listTools, prepareTurnToolSnapshot, registerHarnessTools, registerTool, registerTools, requireTool, resetTools, } from './src/kernel/tools/mod.js';
51
56
  export { jsonlSink, memorySink, noopSink, resolveTraceDir, sinkFromDir, writeTrace, } from './src/observability/trace.js';
52
- export { createLocalProvider, createProvider, DEFAULT_LOCAL_BASE_URL, } from './src/providers/mod.js';
57
+ export * from './src/presets/mod.js';
58
+ export { createProvider } from './src/providers/mod.js';
59
+ export * from './src/interface/mod.js';
@@ -12,8 +12,8 @@
12
12
  *
13
13
  * @module
14
14
  */
15
+ import { bindCanary, eventHasCanary, mintCanary } from '../../guardrails/canary.js';
15
16
  import { sanitizeTurnRequest } from '../../guardrails/sanitize.js';
16
- import { bindCanary, eventHasCanary, mintCanary } from '../../kernel/engine/boundary.js';
17
17
  import { runTurn } from '../../kernel/engine/runner.js';
18
18
  import { clearProfiles, registerProfile } from '../../kernel/registry/profiles.js';
19
19
  import { pickSystemRole, resolveTurn } from '../../kernel/registry/resolve.js';
@@ -25,6 +25,7 @@ const MS_PER_SEC = 1000;
25
25
  const BENCH_PROFILE_ID = '__bench__';
26
26
  function registerBenchProfile() {
27
27
  registerProfile({
28
+ type: 'text',
28
29
  id: BENCH_PROFILE_ID,
29
30
  identity: {
30
31
  handle: 'bench',
@@ -42,11 +43,13 @@ function registerBenchProfile() {
42
43
  summaries: { on: 'none', off: 'none' },
43
44
  maxOutputTokens: 4096,
44
45
  temperature: 0,
45
- keyBuiltins: [],
46
+ builtInTools: [],
46
47
  },
47
48
  },
48
49
  thinking: 'none',
49
50
  },
51
+ tools: { allow: [] },
52
+ inputs: { text: true },
50
53
  guardrails: {
51
54
  canary: true,
52
55
  sanitizeInput: true,
@@ -94,7 +97,7 @@ async function measureRawProvider(provider) {
94
97
  model: 'bench-model',
95
98
  apiId: 'bench-model',
96
99
  thinking: 'none',
97
- summaries: 'none',
100
+ summaries: undefined,
98
101
  maxOutputTokens: 4096,
99
102
  temperature: 0,
100
103
  builtins: [],
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Adversarial canary egress fuzzer.
3
+ *
4
+ * Pipes synthetic model leak attempts through the real runTurn stream gate
5
+ * and Live batch gate, then reports bypasses — output that still contains
6
+ * the raw per-turn canary token where the gate should have blocked.
7
+ *
8
+ * @module
9
+ */
10
+ /** Run adversarial canary fuzz; returns true when no bypasses or false alarms. */
11
+ export declare function fuzzCanaryCommand(options?: {
12
+ canary?: string;
13
+ }): Promise<boolean>;