theorum 0.1.15 → 1.1.3

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 (305) hide show
  1. package/README.md +241 -98
  2. package/esm/mod.d.ts +57 -28
  3. package/esm/mod.js +43 -23
  4. package/esm/src/cli/commands/bench.js +18 -18
  5. package/esm/src/cli/commands/fuzz-canary.d.ts +13 -0
  6. package/esm/src/cli/commands/fuzz-canary.js +191 -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/guardrails-eval.d.ts +14 -0
  10. package/esm/src/cli/commands/guardrails-eval.js +15 -0
  11. package/esm/src/cli/commands/profile.js +35 -15
  12. package/esm/src/cli/commands/run.d.ts +3 -0
  13. package/esm/src/cli/commands/run.js +23 -32
  14. package/esm/src/cli/commands/test.d.ts +10 -1
  15. package/esm/src/cli/commands/test.js +34 -34
  16. package/esm/src/cli/event-log.d.ts +19 -0
  17. package/esm/src/cli/event-log.js +147 -0
  18. package/esm/src/cli/index.js +57 -11
  19. package/esm/src/cli/matrix/synthesizer.d.ts +10 -12
  20. package/esm/src/cli/matrix/synthesizer.js +45 -118
  21. package/esm/src/guardrails/canary-gate.d.ts +21 -0
  22. package/esm/src/guardrails/canary-gate.js +32 -0
  23. package/esm/src/guardrails/canary.d.ts +34 -0
  24. package/esm/src/guardrails/canary.js +150 -0
  25. package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +17 -0
  26. package/esm/src/guardrails/corpus/canary-egress-attacks.js +151 -0
  27. package/esm/src/guardrails/corpus/fuzz-inbound.d.ts +11 -0
  28. package/esm/src/guardrails/corpus/fuzz-inbound.js +213 -0
  29. package/esm/src/guardrails/corpus/inbound-payloads.d.ts +10 -0
  30. package/esm/src/guardrails/corpus/inbound-payloads.js +125 -0
  31. package/esm/src/guardrails/corpus/live-attacks.d.ts +20 -0
  32. package/esm/src/guardrails/corpus/live-attacks.js +231 -0
  33. package/esm/src/guardrails/corpus/mod.d.ts +14 -0
  34. package/esm/src/guardrails/corpus/mod.js +11 -0
  35. package/esm/src/guardrails/corpus/secrets.d.ts +17 -0
  36. package/esm/src/guardrails/corpus/secrets.js +17 -0
  37. package/esm/src/guardrails/corpus/strings.d.ts +28 -0
  38. package/esm/src/guardrails/corpus/strings.js +34 -0
  39. package/esm/src/guardrails/corpus/types.d.ts +38 -0
  40. package/esm/src/guardrails/corpus/types.js +6 -0
  41. package/esm/src/guardrails/egress.d.ts +32 -0
  42. package/esm/src/guardrails/egress.js +87 -0
  43. package/esm/src/guardrails/error.d.ts +14 -23
  44. package/esm/src/guardrails/error.js +87 -76
  45. package/esm/src/guardrails/eval/corpus.d.ts +108 -0
  46. package/esm/src/guardrails/eval/corpus.js +978 -0
  47. package/esm/src/guardrails/eval/mod.d.ts +51 -0
  48. package/esm/src/guardrails/eval/mod.js +133 -0
  49. package/esm/src/guardrails/eval/score.d.ts +66 -0
  50. package/esm/src/guardrails/eval/score.js +114 -0
  51. package/esm/src/guardrails/events.d.ts +25 -0
  52. package/esm/src/guardrails/events.js +56 -0
  53. package/esm/src/guardrails/hits.d.ts +24 -0
  54. package/esm/src/guardrails/hits.js +45 -0
  55. package/esm/src/guardrails/injection.js +28 -5
  56. package/esm/src/guardrails/lexicon.d.ts +39 -0
  57. package/esm/src/guardrails/lexicon.js +200 -0
  58. package/esm/src/guardrails/live-outbound-gate.d.ts +41 -0
  59. package/esm/src/guardrails/live-outbound-gate.js +222 -0
  60. package/esm/src/guardrails/mod.d.ts +30 -6
  61. package/esm/src/guardrails/mod.js +20 -5
  62. package/esm/src/guardrails/network.d.ts +19 -0
  63. package/esm/src/guardrails/network.js +234 -0
  64. package/esm/src/guardrails/policy.d.ts +35 -0
  65. package/esm/src/guardrails/policy.js +50 -0
  66. package/esm/src/guardrails/progressive-yield.d.ts +51 -0
  67. package/esm/src/guardrails/progressive-yield.js +98 -0
  68. package/esm/src/guardrails/quota.d.ts +17 -3
  69. package/esm/src/guardrails/quota.js +18 -4
  70. package/esm/src/guardrails/sanitize.d.ts +45 -19
  71. package/esm/src/guardrails/sanitize.js +177 -94
  72. package/esm/src/guardrails/sensitive.js +2 -1
  73. package/esm/src/guardrails/serialize.d.ts +35 -0
  74. package/esm/src/guardrails/serialize.js +58 -0
  75. package/esm/src/guardrails/testing.d.ts +17 -0
  76. package/esm/src/guardrails/testing.js +13 -0
  77. package/esm/src/guardrails/theorum-error.d.ts +12 -0
  78. package/esm/src/guardrails/theorum-error.js +15 -0
  79. package/esm/src/guardrails/tool-directives.d.ts +48 -0
  80. package/esm/src/guardrails/tool-directives.js +124 -0
  81. package/esm/src/guardrails/tool-result.d.ts +93 -0
  82. package/esm/src/guardrails/tool-result.js +276 -0
  83. package/esm/src/guardrails/types.d.ts +291 -0
  84. package/esm/src/guardrails/types.js +72 -0
  85. package/esm/src/host/client-turn.d.ts +19 -0
  86. package/esm/src/host/client-turn.js +36 -0
  87. package/esm/src/host/mint-trace.d.ts +1 -1
  88. package/esm/src/host/mod.d.ts +5 -3
  89. package/esm/src/host/mod.js +4 -3
  90. package/esm/src/kernel/auth/crypto.d.ts +42 -0
  91. package/esm/src/kernel/auth/crypto.js +106 -0
  92. package/esm/src/kernel/auth/mod.d.ts +11 -0
  93. package/esm/src/kernel/auth/mod.js +11 -0
  94. package/esm/src/kernel/auth/oauth.d.ts +47 -0
  95. package/esm/src/kernel/auth/oauth.js +278 -0
  96. package/esm/src/kernel/auth/types.d.ts +133 -0
  97. package/esm/src/kernel/auth/types.js +13 -0
  98. package/esm/src/kernel/engine/delta.d.ts +24 -2
  99. package/esm/src/kernel/engine/delta.js +478 -39
  100. package/esm/src/kernel/engine/live-inbound.d.ts +21 -0
  101. package/esm/src/kernel/engine/live-inbound.js +31 -0
  102. package/esm/src/kernel/engine/live-ingress.d.ts +19 -0
  103. package/esm/src/kernel/engine/live-ingress.js +47 -0
  104. package/esm/src/kernel/engine/repair.js +13 -12
  105. package/esm/src/kernel/engine/runner/gates.d.ts +1 -1
  106. package/esm/src/kernel/engine/runner/gates.js +130 -43
  107. package/esm/src/kernel/engine/runner/mod.d.ts +6 -4
  108. package/esm/src/kernel/engine/runner/mod.js +192 -53
  109. package/esm/src/kernel/engine/runner/schema-validation.js +3 -3
  110. package/esm/src/kernel/engine/runner/stages.d.ts +39 -0
  111. package/esm/src/kernel/engine/runner/stages.js +89 -0
  112. package/esm/src/kernel/engine/runner/state.d.ts +31 -0
  113. package/esm/src/kernel/engine/runner/steps.d.ts +1 -1
  114. package/esm/src/kernel/engine/runner/steps.js +244 -43
  115. package/esm/src/kernel/engine/runner/stream.d.ts +9 -3
  116. package/esm/src/kernel/engine/runner/stream.js +140 -44
  117. package/esm/src/kernel/engine/session/mod.d.ts +25 -0
  118. package/esm/src/kernel/engine/session/mod.js +557 -0
  119. package/esm/src/kernel/interaction-parts.d.ts +14 -0
  120. package/esm/src/kernel/interaction-parts.js +23 -0
  121. package/esm/src/kernel/mod.d.ts +21 -10
  122. package/esm/src/kernel/mod.js +11 -8
  123. package/esm/src/kernel/profile-graph.d.ts +159 -0
  124. package/esm/src/kernel/profile-graph.js +156 -0
  125. package/esm/src/kernel/registry/attachments.d.ts +12 -10
  126. package/esm/src/kernel/registry/attachments.js +33 -27
  127. package/esm/src/kernel/registry/catalog.d.ts +25 -24
  128. package/esm/src/kernel/registry/catalog.js +60 -101
  129. package/esm/src/kernel/registry/ingress.d.ts +9 -4
  130. package/esm/src/kernel/registry/ingress.js +97 -75
  131. package/esm/src/kernel/registry/profile-outputs.d.ts +4 -0
  132. package/esm/src/kernel/registry/profile-outputs.js +8 -0
  133. package/esm/src/kernel/registry/profiles.d.ts +55 -12
  134. package/esm/src/kernel/registry/profiles.js +413 -73
  135. package/esm/src/kernel/registry/provider-request.js +13 -7
  136. package/esm/src/kernel/registry/resolve.d.ts +8 -8
  137. package/esm/src/kernel/registry/resolve.js +169 -154
  138. package/esm/src/kernel/registry/schemas.js +1 -1
  139. package/esm/src/kernel/registry/sole-model.d.ts +8 -0
  140. package/esm/src/kernel/registry/sole-model.js +10 -0
  141. package/esm/src/kernel/registry/system-prompt.d.ts +10 -0
  142. package/esm/src/kernel/registry/system-prompt.js +40 -0
  143. package/esm/src/kernel/registry/system-role.d.ts +8 -0
  144. package/esm/src/kernel/registry/system-role.js +14 -0
  145. package/esm/src/kernel/registry/vault.d.ts +12 -7
  146. package/esm/src/kernel/registry/vault.js +32 -10
  147. package/esm/src/kernel/schema.d.ts +231 -0
  148. package/esm/src/kernel/schema.js +607 -0
  149. package/esm/src/kernel/stages.d.ts +175 -0
  150. package/esm/src/kernel/stages.js +476 -0
  151. package/esm/src/kernel/stop.d.ts +78 -19
  152. package/esm/src/kernel/stop.js +51 -16
  153. package/esm/src/kernel/tools/events.d.ts +41 -0
  154. package/esm/src/kernel/tools/events.js +71 -0
  155. package/esm/src/kernel/tools/execute.d.ts +84 -0
  156. package/esm/src/kernel/tools/execute.js +614 -0
  157. package/esm/src/kernel/tools/harness.d.ts +8 -0
  158. package/esm/src/kernel/tools/harness.js +46 -0
  159. package/esm/src/kernel/tools/invoke.d.ts +10 -0
  160. package/esm/src/kernel/tools/invoke.js +101 -0
  161. package/esm/src/kernel/tools/mod.d.ts +13 -0
  162. package/esm/src/kernel/tools/mod.js +11 -0
  163. package/esm/src/kernel/tools/permission.d.ts +15 -0
  164. package/esm/src/kernel/tools/permission.js +47 -0
  165. package/esm/src/kernel/tools/project.d.ts +12 -0
  166. package/esm/src/kernel/tools/project.js +36 -0
  167. package/esm/src/kernel/tools/registry.d.ts +23 -0
  168. package/esm/src/kernel/tools/registry.js +81 -0
  169. package/esm/src/kernel/tools/remote.d.ts +94 -0
  170. package/esm/src/kernel/tools/remote.js +577 -0
  171. package/esm/src/kernel/tools/resolve.d.ts +39 -0
  172. package/esm/src/kernel/tools/resolve.js +283 -0
  173. package/esm/src/kernel/tools/schema.d.ts +15 -0
  174. package/esm/src/kernel/tools/schema.js +176 -0
  175. package/esm/src/kernel/tools/stage-run.d.ts +105 -0
  176. package/esm/src/kernel/tools/stage-run.js +155 -0
  177. package/esm/src/kernel/tools/types.d.ts +394 -0
  178. package/esm/src/kernel/tools/types.js +9 -0
  179. package/esm/src/kernel/types.d.ts +540 -256
  180. package/esm/src/kernel/util/find-last.d.ts +2 -0
  181. package/esm/src/kernel/util/find-last.js +10 -0
  182. package/esm/src/observability/destinations.d.ts +31 -0
  183. package/esm/src/observability/destinations.js +67 -0
  184. package/esm/src/observability/mod.d.ts +10 -3
  185. package/esm/src/observability/mod.js +6 -2
  186. package/esm/src/observability/policy.d.ts +27 -0
  187. package/esm/src/observability/policy.js +80 -0
  188. package/esm/src/observability/resolve-policy.d.ts +16 -0
  189. package/esm/src/observability/resolve-policy.js +64 -0
  190. package/esm/src/observability/trace-attach.d.ts +8 -4
  191. package/esm/src/observability/trace-attach.js +50 -29
  192. package/esm/src/observability/trace-record.d.ts +23 -13
  193. package/esm/src/observability/trace-record.js +96 -39
  194. package/esm/src/observability/trace-sink.d.ts +19 -0
  195. package/esm/src/observability/trace-sink.js +10 -0
  196. package/esm/src/observability/trace-usage.d.ts +10 -3
  197. package/esm/src/observability/trace-usage.js +70 -17
  198. package/esm/src/observability/trace.d.ts +18 -7
  199. package/esm/src/observability/trace.js +34 -17
  200. package/esm/src/observability/types.d.ts +113 -0
  201. package/esm/src/observability/types.js +11 -0
  202. package/esm/src/presets/google/speech-voices.d.ts +11 -0
  203. package/esm/src/presets/google/speech-voices.js +41 -0
  204. package/esm/src/presets/google.d.ts +36 -24
  205. package/esm/src/presets/google.js +50 -63
  206. package/esm/src/presets/mod.d.ts +2 -2
  207. package/esm/src/presets/mod.js +1 -1
  208. package/esm/src/providers/create-provider.d.ts +20 -17
  209. package/esm/src/providers/create-provider.js +72 -26
  210. package/esm/src/providers/google/interactions/framing.d.ts +23 -0
  211. package/esm/src/providers/google/interactions/framing.js +269 -0
  212. package/esm/src/providers/google/interactions/mod.d.ts +7 -0
  213. package/esm/src/providers/google/interactions/mod.js +7 -0
  214. package/esm/src/providers/google/interactions/stream.d.ts +83 -0
  215. package/esm/src/providers/google/interactions/stream.js +588 -0
  216. package/esm/src/providers/google/keys.d.ts +26 -0
  217. package/esm/src/providers/{keys.js → google/keys.js} +19 -31
  218. package/esm/src/providers/google/live/framing.d.ts +49 -0
  219. package/esm/src/providers/google/live/framing.js +552 -0
  220. package/esm/src/providers/google/live/openapi-schema.d.ts +6 -0
  221. package/esm/src/providers/google/live/openapi-schema.js +46 -0
  222. package/esm/src/providers/google/live/session.d.ts +25 -0
  223. package/esm/src/providers/google/live/session.js +134 -0
  224. package/esm/src/providers/google/live/stream.d.ts +45 -0
  225. package/esm/src/providers/google/live/stream.js +214 -0
  226. package/esm/src/providers/google/urls.d.ts +6 -0
  227. package/esm/src/providers/google/urls.js +6 -0
  228. package/esm/src/providers/local/local.d.ts +30 -0
  229. package/esm/src/providers/{local.js → local/local.js} +66 -126
  230. package/esm/src/providers/local/mod.d.ts +9 -0
  231. package/esm/src/providers/local/mod.js +9 -0
  232. package/esm/src/providers/mod.d.ts +6 -3
  233. package/esm/src/providers/mod.js +3 -1
  234. package/esm/src/providers/openrouter/cache-control.d.ts +24 -0
  235. package/esm/src/providers/openrouter/cache-control.js +23 -0
  236. package/esm/src/providers/openrouter/chat.d.ts +107 -0
  237. package/esm/src/providers/{openrouter.js → openrouter/chat.js} +117 -231
  238. package/esm/src/providers/openrouter/image.d.ts +34 -0
  239. package/esm/src/providers/openrouter/image.js +275 -0
  240. package/esm/src/providers/openrouter/openai/chat-payload.d.ts +24 -0
  241. package/esm/src/providers/openrouter/openai/chat-payload.js +82 -0
  242. package/esm/src/providers/openrouter/openai/compat.d.ts +53 -0
  243. package/esm/src/providers/openrouter/openai/compat.js +213 -0
  244. package/esm/src/providers/openrouter/openai/image-payload.d.ts +18 -0
  245. package/esm/src/providers/openrouter/openai/image-payload.js +90 -0
  246. package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +22 -0
  247. package/esm/src/providers/openrouter/openai/sdk-messages.js +122 -0
  248. package/esm/src/providers/openrouter/resolve-api-key.d.ts +9 -0
  249. package/esm/src/providers/openrouter/resolve-api-key.js +24 -0
  250. package/esm/src/providers/openrouter/speech.d.ts +23 -0
  251. package/esm/src/providers/{speech.js → openrouter/speech.js} +32 -55
  252. package/esm/src/providers/probe.d.ts +1 -0
  253. package/esm/src/providers/probe.js +22 -0
  254. package/esm/src/providers/shared/pcm.d.ts +12 -0
  255. package/esm/src/providers/{pcm.js → shared/pcm.js} +16 -3
  256. package/esm/src/providers/shared/sse.d.ts +18 -0
  257. package/esm/src/providers/shared/sse.js +87 -0
  258. package/esm/src/providers/shared/tool-args.d.ts +17 -0
  259. package/esm/src/providers/shared/tool-args.js +45 -0
  260. package/esm/src/providers/shared/upstream-tap.d.ts +5 -0
  261. package/esm/src/providers/{google-tap.js → shared/upstream-tap.js} +4 -7
  262. package/esm/src/providers/shared/upstream-tape.d.ts +6 -0
  263. package/esm/src/providers/{gemini-tape.js → shared/upstream-tape.js} +12 -22
  264. package/esm/src/providers/types.d.ts +27 -0
  265. package/esm/src/providers/types.js +1 -0
  266. package/package.json +11 -7
  267. package/docs/cli.md +0 -97
  268. package/docs/guardrails.md +0 -178
  269. package/docs/host.md +0 -97
  270. package/docs/kernel.md +0 -404
  271. package/docs/observability.md +0 -105
  272. package/docs/openrouter.md +0 -125
  273. package/docs/presets-google.md +0 -91
  274. package/docs/presets.md +0 -88
  275. package/docs/providers.md +0 -202
  276. package/docs/streaming.md +0 -96
  277. package/esm/src/kernel/engine/boundary.d.ts +0 -10
  278. package/esm/src/kernel/engine/boundary.js +0 -55
  279. package/esm/src/kernel/engine/runner/tools.d.ts +0 -13
  280. package/esm/src/kernel/engine/runner/tools.js +0 -198
  281. package/esm/src/kernel/registry/tools.d.ts +0 -12
  282. package/esm/src/kernel/registry/tools.js +0 -36
  283. package/esm/src/providers/expose-for-tests.d.ts +0 -1
  284. package/esm/src/providers/expose-for-tests.js +0 -25
  285. package/esm/src/providers/gemini-tape.d.ts +0 -2
  286. package/esm/src/providers/google-tap.d.ts +0 -3
  287. package/esm/src/providers/interactions.d.ts +0 -5
  288. package/esm/src/providers/interactions.js +0 -169
  289. package/esm/src/providers/keys.d.ts +0 -19
  290. package/esm/src/providers/local.d.ts +0 -29
  291. package/esm/src/providers/openrouter-mod.d.ts +0 -13
  292. package/esm/src/providers/openrouter-mod.js +0 -12
  293. package/esm/src/providers/openrouter-payload.d.ts +0 -39
  294. package/esm/src/providers/openrouter-payload.js +0 -195
  295. package/esm/src/providers/openrouter.d.ts +0 -15
  296. package/esm/src/providers/pcm.d.ts +0 -7
  297. package/esm/src/providers/provider.d.ts +0 -15
  298. package/esm/src/providers/provider.js +0 -202
  299. package/esm/src/providers/speech.d.ts +0 -23
  300. package/esm/src/providers/sse.d.ts +0 -7
  301. package/esm/src/providers/sse.js +0 -55
  302. package/esm/src/streaming/mod.d.ts +0 -9
  303. package/esm/src/streaming/mod.js +0 -8
  304. /package/esm/src/{streaming → host}/readStreamingJsonStringField.d.ts +0 -0
  305. /package/esm/src/{streaming → host}/readStreamingJsonStringField.js +0 -0
