theorum 0.1.15 → 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 +177 -90
  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 +437 -39
  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 -202
  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 -202
  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,11 +10,11 @@
10
10
 
11
11
  # THEORUM: The Flat Agent Kernel
12
12
 
13
- **Current release: `0.1.15`** (`jsr:@theorum/core` / npm `theorum`).
13
+ **Current release: `1.0.0`** (`jsr:@theorum/core` / npm `theorum`).
14
14
 
15
15
  > **"Profiles describe the contract. Providers move bytes. The runner enforces the turn."**
16
16
 
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, 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.
18
18
 
19
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.
20
20
 
@@ -29,7 +29,7 @@ OpenRouter chat transport is powered by Vercel AI SDK Core under the adapter. TH
29
29
  profiles = "Host-owned declarations for model, inputs, outputs, tools, and guardrails"
30
30
  runner = "Single deterministic execution path for one agent turn"
31
31
  providers = "createProvider routes protocol/provider; adapters stay internal"
32
- tools = "Profile allowlist ceiling plus per-turn dynamic declarations"
32
+ tools = "Profile allowlist ceiling plus per-turn opt-in gates"
33
33
  egress = "Typed host hook for outbound disclosure checks and repair loops"
34
34
  traces = "Host-injected sinks; no environment variables or bundled destinations"
35
35
 
@@ -61,7 +61,7 @@ flowchart TD
61
61
  Resolve["resolveTurn"]
62
62
  Guard["sanitize + canary + egress"]
63
63
  Runner["runTurn"]
64
- ToolLoop["dynamic tool loop"]
64
+ ToolLoop["registered tool loop"]
65
65
  Repair["repair attempts"]
66
66
  end
67
67
 
@@ -84,27 +84,66 @@ flowchart TD
84
84
  Runner --> TraceSink
85
85
  ```
86
86
 
87
- 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
88
 
89
- ### Turn Lifecycle
89
+ ### Turn execution and tools
90
+
91
+ One turn is a single pipeline. Tools share `executeRegisteredTool` with `invokeTool`; compaction,
92
+ guardrails, and streaming attach at different layers.
90
93
 
91
94
  ```mermaid
92
- stateDiagram-v2
93
- [*] --> ResolveProfile: host sends TurnRequest
94
- ResolveProfile --> NormalizeInput: profile input rules
95
- NormalizeInput --> BindBoundary: canary + user data fencing
96
- BindBoundary --> ProviderStream: ModelProvider.complete
97
- ProviderStream --> ToolDispatch: tool event
98
- ToolDispatch --> ProviderStream: autonomous loop continues
99
- ProviderStream --> EgressGate: final candidate
100
- EgressGate --> RepairTurn: blocked + retry budget
101
- RepairTurn --> ProviderStream
102
- EgressGate --> ValidateOutput: clear
103
- ValidateOutput --> EmitEvents: text/media/structured/tokens/done
104
- EmitEvents --> Trace: host sink receives audit record
105
- 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
106
133
  ```
107
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
+
108
147
  ---
109
148
 
110
149
  ## Install
@@ -145,6 +184,7 @@ import {
145
184
  } from "jsr:@theorum/core";
146
185
 
147
186
  const profile = defineProfile({
187
+ type: "text",
148
188
  id: "assistant.basic",
149
189
  identity: {
150
190
  handle: "assistant",
@@ -157,18 +197,19 @@ const profile = defineProfile({
157
197
  config: {
158
198
  hostFastModel: {
159
199
  apiId: "perplexity/sonar",
160
- openRouterId: "perplexity/sonar",
161
200
  thinking: { on: "high", off: "minimal" },
162
201
  thinkingLevels: ["minimal", "low", "medium", "high"],
163
202
  summaries: { on: "auto", off: "none" },
164
203
  maxOutputTokens: 8192,
165
204
  temperature: 1,
166
- keyBuiltins: [],
205
+ builtInTools: [],
167
206
  },
168
207
  },
169
208
  thinking: "minimal",
170
209
  maxSteps: 1,
171
210
  },
211
+ tools: { allow: [] },
212
+ inputs: { text: true },
172
213
  outputs: {
173
214
  streaming: { streamThoughts: false },
174
215
  },
@@ -197,38 +238,52 @@ for await (const event of runTurn(
197
238
 
198
239
  ---
199
240
 
200
- ## Dynamic Tools
241
+ ## Registered Tools
201
242
 
202
- THEORUM separates tool concerns into three layers.
243
+ THEORUM separates tool concerns into four layers.
203
244
 
204
245
  | Layer | Owner | Purpose |
205
246
  | :--- | :--- | :--- |
206
- | **Access** | Profile | Hard ceiling: the agent cannot use a tool outside `profile.tools.allow`. |
207
- | **Visibility** | Turn request | Per-turn declarations: T0/T1/T2 schemas can be passed or loaded dynamically. |
208
- | **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 |
209
251
 
210
252
  ```ts