@@ -1,106 +1,352 @@
1
1
  /**
2
2
  * Runtime profile registry for host-owned THEORUM profiles.
3
3
  *
4
- * THEORUM ships profile types and defaults, not application profiles. Host apps
5
- * register their profiles at process startup or test setup.
4
+ * THEORUM ships profile types — not application profiles and not invented defaults.
5
+ * Hosts must pass required fields explicitly (`type`, `models`, …).
6
6
  *
7
7
  * @module
8
8
  */
9
9
  import { TheorumError } from '../../guardrails/error.js';
10
+ import { HOST_GUARDRAIL_FIELDS, } from '../../guardrails/types.js';
11
+ import { resolveObservabilityPolicy } from '../../observability/resolve-policy.js';
12
+ import { assertLiveIngressConfigured } from '../engine/live-ingress.js';
13
+ import { CACHE_MODES, CACHE_TTLS, isValidPair, isValidProfileProtocol, protocolsForProfileType, } from '../schema.js';
14
+ import { isContinueStopKind } from '../stop.js';
15
+ import { getTool } from '../tools/registry.js';
16
+ import { soleModelId } from './sole-model.js';
10
17
  const profiles = new Map();
11
- function assertModelSpecs(profileId, allow, config) {
12
- for (const id of allow) {
13
- if (!config[id]) {
14
- throw new TheorumError(`Profile ${profileId} allowlists '${id}' without a model spec`);
18
+ /** Fields a `host` profile must not carry — rejected when supplied. */
19
+ const HOST_ABSENT_FIELDS = [
20
+ 'models',
21
+ 'defaultModel',
22
+ 'allowModelSelect',
23
+ 'identity',
24
+ 'inputs',
25
+ 'outputs',
26
+ 'turnBehaviour',
27
+ 'key',
28
+ 'maxSteps',
29
+ ];
30
+ /**
31
+ * Guardrails that only a model turn can run, so a host profile must not declare
32
+ * them: `egress` gates user-visible model text in the turn runner, `canary` is
33
+ * minted into a system prompt, and `quota` counts turns. None is reachable from
34
+ * `invokeTool`, so accepting them would register config that guards nothing.
35
+ */
36
+ const HOST_ABSENT_GUARDRAILS = ['quota', 'canary', 'egress'];
37
+ const HOST_GUARDRAIL_REASON = {
38
+ quota: 'quota counts model turns', // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
39
+ canary: 'canary is minted into a system prompt', // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
40
+ egress: 'egress gates user-visible model text in the turn runner', // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
41
+ };
42
+ function assertHostGuardrails(profileId, guardrails) {
43
+ if (!guardrails)
44
+ return;
45
+ const extra = guardrails;
46
+ for (const key of HOST_ABSENT_GUARDRAILS) {
47
+ if (extra[key] !== undefined) {
48
+ throw new TheorumError(`Profile ${profileId}: type 'host' must not set guardrails.${key} — a host profile runs no model and ${HOST_GUARDRAIL_REASON[key]}. Host profiles accept ${HOST_GUARDRAIL_FIELDS.join(', ')}.`);
15
49
  }
16
50
  }
17
51
  }
18
- function buildDefaultIdentity(id, identity) {
52
+ function defineHostProfile(input) {
53
+ const extra = input;
54
+ for (const key of HOST_ABSENT_FIELDS) {
55
+ if (extra[key] !== undefined) {
56
+ throw new TheorumError(`Profile ${input.id}: type 'host' must not set ${key}`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
57
+ }
58
+ }
59
+ assertHostGuardrails(input.id, input.guardrails);
60
+ assertHostTools(input.id, input.tools);
61
+ assertObservability(input.id, input.observability);
19
62
  return {
20
- handle: identity?.handle ?? id,
21
- chat: identity?.chat,
22
- system: identity?.system,
23
- systemByRole: identity?.systemByRole,
63
+ type: 'host',
64
+ id: input.id,
65
+ tools: { allow: input.tools.allow },
66
+ guardrails: input.guardrails,
67
+ observability: input.observability,
24
68
  };
25
69
  }
26
- function buildDefaultModel(profileId, model) {
27
- assertModelSpecs(profileId, model.allow, model.config);
28
- return {
29
- protocol: model.protocol ?? 'geminiInteractions',
30
- provider: model.provider ?? 'google',
31
- allow: model.allow,
32
- config: model.config,
33
- thinking: model.thinking ?? 'minimal',
34
- controls: model.controls ?? [],
35
- maxSteps: model.maxSteps ?? 1,
36
- key: model.key ?? 'freeA',
37
- select: model.select,
38
- };
70
+ function assertHostTools(profileId, tools) {
71
+ if (!Array.isArray(tools?.allow)) {
72
+ throw new TheorumError(`Profile ${profileId}: type 'host' must set tools.allow`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
73
+ }
74
+ const extra = tools;
75
+ if (extra.t1Policy !== undefined || extra.t2Loader !== undefined) {
76
+ throw new TheorumError(`Profile ${profileId}: tools.t1Policy / tools.t2Loader are not supported on type 'host' — every allowed tool is executable`);
77
+ }
39
78
  }
40
- function buildDefaultInputs(inputs) {
41
- return {
42
- text: inputs?.text ?? true,
43
- attachments: inputs?.attachments,
44
- voice: inputs?.voice,
45
- maxFiles: inputs?.maxFiles,
46
- maxBytes: inputs?.maxBytes,
47
- maxTurnBytes: inputs?.maxTurnBytes,
48
- limitsByMime: inputs?.limitsByMime,
49
- slots: inputs?.slots,
50
- };
79
+ function assertModelsNonEmpty(profileId, models) {
80
+ if (Object.keys(models).length === 0) {
81
+ throw new TheorumError(`Profile ${profileId} must declare at least one model`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
82
+ }
51
83
  }
52
- function buildDefaultOutputs(outputs) {
53
- return {
54
- structured: outputs?.structured ?? null,
55
- image: outputs?.image,
56
- speech: outputs?.speech,
57
- validation: outputs?.validation,
58
- streaming: outputs?.streaming,
59
- };
84
+ function assertDefaultModel(profileId, input) {
85
+ const ids = Object.keys(input.models);
86
+ const inferred = input.defaultModel ?? soleModelId(input.models);
87
+ if (!inferred) {
88
+ throw new TheorumError(`Profile ${profileId} must set defaultModel when more than one model is declared`);
89
+ }
90
+ if (!input.models[inferred]) {
91
+ throw new TheorumError(`Profile ${profileId} defaultModel '${inferred}' is not declared`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
92
+ }
93
+ if (input.allowModelSelect && ids.length < 2) {
94
+ throw new TheorumError(`Profile ${profileId} allowModelSelect requires at least two models`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
95
+ }
96
+ }
97
+ function assertModelBinding(profileId, modelId, binding) {
98
+ if (!binding.protocol) {
99
+ throw new TheorumError(`Profile ${profileId} model '${modelId}' must set protocol`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
100
+ }
101
+ if (!binding.provider) {
102
+ throw new TheorumError(`Profile ${profileId} model '${modelId}' must set provider`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
103
+ }
104
+ if (!binding.apiId) {
105
+ throw new TheorumError(`Profile ${profileId} model '${modelId}' must set apiId`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
106
+ }
107
+ if (!isValidPair(binding.protocol, binding.provider)) {
108
+ throw new TheorumError(`Profile ${profileId} model '${modelId}': protocol '${binding.protocol}' is not valid for provider '${binding.provider}'`);
109
+ }
110
+ assertModelEfforts(profileId, modelId, binding);
111
+ if (binding.cache) {
112
+ assertCacheSpec(profileId, modelId, binding);
113
+ }
114
+ assertInteractionsPersistence(profileId, modelId, binding);
60
115
  }
61
- function buildDefaultGuardrails(guardrails) {
116
+ function assertModelEfforts(profileId, modelId, binding) {
117
+ const efforts = binding.efforts;
118
+ if (!efforts || Object.keys(efforts).length === 0) {
119
+ if (binding.defaultEffort || binding.allowEffortSelect) {
120
+ throw new TheorumError(`Profile ${profileId} model '${modelId}': defaultEffort and allowEffortSelect require efforts`);
121
+ }
122
+ return;
123
+ }
124
+ const keys = Object.keys(efforts);
125
+ const defaultAlias = binding.defaultEffort ?? (keys.length === 1 ? keys[0] : undefined);
126
+ if (!defaultAlias) {
127
+ throw new TheorumError(`Profile ${profileId} model '${modelId}' must set defaultEffort when more than one effort is declared`);
128
+ }
129
+ if (!efforts[defaultAlias]) {
130
+ throw new TheorumError(`Profile ${profileId} model '${modelId}' defaultEffort '${defaultAlias}' is not declared`);
131
+ }
132
+ if (binding.allowEffortSelect && keys.length < 2) {
133
+ throw new TheorumError(`Profile ${profileId} model '${modelId}' allowEffortSelect requires at least two efforts`);
134
+ }
135
+ }
136
+ function assertTypeProtocols(profile) {
137
+ for (const [modelId, binding] of Object.entries(profile.models)) {
138
+ if (!isValidProfileProtocol(profile.type, binding.protocol)) {
139
+ const valid = protocolsForProfileType(profile.type).join(', ');
140
+ throw new TheorumError(`Profile ${profile.id} model '${modelId}': type '${profile.type}' cannot use protocol '${binding.protocol}'. Supported: ${valid}`);
141
+ }
142
+ }
143
+ }
144
+ function profileModelFields(input) {
62
145
  return {
63
- quota: guardrails?.quota,
64
- canary: guardrails?.canary ?? true,
65
- sanitizeInput: guardrails?.sanitizeInput ?? true,
66
- redactSensitive: guardrails?.redactSensitive ?? true,
67
- egress: guardrails?.egress,
146
+ models: input.models,
147
+ defaultModel: input.defaultModel ?? soleModelId(input.models),
148
+ allowModelSelect: input.allowModelSelect,
149
+ maxSteps: input.maxSteps,
150
+ key: input.key,
68
151
  };
69
152
  }
70
- /** Define a typed profile with stable defaults for optional properties. */
153
+ function assertContinueKindList(profileId, path, kinds) {
154
+ if (!kinds?.length)
155
+ return;
156
+ for (const kind of kinds) {
157
+ if (!isContinueStopKind(kind)) {
158
+ throw new TheorumError(`Profile ${profileId}: turnBehaviour.resumption.${path} may only include ContinueStopKind ` + // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
159
+ `(length | stream_incomplete | provider_error); got '${kind}'`);
160
+ }
161
+ }
162
+ }
163
+ function assertResumption(profileId, resumption) {
164
+ if (!resumption)
165
+ return;
166
+ assertContinueKindList(profileId, 'allowContinue', resumption.allowContinue);
167
+ assertContinueKindList(profileId, 'autoContinue', resumption.autoContinue);
168
+ }
169
+ function assertTurnBehaviour(profileId, input) {
170
+ if (input.type === 'host')
171
+ return;
172
+ if (input.type === 'live') {
173
+ const tb = input.turnBehaviour;
174
+ if (tb?.resumption !== undefined) {
175
+ throw new TheorumError(`Profile ${profileId}: type 'live' uses live.sessionResumption, not turnBehaviour.resumption`);
176
+ }
177
+ return;
178
+ }
179
+ if (input.type !== 'text' && input.turnBehaviour?.allowSteering !== undefined) {
180
+ throw new TheorumError(`Profile ${profileId}: turnBehaviour.allowSteering is only valid on type 'text' or 'live'`);
181
+ }
182
+ assertResumption(profileId, input.turnBehaviour?.resumption);
183
+ }
184
+ function assertObservability(profileId, spec) {
185
+ if (!spec) {
186
+ return;
187
+ }
188
+ try {
189
+ const policy = resolveObservabilityPolicy(spec);
190
+ if (policy.retainForDays <= 0 || !Number.isFinite(policy.retainForDays)) {
191
+ throw new TheorumError(`Profile ${profileId}: observability.retainForDays must be a positive number`);
192
+ }
193
+ if (policy.rotateAfterMiB <= 0 || !Number.isFinite(policy.rotateAfterMiB)) {
194
+ throw new TheorumError(`Profile ${profileId}: observability.rotateAfterMiB must be a positive number`);
195
+ }
196
+ }
197
+ catch (err) {
198
+ if (err instanceof TheorumError && err.message.startsWith('Profile ')) {
199
+ throw err;
200
+ }
201
+ const message = err instanceof Error ? err.message : String(err);
202
+ throw new TheorumError(`Profile ${profileId}: ${message}`);
203
+ }
204
+ }
71
205
  function defineProfile(input) {
72
- return {
73
- id: input.id,
74
- identity: buildDefaultIdentity(input.id, input.identity),
75
- model: buildDefaultModel(input.id, input.model),
76
- tools: { allow: input.tools?.allow ?? [] },
77
- inputs: buildDefaultInputs(input.inputs),
78
- outputs: buildDefaultOutputs(input.outputs),
79
- guardrails: buildDefaultGuardrails(input.guardrails),
206
+ if (input.type === 'host') {
207
+ return defineHostProfile(input);
208
+ }
209
+ assertModelsNonEmpty(input.id, input.models);
210
+ assertDefaultModel(input.id, input);
211
+ assertTurnBehaviour(input.id, input);
212
+ assertObservability(input.id, input.observability);
213
+ for (const [modelId, binding] of Object.entries(input.models)) {
214
+ assertModelBinding(input.id, modelId, binding);
215
+ }
216
+ const identity = {
217
+ handle: input.identity.handle,
218
+ system: input.identity.system,
219
+ systemByRole: input.identity.systemByRole,
80
220
  };
221
+ const guardrails = input.guardrails;
222
+ const observability = input.observability;
223
+ const modelFields = profileModelFields(input);
224
+ let profile;
225
+ switch (input.type) {
226
+ case 'text':
227
+ profile = {
228
+ type: 'text',
229
+ id: input.id,
230
+ identity,
231
+ ...modelFields,
232
+ tools: input.tools,
233
+ inputs: input.inputs,
234
+ outputs: input.outputs,
235
+ turnBehaviour: input.turnBehaviour,
236
+ guardrails,
237
+ observability,
238
+ };
239
+ break;
240
+ case 'image':
241
+ profile = {
242
+ type: 'image',
243
+ id: input.id,
244
+ identity,
245
+ ...modelFields,
246
+ image: input.image,
247
+ tools: input.tools,
248
+ inputs: input.inputs,
249
+ outputs: input.outputs,
250
+ turnBehaviour: input.turnBehaviour,
251
+ guardrails,
252
+ observability,
253
+ };
254
+ break;
255
+ case 'speech':
256
+ profile = {
257
+ type: 'speech',
258
+ id: input.id,
259
+ identity,
260
+ ...modelFields,
261
+ speech: input.speech,
262
+ outputs: input.outputs,
263
+ turnBehaviour: input.turnBehaviour,
264
+ guardrails,
265
+ observability,
266
+ };
267
+ break;
268
+ case 'live': {
269
+ const liveInput = input;
270
+ if (liveInput.inputs !== undefined) {
271
+ throw new TheorumError(`Profile ${input.id}: type 'live' must not set inputs`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
272
+ }
273
+ if (liveInput.outputs !== undefined) {
274
+ throw new TheorumError(`Profile ${input.id}: type 'live' must not set outputs`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
275
+ }
276
+ profile = {
277
+ type: 'live',
278
+ id: input.id,
279
+ identity,
280
+ ...modelFields,
281
+ live: input.live,
282
+ tools: assertLiveTools(input.id, input.tools),
283
+ turnBehaviour: liveInput.turnBehaviour,
284
+ guardrails,
285
+ observability,
286
+ };
287
+ assertLiveIngressConfigured(profile);
288
+ break;
289
+ }
290
+ default: {
291
+ const _exhaustive = input;
292
+ throw new TheorumError(`Unknown profile type '${String(_exhaustive)}'`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
293
+ }
294
+ }
295
+ assertTypeProtocols(profile);
296
+ return profile;
81
297
  }
82
298
  function assertCompactionSpec(profileId, modelId, spec) {
83
- const tag = `Profile ${profileId} model ${modelId} compaction`;
299
+ const tag = `Profile ${profileId} model ${modelId} compaction`; // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
84
300
  assertCompactionBudget(tag, spec);
85
301
  assertCompactionRetain(tag, spec);
86
302
  if (spec.meter != null && spec.meter !== 'history' && spec.meter !== 'input') {
87
- throw new TheorumError(`${tag}: meter must be 'history' or 'input'`);
303
+ throw new TheorumError(`${tag}: meter must be 'history' or 'input'`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
88
304
  }
89
305
  if (!profiles.has(spec.profile)) {
90
306
  throw new TheorumError(`${tag}: compaction profile '${spec.profile}' must be registered before '${profileId}'`);
91
307
  }
92
308
  }
309
+ function assertCacheSpec(profileId, modelId, binding) {
310
+ const spec = binding.cache;
311
+ if (!spec) {
312
+ return;
313
+ }
314
+ const tag = `Profile ${profileId} model '${modelId}'`;
315
+ if (binding.provider !== 'openrouter' || binding.protocol !== 'openAi') {
316
+ throw new TheorumError(`${tag}: cache is only valid when protocol is 'openAi' and provider is 'openrouter'`);
317
+ }
318
+ if (!CACHE_MODES.includes(spec.mode)) {
319
+ throw new TheorumError(`${tag}: cache.mode must be one of ${CACHE_MODES.join(' | ')}`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
320
+ }
321
+ if (spec.ttl != null && !CACHE_TTLS.includes(spec.ttl)) {
322
+ throw new TheorumError(`${tag}: cache.ttl must be one of ${CACHE_TTLS.join(' | ')}`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
323
+ }
324
+ }
325
+ function assertInteractionsPersistence(profileId, modelId, binding) {
326
+ if (binding.store === undefined && binding.persistViaInteractionId === undefined) {
327
+ return;
328
+ }
329
+ if (binding.protocol === 'geminiInteractions' && binding.provider === 'google') {
330
+ return;
331
+ }
332
+ const which = binding.store !== undefined && binding.persistViaInteractionId !== undefined
333
+ ? 'store and persistViaInteractionId' // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
334
+ : binding.store !== undefined
335
+ ? 'store'
336
+ : 'persistViaInteractionId';
337
+ throw new TheorumError(`Profile ${profileId} model '${modelId}': ${which} is only valid when protocol is 'geminiInteractions' and provider is 'google'`);
338
+ }
93
339
  function assertCompactionBudget(tag, spec) {
94
340
  if (spec.maxTokens <= 0) {
95
- throw new TheorumError(`${tag}: maxTokens must be > 0`);
341
+ throw new TheorumError(`${tag}: maxTokens must be > 0`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
96
342
  }
97
343
  if (spec.compactAt <= 0 || spec.compactAt >= 1) {
98
- throw new TheorumError(`${tag}: compactAt must be in (0, 1)`);
344
+ throw new TheorumError(`${tag}: compactAt must be in (0, 1)`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
99
345
  }
100
346
  }
101
347
  function assertCompactionRetain(tag, spec) {
102
348
  if (spec.previousExchanges < 0) {
103
- throw new TheorumError(`${tag}: previousExchanges must be >= 0`);
349
+ throw new TheorumError(`${tag}: previousExchanges must be >= 0`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
104
350
  }
105
351
  if (spec.previousExchanges > 0 && spec.previousExchanges < 1) {
106
352
  if (spec.previousExchanges >= spec.compactAt) {
@@ -108,22 +354,116 @@ function assertCompactionRetain(tag, spec) {
108
354
  }
109
355
  }
110
356
  if (spec.previousExchanges >= 1 && !Number.isInteger(spec.previousExchanges)) {
111
- throw new TheorumError(`${tag}: previousExchanges >= 1 must be an integer`);
357
+ throw new TheorumError(`${tag}: previousExchanges >= 1 must be an integer`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
112
358
  }
113
359
  }
114
- /** Register one host-owned profile in the process-local registry. */
115
- function registerProfile(profileInput) {
116
- const profile = defineProfile(profileInput);
117
- assertModelSpecs(profile.id, profile.model.allow, profile.model.config);
118
- const { attachments, voice, maxFiles, maxBytes, maxTurnBytes } = profile.inputs;
360
+ function profileToolsAllow(profile) {
361
+ if (profile.type === 'speech') {
362
+ return [];
363
+ }
364
+ return profile.tools.allow;
365
+ }
366
+ function assertCustomToolsOnly(profile) {
367
+ for (const id of profileToolsAllow(profile)) {
368
+ const tool = getTool(id);
369
+ if (tool?.type === 'builtin') {
370
+ throw new TheorumError(profile.type === 'host'
371
+ ? `Profile ${profile.id} lists builtin '${id}' in tools.allow — type 'host' never runs a model` // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
372
+ : `Profile ${profile.id} lists builtin '${id}' in tools.allow — declare it on models.*.builtInTools instead`);
373
+ }
374
+ }
375
+ }
376
+ function assertLiveTools(profileId, tools) {
377
+ const extra = tools;
378
+ if (extra.t1Policy !== undefined) {
379
+ throw new TheorumError(`Profile ${profileId}: tools.t1Policy is not supported on type 'live' — wire T0 tools in tools.allow for session setup`);
380
+ }
381
+ if (extra.t2Loader !== undefined) {
382
+ throw new TheorumError(`Profile ${profileId}: tools.t2Loader is not supported on type 'live' — Gemini Live function declarations are fixed at session setup`);
383
+ }
384
+ return { allow: tools.allow };
385
+ }
386
+ function assertProfileToolLoader(profile) {
387
+ if (profile.type === 'speech') {
388
+ return;
389
+ }
390
+ if (profile.type === 'live') {
391
+ assertLiveTools(profile.id, profile.tools);
392
+ return;
393
+ }
394
+ if (profile.type === 'host') {
395
+ assertHostTools(profile.id, profile.tools);
396
+ return;
397
+ }
398
+ const loaderId = profile.tools.t2Loader;
399
+ if (!loaderId) {
400
+ return;
401
+ }
402
+ if (!profile.tools.allow.includes(loaderId)) {
403
+ throw new TheorumError(`Profile ${profile.id} tools.t2Loader '${loaderId}' must also be listed in tools.allow`);
404
+ }
405
+ const tool = getTool(loaderId);
406
+ if (tool?.type !== 'function') {
407
+ throw new TheorumError(`Profile ${profile.id} tools.t2Loader '${loaderId}' must be a registered type: 'function' tool`);
408
+ }
409
+ }
410
+ /** Every builtin id declared across a profile's model bindings. */
411
+ function* modelBuiltinIds(profile) {
412
+ for (const [modelId, binding] of Object.entries(profile.models)) {
413
+ for (const id of binding.builtInTools ?? []) {
414
+ yield { modelId, id };
415
+ }
416
+ }
417
+ }
418
+ function assertModelBuiltInTools(profile) {
419
+ for (const { modelId, id } of modelBuiltinIds(profile)) {
420
+ const tool = getTool(id);
421
+ if (tool?.type !== 'builtin') {
422
+ throw new TheorumError(`Profile ${profile.id} model '${modelId}' lists '${id}' in builtInTools — not a registered builtin`);
423
+ }
424
+ }
425
+ }
426
+ function assertCompactionOnlyOnText(profile) {
427
+ if (profile.type === 'text') {
428
+ return;
429
+ }
430
+ for (const [modelId, binding] of Object.entries(profile.models)) {
431
+ if (binding.compaction) {
432
+ throw new TheorumError(`Profile ${profile.id} model '${modelId}': compaction is only valid on type 'text'`);
433
+ }
434
+ }
435
+ }
436
+ function assertMediaLimits(profile) {
437
+ if (profile.type === 'speech' || profile.type === 'live') {
438
+ return;
439
+ }
440
+ const inputs = profile.inputs;
441
+ if (!inputs) {
442
+ return;
443
+ }
444
+ const { attachments, voice, maxFiles, maxBytes, maxTurnBytes } = inputs;
119
445
  if (attachments || voice) {
120
446
  if (!(maxFiles && maxBytes && maxTurnBytes)) {
121
- throw new TheorumError(`Profile ${profile.id} must set maxFiles, maxBytes, and maxTurnBytes`);
447
+ throw new TheorumError(`Profile ${profile.id} must set maxFiles, maxBytes, and maxTurnBytes`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
122
448
  }
123
449
  }
124
- for (const [modelId, spec] of Object.entries(profile.model.config)) {
125
- if (spec.compaction) {
126
- assertCompactionSpec(profile.id, modelId, spec.compaction);
450
+ }
451
+ /** Register one host-owned profile in the process-local registry. */
452
+ function registerProfile(profileInput) {
453
+ const profile = defineProfile(profileInput);
454
+ assertCustomToolsOnly(profile);
455
+ assertProfileToolLoader(profile);
456
+ if (profile.type === 'host') {
457
+ // No models, ingress, media limits, or compaction to validate — the tool ceiling is the whole contract.
458
+ profiles.set(profile.id, profile);
459
+ return;
460
+ }
461
+ assertModelBuiltInTools(profile);
462
+ assertCompactionOnlyOnText(profile);
463
+ assertMediaLimits(profile);
464
+ for (const [modelId, binding] of Object.entries(profile.models)) {
465
+ if (binding.compaction) {
466
+ assertCompactionSpec(profile.id, modelId, binding.compaction);
127
467
  }
128
468
  }
129
469
  profiles.set(profile.id, profile);
@@ -1,25 +1,31 @@
1
1
  /** Build the provider request projection shared by execution and tracing. */
2
2
  function providerCompleteRequest(generation, system) {
3
+ const isInteractions = generation.transport === 'interactions';
3
4
  return {
4
5
  model: generation.model,
5
6
  apiId: generation.apiId,
6
- openRouterId: generation.openRouterId,
7
- previousInteractionId: generation.previousInteractionId,
8
- store: generation.store,
7
+ previousInteractionId: isInteractions ? generation.previousInteractionId : undefined,
8
+ store: isInteractions ? generation.store : undefined,
9
+ stream: isInteractions ? generation.stream : undefined,
9
10
  thinking: generation.thinking,
10
- summaries: generation.summaries,
11
+ summaries: isInteractions ? generation.summaries : undefined,
11
12
  maxOutputTokens: generation.maxOutputTokens,
12
13
  temperature: generation.temperature,
13
14
  builtins: generation.builtins,
15
+ googleMapsLocation: isInteractions ? generation.googleMapsLocation : undefined,
16
+ cache: generation.cache,
17
+ sessionId: generation.sessionId,
14
18
  system,
15
19
  input: generation.input,
16
20
  history: generation.history,
17
- dynamicTools: generation.dynamicTools,
18
- dynamicToolLoader: generation.dynamicToolLoader,
21
+ interactionOnlyInput: isInteractions ? generation.interactionOnlyInput : undefined,
22
+ wireTools: generation.tools.wire,
19
23
  structured: generation.structured,
20
24
  image: generation.image,
21
25
  speech: generation.speech,
22
- geminiBucket: generation.geminiBucket,
26
+ live: generation.live,
27
+ sessionResumptionHandle: generation.sessionResumptionHandle,
28
+ keySlot: generation.keySlot,
23
29
  };
24
30
  }
25
31
  export { providerCompleteRequest };
@@ -1,19 +1,19 @@
1
1
  /**
2
2
  * Profile resolution for THEORUM turns.
3
3
  *
4
- * This module validates caller overrides, selects models and tools, normalizes
5
- * input parts, and produces the provider request state consumed by `runTurn`.
6
- *
7
4
  * @module
8
5
  */
9
- import type { Profile, ProjectedProfile, ResolvedGeneration, ToolId, TurnRequest } from '../types.js';
10
- declare function assertToolAllowed(profile: Profile, name: ToolId): void;
6
+ import type { ModelId, ModelProfile, Profile, ProjectedProfile, ResolvedGeneration, TurnRequest } from '../types.js';
7
+ /** Narrow to a model-binding profile; `host` never runs a model. */
8
+ declare function requireModelProfile(profile: Profile, door: string): ModelProfile;
9
+ declare function pickModel(profile: ModelProfile, requested?: string): ModelId;
11
10
  /** Resolve a host `TurnRequest` into provider-ready generation state. */
12
11
  declare function resolveTurn(req: TurnRequest): {
13
- profile: Profile;
12
+ profile: ModelProfile;
14
13
  generation: ResolvedGeneration;
15
14
  };
15
+ /** Project a profile object into a safe host/UI inspection object. */
16
+ declare function projectProfileObject(input: Profile): ProjectedProfile;
16
17
  /** Project a registered profile into a safe host/UI inspection object. */
17
18
  declare function projectProfile(id: Profile['id']): ProjectedProfile;
18
- declare function pickSystemRole(profile: Profile, requested?: string): string;
19
- export { assertToolAllowed, pickSystemRole, projectProfile, resolveTurn };
19
+ export { pickModel, projectProfile, projectProfileObject, requireModelProfile, resolveTurn };