211
- const dynamicTools = [
212
- {
213
- name: "lookup_order",
214
- description: "Fetch order state from the host application.",
215
- loadTier: "T1",
216
- permissionTier: "session_consent",
217
- parameters: {
218
- type: "object",
219
- properties: { orderId: { type: "string" } },
220
- required: ["orderId"],
221
- },
222
- handler: async (args) => ({
223
- status: "ok",
224
- finding: "Order is in transit.",
225
- data: { orderId: args.orderId, state: "in_transit" },
226
- }),
227
- },
228
- ] 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 } });
229
279
  ```
230
280
 
231
- 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`).
232
287
 
233
288
  ---
234
289
 
@@ -238,22 +293,28 @@ Inbound and outbound safety are generic kernel hooks.
238
293
 
239
294
  ```ts
240
295
  const guardedProfile = defineProfile({
296
+ type: "text",
241
297
  id: "assistant.guarded",
298
+ identity: { handle: "guarded", system: "You are a careful assistant." },
242
299
  model: {
300
+ protocol: "openAi",
301
+ provider: "openrouter",
243
302
  allow: ["hostFastModel"],
244
303
  config: {
245
304
  hostFastModel: {
246
305
  apiId: "perplexity/sonar",
247
- openRouterId: "perplexity/sonar",
248
306
  thinking: { on: "high", off: "minimal" },
249
307
  thinkingLevels: ["minimal", "low", "medium", "high"],
250
308
  summaries: { on: "auto", off: "none" },
251
309
  maxOutputTokens: 8192,
252
310
  temperature: 1,
253
- keyBuiltins: [],
311
+ builtInTools: [],
254
312
  },
255
313
  },
314
+ thinking: "minimal",
256
315
  },
316
+ tools: { allow: [] },
317
+ inputs: { text: true },
257
318
  guardrails: {
258
319
  egress: {
259
320
  onBlock: "reject_to_agent",
@@ -289,7 +350,7 @@ import { createProvider, runTurn } from "jsr:@theorum/core";
289
350
 
290
351
  const provider = createProvider(profile, {
291
352
  gemini: { vault: hostGeminiKeyVault, fetch },
292
- openRouter: { apiKey: hostSecrets.openRouterApiKey },
353
+ openAiGateway: { apiKey: hostSecrets.openRouterApiKey },
293
354
  // openAi + local — optional; default baseUrl http://127.0.0.1:11434
294
355
  local: { baseUrl: hostResolvedLocalBaseUrl },
295
356
  });
@@ -299,7 +360,7 @@ for await (const event of runTurn({ profile: profile.id, input: { text: "…" }
299
360
  }
300
361
  ```
301
362
 
302
- `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).
303
364
 
304
365
  | Profile | Transport |
305
366
  | :--- | :--- |
@@ -310,17 +371,14 @@ for await (const event of runTurn({ profile: profile.id, input: { text: "…" }
310
371
 
311
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`.
312
373
 
313
- OpenRouter uses Vercel AI SDK Core inside THEORUM's provider adapter. That stack
314
- loads **lazily on the first `complete` call** for `openAi` + `openrouter` chat
315
- not when importing THEORUM, and not for Google or local providers. The adapter
316
- still emits THEORUM `TurnEvent` values and preserves raw provider evidence for
317
- citations/provenance where the normalized SDK stream does not expose enough detail.
318
-
319
- Advanced OpenRouter exports live under `theorum/openrouter` (`createOpenRouterProvider`,
320
- `toOpenRouterPayload`, …). Prefer `createProvider` for turns unless the host needs
321
- to wire the OpenRouter adapter directly. Direct local construction is also available
322
- as `createLocalProvider` from the main / providers entrypoints. Importing
323
- `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.
324
382
 
325
383
  ---
326
384
 
@@ -330,14 +388,16 @@ as `createLocalProvider` from the main / providers entrypoints. Importing
330
388
  | :--- | :--- |
331
389
  | `jsr:@theorum/core` / `theorum` | Main kernel API: profiles, schemas, runner, core types, provider constructors. |
332
390
  | `jsr:@theorum/core/kernel` / `theorum/kernel` | Profile/turn types, tool catalog, `requireModelSpec`, thinking clamps over host model maps. |
333
- | `jsr:@theorum/core/providers` / `theorum/providers` | `createProvider` + Gemini vault types. |
334
- | `jsr:@theorum/core/openrouter` / `theorum/openrouter` | Direct OpenRouter provider adapter and payload helpers (advanced). |
335
- | `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). |
336
395
  | `jsr:@theorum/core/observability` / `theorum/observability` | Trace sinks and trace record helpers. |
337
396
  | `jsr:@theorum/core/host` / `theorum/host` | Optional Deno HTTP helpers (`json`, status mapping, cutout mint flush). |
338
397
  | `jsr:@theorum/core/cli` / `theorum/cli` | Profile inspection and stress-test CLI (`theorum` binary on npm). |
339
398
  | `jsr:@theorum/core/presets` / `theorum/presets` | Optional convenience packs (`registerGooglePreset`, …). |
340
- | `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). |
341
401
 
342
402
  Internal files remain present in source for maintainability, but package consumers should use the public entrypoints above.
343
403
 
@@ -348,39 +408,55 @@ Named exports from the root barrel (same symbols hosts get from `theorum` /
348
408
 
349
409
  | Group | Symbols |
350
410
  | --- | --- |
351
- | Guardrails errors | `describeError`, `isAbortError`, `publicError`, `TheorumError`, `throwIfAborted`, `toErrorEvent` |
411
+ | Guardrails errors | `describeError`, `isAbortError`, `publicError`, `TheorumError`, `throwIfAborted`, `toErrorEvent`, `PUBLIC_CANARY` |
352
412
  | Quota | `QuotaSlotStatus`, `clientIp`, `quotaMessage`, `releaseSlot`, `resetSlots`, `skipQuota`, `takeSlot` |
353
- | 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` |
354
415
  | Compaction | `CompactionSplit`, `CompactionTokens`, `compactionMeter`, `compactionNeeded`, `estimateHistoryTokens`, `HISTORY_MEDIA_TOKENS`, `HISTORY_TEXT_ENCODING`, `resolveCompactionTokens`, `resolveHistoryTokens`, `shouldCompact`, `splitForCompaction` |
355
- | Runner | `runTurn` |
356
- | Catalog | `CATALOG`, `clampThinkingLevel`, `clampThinkingLevelForApiId`, `mediaKindForMime`, `getTool`, `listBuiltinIds`, `mimeAllowed`, `mimeEssence`, `modelEntryByApiId`, `registerTools`, `requireModelSpec`, `resetTools` |
357
- | Profiles | `ProfileDefinition`, `clearProfiles`, `defineProfile`, `getProfile`, `hasProfile`, `listProfiles`, `registerProfile`, `registerProfiles`, `projectProfile`, `resolveTurn` |
358
- | Structured | `getStructured`, `registerStructured`, `executeTool` |
359
- | 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` |
360
425
  | Observability | `jsonlSink`, `memorySink`, `noopSink`, `resolveTraceDir`, `sinkFromDir`, `writeTrace`, `TraceRecord` |
361
- | 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`) |
362
427
 
363
428
  Kernel types re-exported through this barrel follow `export type *` from
364
- `src/kernel/types.ts` (see `src/kernel/CONTRACT.md`).
429
+ `src/kernel/types.ts` (behavioral detail for contributors: repo
430
+ `docs/contracts/kernel.md`).
365
431
 
366
432
  ---
367
433
 
368
434
  ## Documentation
369
435
 
370
- 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** |
371
443
 
372
- | Doc | Export |
444
+ On GitHub, module contracts:
445
+
446
+ | Doc (repo only) | Export |
373
447
  | :--- | :--- |
374
- | [`src/kernel/CONTRACT.md`](src/kernel/CONTRACT.md) | `theorum/kernel` — profiles, runner, compaction, stop/resume |
375
- | [`src/providers/CONTRACT.md`](src/providers/CONTRACT.md) | `theorum/providers` — `createProvider`, secrets boundary |
376
- | [`src/providers/OPENROUTER.md`](src/providers/OPENROUTER.md) | `theorum/openrouter` |
377
- | [`src/guardrails/CONTRACT.md`](src/guardrails/CONTRACT.md) | `theorum/guardrails` |
378
- | [`src/observability/CONTRACT.md`](src/observability/CONTRACT.md) | `theorum/observability` |
379
- | [`src/host/CONTRACT.md`](src/host/CONTRACT.md) | `theorum/host` |
380
- | [`src/cli/CONTRACT.md`](src/cli/CONTRACT.md) | `theorum/cli` |
381
- | [`src/presets/CONTRACT.md`](src/presets/CONTRACT.md) | `theorum/presets` |
382
- | [`src/presets/GOOGLE.md`](src/presets/GOOGLE.md) | `theorum/presets/google` |
383
- | [`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).
384
460
 
385
461
  Document health is enforced by `npm run lint:docs` — the **first** step of
386
462
  `npm run lint` / `deno task lint` (`docs/_map.mjs`):
@@ -389,6 +465,9 @@ Document health is enforced by `npm run lint:docs` — the **first** step of
389
465
  - Export parity with `package.json` and export-drift vs entry `mod.ts` files
390
466
  - Doc + **section** freshness on every code change (no Export-only gaming)
391
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`)
392
471
  - Pre-commit runs `lint:docs` automatically (`prepare` installs the hook on `npm install`)
393
472
 
394
473
  ---
@@ -418,16 +497,16 @@ cd npm
418
497
  npm pack
419
498
  ```
420
499
 
421
- 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.
422
501
 
423
502
  ```bash
424
- 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"
425
504
  ```
426
505
 
427
- 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:
428
507
 
429
508
  ```bash
430
- deno run --allow-net scripts/verify-live.ts \
509
+ deno run --allow-net scripts/verify-provider-smoke.ts \
431
510
  --api-key "$OPENROUTER_API_KEY" \
432
511
  --model hostFastModel \
433
512
  --api-id perplexity/sonar
@@ -446,10 +525,17 @@ env_files_in_package = false
446
525
  ambient_secret_reads = false
447
526
  business_logic_in_kernel = false
448
527
  provider_keys_host_owned = true
528
+ provider_adapters_lazy = true
449
529
  trace_sinks_host_injected = true
450
530
  realtime_duplex_voice = "out of scope"
451
531
  ```
452
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
+
453
539
  If an app needs domain rules, platform delivery policy, product copy, database access, or session memory, that belongs outside THEORUM.
454
540
 
455
541
  ---
@@ -487,6 +573,7 @@ MIT License. Copyright (c) ORCHID AI LLC.
487
573
  },
488
574
  "Package Boundary": {
489
575
  "supports": [
576
+ { "kind": "source", "path": "src/providers/mod.ts" },
490
577
  { "kind": "source", "path": "src/providers/create-provider.ts" },
491
578
  { "kind": "contract_test", "path": "tests/providers/create-provider.test.ts" }
492
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>;