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
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Profile graph — playground / authoring topology projected from PROFILE_FIELDS.
3
+ *
4
+ * This is not runtime policy. It declares which profile sections are graph
5
+ * facets, for which ProfileType, whether they may be omitted, and whether the
6
+ * host UI uses a schema form or a structural editor. The playground must import
7
+ * this catalog; it must not invent FacetKind unions.
8
+ *
9
+ * @module
10
+ */
11
+ import type { ProfileType } from './schema.js';
12
+ /** How the playground (or other host UI) should edit this facet. */
13
+ export type ProfileGraphEditor = 'schema' | 'structural';
14
+ /** Where the facet sits in the authoring graph. */
15
+ export type ProfileGraphRole = 'root' | 'spine' | 'branch';
16
+ /**
17
+ * Authoring-graph catalog. Adding a profile section? Add PROFILE_FIELDS and a row
18
+ * here — never a FacetKind in the frontend.
19
+ *
20
+ * `ProfileGraphFacetId` is derived from this array; do not maintain a union by hand.
21
+ */
22
+ declare const PROFILE_GRAPH_DEF: readonly [{
23
+ readonly id: "identity";
24
+ readonly profilePath: "identity";
25
+ readonly role: "root";
26
+ readonly profileTypes: readonly ("text" | "image" | "speech" | "live" | "host")[];
27
+ readonly optional: false;
28
+ readonly editor: "structural";
29
+ readonly label: "Identity";
30
+ readonly ownsFields: readonly ["id", "type"];
31
+ }, {
32
+ readonly id: "models";
33
+ readonly profilePath: "models";
34
+ readonly role: "spine";
35
+ readonly profileTypes: readonly ("text" | "image" | "speech" | "live" | "host")[];
36
+ readonly optional: false;
37
+ readonly editor: "structural";
38
+ readonly label: "Models";
39
+ readonly ownsFields: readonly ["defaultModel", "allowModelSelect", "maxSteps", "key"];
40
+ }, {
41
+ readonly id: "modelBinding";
42
+ readonly profilePath: "models.*";
43
+ readonly role: "branch";
44
+ readonly parent: "models";
45
+ readonly profileTypes: readonly ("text" | "image" | "speech" | "live" | "host")[];
46
+ readonly optional: false;
47
+ readonly editor: "structural";
48
+ readonly label: "Model binding";
49
+ }, {
50
+ readonly id: "image";
51
+ readonly profilePath: "image";
52
+ readonly role: "spine";
53
+ readonly profileTypes: readonly ["image"];
54
+ readonly optional: false;
55
+ readonly editor: "structural";
56
+ readonly label: "Image";
57
+ }, {
58
+ readonly id: "speech";
59
+ readonly profilePath: "speech";
60
+ readonly role: "spine";
61
+ readonly profileTypes: readonly ["speech"];
62
+ readonly optional: false;
63
+ readonly editor: "structural";
64
+ readonly label: "Speech";
65
+ }, {
66
+ readonly id: "live";
67
+ readonly profilePath: "live";
68
+ readonly role: "spine";
69
+ readonly profileTypes: readonly ["live"];
70
+ readonly optional: false;
71
+ readonly editor: "structural";
72
+ readonly label: "Live";
73
+ }, {
74
+ readonly id: "tools";
75
+ readonly profilePath: "tools";
76
+ readonly role: "spine";
77
+ readonly profileTypes: readonly ["text", "image", "live", "host"];
78
+ readonly optional: false;
79
+ readonly editor: "structural";
80
+ readonly label: "Tools";
81
+ }, {
82
+ readonly id: "toolSpec";
83
+ readonly profilePath: "tools.allow";
84
+ readonly role: "branch";
85
+ readonly parent: "tools";
86
+ readonly profileTypes: readonly ["text", "image", "live", "host"];
87
+ readonly optional: true;
88
+ readonly editor: "structural";
89
+ readonly label: "Tool";
90
+ }, {
91
+ readonly id: "inputs";
92
+ readonly profilePath: "inputs";
93
+ readonly role: "spine";
94
+ readonly profileTypes: readonly ["text", "image"];
95
+ readonly optional: false;
96
+ readonly editor: "structural";
97
+ readonly label: "Inputs";
98
+ }, {
99
+ readonly id: "outputs";
100
+ readonly profilePath: "outputs";
101
+ readonly role: "spine";
102
+ readonly profileTypes: readonly ["text", "image", "speech"];
103
+ readonly optional: true;
104
+ readonly editor: "structural";
105
+ readonly label: "Outputs";
106
+ }, {
107
+ readonly id: "turnBehaviour";
108
+ readonly profilePath: "turnBehaviour";
109
+ readonly role: "spine";
110
+ readonly profileTypes: readonly ["text", "image", "speech", "live"];
111
+ readonly optional: true;
112
+ readonly editor: "structural";
113
+ readonly label: "Turn behaviour";
114
+ }, {
115
+ readonly id: "guardrails";
116
+ readonly profilePath: "guardrails";
117
+ readonly role: "spine";
118
+ readonly profileTypes: readonly ("text" | "image" | "speech" | "live" | "host")[];
119
+ readonly optional: true;
120
+ readonly editor: "structural";
121
+ readonly label: "Guardrails";
122
+ }, {
123
+ readonly id: "observability";
124
+ readonly profilePath: "observability";
125
+ readonly role: "spine";
126
+ readonly profileTypes: readonly ("text" | "image" | "speech" | "live" | "host")[];
127
+ readonly optional: true;
128
+ readonly editor: "structural";
129
+ readonly label: "Observability";
130
+ }];
131
+ /** Stable facet ids — derived from PROFILE_GRAPH; never hand-maintained. */
132
+ export type ProfileGraphFacetId = (typeof PROFILE_GRAPH_DEF)[number]['id'];
133
+ /**
134
+ * One node kind on the profile authoring graph.
135
+ *
136
+ * `profilePath` is a PROFILE_FIELDS key (section root) or a dynamic path
137
+ * (`models.*`). Branch facets nest under `parent`.
138
+ */
139
+ export interface ProfileGraphFacet {
140
+ id: ProfileGraphFacetId;
141
+ profilePath: string;
142
+ role: ProfileGraphRole;
143
+ parent?: ProfileGraphFacetId;
144
+ profileTypes: readonly ProfileType[];
145
+ optional: boolean;
146
+ editor: ProfileGraphEditor;
147
+ label: string;
148
+ /**
149
+ * Extra PROFILE_FIELDS top-level keys owned by this facet (not 1:1 with id).
150
+ * Used by the drift gate so `defaultModel` / `id` / `type` are not orphaned.
151
+ */
152
+ ownsFields?: readonly string[];
153
+ }
154
+ export declare const PROFILE_GRAPH: readonly ProfileGraphFacet[];
155
+ /** Spine (and root) facets visible for a profile type, in catalog order. */
156
+ declare function spineFacetsForProfileType(type: ProfileType): ProfileGraphFacet[];
157
+ /** Look up a graph facet by id. */
158
+ declare function profileGraphFacet(id: ProfileGraphFacetId): ProfileGraphFacet | undefined;
159
+ export { profileGraphFacet, spineFacetsForProfileType };
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Profile graph — playground / authoring topology projected from PROFILE_FIELDS.
3
+ *
4
+ * This is not runtime policy. It declares which profile sections are graph
5
+ * facets, for which ProfileType, whether they may be omitted, and whether the
6
+ * host UI uses a schema form or a structural editor. The playground must import
7
+ * this catalog; it must not invent FacetKind unions.
8
+ *
9
+ * @module
10
+ */
11
+ /**
12
+ * Mirrors PROFILE_TYPES — value import would cycle through schema re-exports.
13
+ * Drift is gated by tests/kernel/profile-graph.test.ts.
14
+ */
15
+ const ALL = ['text', 'image', 'speech', 'live', 'host'];
16
+ /** Types that bind models — `host` never runs a model. */
17
+ const MODEL_TYPES = ['text', 'image', 'speech', 'live'];
18
+ /**
19
+ * Authoring-graph catalog. Adding a profile section? Add PROFILE_FIELDS and a row
20
+ * here — never a FacetKind in the frontend.
21
+ *
22
+ * `ProfileGraphFacetId` is derived from this array; do not maintain a union by hand.
23
+ */
24
+ const PROFILE_GRAPH_DEF = [
25
+ {
26
+ id: 'identity',
27
+ profilePath: 'identity',
28
+ role: 'root',
29
+ profileTypes: ALL,
30
+ optional: false,
31
+ editor: 'structural',
32
+ label: 'Identity',
33
+ ownsFields: ['id', 'type'],
34
+ },
35
+ {
36
+ id: 'models',
37
+ profilePath: 'models',
38
+ role: 'spine',
39
+ profileTypes: MODEL_TYPES,
40
+ optional: false,
41
+ editor: 'structural',
42
+ label: 'Models',
43
+ ownsFields: ['defaultModel', 'allowModelSelect', 'maxSteps', 'key'],
44
+ },
45
+ {
46
+ id: 'modelBinding',
47
+ profilePath: 'models.*',
48
+ role: 'branch',
49
+ parent: 'models',
50
+ profileTypes: MODEL_TYPES,
51
+ optional: false,
52
+ editor: 'structural',
53
+ label: 'Model binding',
54
+ },
55
+ {
56
+ id: 'image',
57
+ profilePath: 'image',
58
+ role: 'spine',
59
+ profileTypes: ['image'],
60
+ optional: false,
61
+ editor: 'structural',
62
+ label: 'Image',
63
+ },
64
+ {
65
+ id: 'speech',
66
+ profilePath: 'speech',
67
+ role: 'spine',
68
+ profileTypes: ['speech'],
69
+ optional: false,
70
+ editor: 'structural',
71
+ label: 'Speech',
72
+ },
73
+ {
74
+ id: 'live',
75
+ profilePath: 'live',
76
+ role: 'spine',
77
+ profileTypes: ['live'],
78
+ optional: false,
79
+ editor: 'structural',
80
+ label: 'Live',
81
+ },
82
+ {
83
+ id: 'tools',
84
+ profilePath: 'tools',
85
+ role: 'spine',
86
+ profileTypes: ['text', 'image', 'live', 'host'],
87
+ optional: false,
88
+ editor: 'structural',
89
+ label: 'Tools',
90
+ },
91
+ {
92
+ id: 'toolSpec',
93
+ profilePath: 'tools.allow',
94
+ role: 'branch',
95
+ parent: 'tools',
96
+ profileTypes: ['text', 'image', 'live', 'host'],
97
+ optional: true,
98
+ editor: 'structural',
99
+ label: 'Tool',
100
+ },
101
+ {
102
+ id: 'inputs',
103
+ profilePath: 'inputs',
104
+ role: 'spine',
105
+ profileTypes: ['text', 'image'],
106
+ optional: false,
107
+ editor: 'structural',
108
+ label: 'Inputs',
109
+ },
110
+ {
111
+ id: 'outputs',
112
+ profilePath: 'outputs',
113
+ role: 'spine',
114
+ profileTypes: ['text', 'image', 'speech'],
115
+ optional: true,
116
+ editor: 'structural',
117
+ label: 'Outputs',
118
+ },
119
+ {
120
+ id: 'turnBehaviour',
121
+ profilePath: 'turnBehaviour',
122
+ role: 'spine',
123
+ profileTypes: ['text', 'image', 'speech', 'live'],
124
+ optional: true,
125
+ editor: 'structural',
126
+ label: 'Turn behaviour',
127
+ },
128
+ {
129
+ id: 'guardrails',
130
+ profilePath: 'guardrails',
131
+ role: 'spine',
132
+ profileTypes: ALL,
133
+ optional: true,
134
+ editor: 'structural',
135
+ label: 'Guardrails',
136
+ },
137
+ {
138
+ id: 'observability',
139
+ profilePath: 'observability',
140
+ role: 'spine',
141
+ profileTypes: ALL,
142
+ optional: true,
143
+ editor: 'structural',
144
+ label: 'Observability',
145
+ },
146
+ ];
147
+ export const PROFILE_GRAPH = PROFILE_GRAPH_DEF;
148
+ /** Spine (and root) facets visible for a profile type, in catalog order. */
149
+ function spineFacetsForProfileType(type) {
150
+ return PROFILE_GRAPH.filter((facet) => (facet.role === 'root' || facet.role === 'spine') && facet.profileTypes.includes(type));
151
+ }
152
+ /** Look up a graph facet by id. */
153
+ function profileGraphFacet(id) {
154
+ return PROFILE_GRAPH.find((facet) => facet.id === id);
155
+ }
156
+ export { profileGraphFacet, spineFacetsForProfileType };
@@ -1,16 +1,18 @@
1
- import type { MediaLimits, Profile, TurnBlob } from '../types.js';
2
- declare function tooManyFilesMessage(maxFiles: number): string;
3
- declare function fileTooLargeMessage(maxBytes: number): string;
4
- declare function turnTooLargeMessage(maxTurnBytes: number): string;
1
+ import type { MediaLimits, MimeInputs, Profile, TurnBlob, TurnMediaRef } from '../types.js';
2
+ declare function resolveMediaLimits(inputs: MimeInputs): MediaLimits | undefined;
3
+ declare function maxBytesForMime(mimeType: string, limits: MediaLimits): number;
4
+ /** Attachment supplied by provider file reference — no bytes to size-check or sanitize. */
5
+ declare function isTurnMediaRef(item: TurnBlob | TurnMediaRef): item is TurnMediaRef;
5
6
  declare function requireMediaLimits(profile: Profile): MediaLimits;
6
7
  declare function sanitizeCsvText(text: string): string;
7
- declare function assertAttachmentLimits(blobs: TurnBlob[], limits: MediaLimits): void;
8
- declare function sanitizeTurnBlobs(attachments: TurnBlob[] | undefined, voice: TurnBlob[] | undefined, limits: MediaLimits | undefined): {
9
- attachments?: TurnBlob[];
8
+ /** Enforce file count on every attachment; base64 and byte limits only on inline blobs. */
9
+ declare function assertAttachmentLimits(attachments: Array<TurnBlob | TurnMediaRef>, limits: MediaLimits): void;
10
+ declare function sanitizeTurnBlobs(attachments: Array<TurnBlob | TurnMediaRef> | undefined, voice: TurnBlob[] | undefined, limits: MediaLimits | undefined): {
11
+ attachments?: Array<TurnBlob | TurnMediaRef>;
10
12
  voice?: TurnBlob[];
11
13
  };
12
- declare function sanitizeTurnBlobsForProfile(profileId: string, attachments: TurnBlob[] | undefined, voice: TurnBlob[] | undefined): {
13
- attachments?: TurnBlob[];
14
+ declare function sanitizeTurnBlobsForProfile(profileId: string, attachments: Array<TurnBlob | TurnMediaRef> | undefined, voice: TurnBlob[] | undefined): {
15
+ attachments?: Array<TurnBlob | TurnMediaRef>;
14
16
  voice?: TurnBlob[];
15
17
  };
16
- export { assertAttachmentLimits, fileTooLargeMessage, requireMediaLimits, sanitizeCsvText, sanitizeTurnBlobs, sanitizeTurnBlobsForProfile, tooManyFilesMessage, turnTooLargeMessage, };
18
+ export { assertAttachmentLimits, isTurnMediaRef, maxBytesForMime, requireMediaLimits, resolveMediaLimits, sanitizeCsvText, sanitizeTurnBlobs, sanitizeTurnBlobsForProfile, };
@@ -1,5 +1,6 @@
1
1
  import { TheorumError } from '../../guardrails/error.js';
2
2
  import { injectionSpans } from '../../guardrails/injection.js';
3
+ import { lexiconText } from '../../guardrails/lexicon.js';
3
4
  import { sensitiveSpans } from '../../guardrails/sensitive.js';
4
5
  import { applySpans } from '../../observability/spans.js';
5
6
  import { getProfile } from './profiles.js';
@@ -9,23 +10,7 @@ const B64_TRIPLET = 3;
9
10
  const CSV_FORMULA = /(^|,)(\s*)("?)(?:([=@])|([+-])(?![0-9."]))/gm;
10
11
  const B64_BODY = /^[A-Za-z0-9+/]*={0,2}$/;
11
12
  const TEXT_MIMES = new Set(['text/csv', 'text/plain', 'text/markdown']);
12
- const BYTES_PER_KIB = 1024;
13
- function formatMb(bytes) {
14
- const mb = bytes / (BYTES_PER_KIB * BYTES_PER_KIB);
15
- return Number.isInteger(mb) ? `${String(mb)} MB` : `${mb.toFixed(1)} MB`;
16
- }
17
- function tooManyFilesMessage(maxFiles) {
18
- return maxFiles === 1
19
- ? 'Only 1 file per message.'
20
- : `Only ${String(maxFiles)} files per message.`;
21
- }
22
- function fileTooLargeMessage(maxBytes) {
23
- return `Each file must be ${formatMb(maxBytes)} or smaller.`;
24
- }
25
- function turnTooLargeMessage(maxTurnBytes) {
26
- return `Those files together are too large for one message (${formatMb(maxTurnBytes)} max).`;
27
- }
28
- function mediaLimits(inputs) {
13
+ function resolveMediaLimits(inputs) {
29
14
  const { maxFiles, maxBytes, maxTurnBytes, limitsByMime } = inputs;
30
15
  if (maxFiles && maxBytes && maxTurnBytes) {
31
16
  return { maxFiles, maxBytes, maxTurnBytes, limitsByMime };
@@ -46,10 +31,23 @@ function maxBytesForMime(mimeType, limits) {
46
31
  }
47
32
  return limits.maxBytes;
48
33
  }
34
+ /** Attachment supplied by provider file reference — no bytes to size-check or sanitize. */
35
+ function isTurnMediaRef(item) {
36
+ return 'uri' in item;
37
+ }
49
38
  function requireMediaLimits(profile) {
50
- const limits = mediaLimits(profile.inputs);
39
+ if (profile.type === 'speech') {
40
+ throw new TheorumError(`Profile ${profile.id} (speech) does not accept media input`); // lexicon-exempt: developer contract error
41
+ }
42
+ if (profile.type === 'live') {
43
+ throw new TheorumError(`Profile ${profile.id} (live) does not accept turn attachment input`); // lexicon-exempt: developer contract error
44
+ }
45
+ if (profile.type === 'host') {
46
+ throw new TheorumError(`Profile ${profile.id} (host) does not accept turn input`); // lexicon-exempt: developer contract error
47
+ }
48
+ const limits = resolveMediaLimits(profile.inputs ?? {});
51
49
  if (!limits) {
52
- throw new TheorumError(`Profile ${profile.id} must set maxFiles, maxBytes, and maxTurnBytes`);
50
+ throw new TheorumError(`Profile ${profile.id} must set maxFiles, maxBytes, and maxTurnBytes`); // lexicon-exempt: developer contract error
53
51
  }
54
52
  return limits;
55
53
  }
@@ -99,28 +97,36 @@ function sanitizeTextBytes(mime, bytes) {
99
97
  }
100
98
  return new TextEncoder().encode(applySpans(text, [...injectionSpans(text), ...sensitiveSpans(text)]));
101
99
  }
102
- function assertAttachmentLimits(blobs, limits) {
103
- if (blobs.length > limits.maxFiles) {
104
- throw new TheorumError(tooManyFilesMessage(limits.maxFiles));
100
+ /** Enforce file count on every attachment; base64 and byte limits only on inline blobs. */
101
+ function assertAttachmentLimits(attachments, limits) {
102
+ if (attachments.length > limits.maxFiles) {
103
+ throw new TheorumError(lexiconText('attachments.too_many_files', { maxFiles: limits.maxFiles }));
105
104
  }
106
105
  let total = 0;
107
- for (const blob of blobs) {
106
+ for (const blob of attachments) {
107
+ if (isTurnMediaRef(blob)) {
108
+ continue;
109
+ }
108
110
  const { data, mimeType } = blob;
109
111
  if (!B64_BODY.test(data)) {
112
+ // lexicon-exempt: developer-facing wire-format diagnostic, not product copy
110
113
  throw new TheorumError('attachment data must be base64');
111
114
  }
112
115
  const size = b64DecodedLen(data);
113
116
  const maxAllowed = maxBytesForMime(mimeType, limits);
114
117
  if (size > maxAllowed) {
115
- throw new TheorumError(fileTooLargeMessage(maxAllowed));
118
+ throw new TheorumError(lexiconText('attachments.file_too_large', { maxBytes: maxAllowed }));
116
119
  }
117
120
  total += size;
118
121
  }
119
122
  if (total > limits.maxTurnBytes) {
120
- throw new TheorumError(turnTooLargeMessage(limits.maxTurnBytes));
123
+ throw new TheorumError(lexiconText('attachments.turn_too_large', { maxTurnBytes: limits.maxTurnBytes }));
121
124
  }
122
125
  }
123
126
  function sanitizeAttachment(blob) {
127
+ if (isTurnMediaRef(blob)) {
128
+ return blob;
129
+ }
124
130
  const { mimeType, data } = blob;
125
131
  if (!TEXT_MIMES.has(mimeType.split(';')[0]?.trim().toLowerCase() ?? '')) {
126
132
  return blob;
@@ -138,7 +144,7 @@ function sanitizeTurnBlobs(attachments, voice, limits) {
138
144
  const files = attachments ?? [];
139
145
  const clips = voice ?? [];
140
146
  if (!limits) {
141
- throw new TheorumError('This profile does not accept files.');
147
+ throw new TheorumError(lexiconText('attachments.not_accepted', { channel: 'file' }));
142
148
  }
143
149
  assertAttachmentLimits([...files, ...clips], limits);
144
150
  return {
@@ -153,4 +159,4 @@ function sanitizeTurnBlobsForProfile(profileId, attachments, voice) {
153
159
  const limits = requireMediaLimits(getProfile(profileId));
154
160
  return sanitizeTurnBlobs(attachments, voice, limits);
155
161
  }
156
- export { assertAttachmentLimits, fileTooLargeMessage, requireMediaLimits, sanitizeCsvText, sanitizeTurnBlobs, sanitizeTurnBlobsForProfile, tooManyFilesMessage, turnTooLargeMessage, };
162
+ export { assertAttachmentLimits, isTurnMediaRef, maxBytesForMime, requireMediaLimits, resolveMediaLimits, sanitizeCsvText, sanitizeTurnBlobs, sanitizeTurnBlobsForProfile, };
@@ -1,31 +1,32 @@
1
1
  /**
2
- * Tool catalog and MIME helpers.
3
- *
4
- * Model wire metadata is host-owned on `profile.model.config`. This module only
5
- * keeps builtin/custom tool descriptors and shared MIME utilities.
2
+ * MIME helpers and model binding utilities.
6
3
  *
7
4
  * @module
8
5
  */
9
- import type { BuiltinToolId, Catalog, MediaInputKind, ModelId, ModelSpec, Profile, ThinkingLevel, ToolCatalogEntry, ToolId } from '../types.js';
10
- /** Live tool catalog. Starts with harness tools; presets/hosts register more. */
11
- declare const CATALOG: Catalog;
12
- /** Register or replace tool descriptors (idempotent per id). */
13
- declare function registerTools(entries: Record<string, ToolCatalogEntry>): void;
14
- /** Look up one registered tool descriptor. */
15
- declare function getTool(id: ToolId): ToolCatalogEntry | undefined;
16
- /** Ids of all registered provider builtins. */
17
- declare function listBuiltinIds(): BuiltinToolId[];
18
- /** Restore harness-only tools (tests / host reloads). */
19
- declare function resetTools(): void;
6
+ import type { MediaInputKind, ModelBinding, ModelId, ModelProfile, Profile, ThinkingLevel } from '../types.js';
7
+ /** `TurnInput` field a media file rides in. */
8
+ type MediaInputChannel = 'attachments' | 'voice';
20
9
  declare function mimeEssence(mime: string): string;
21
10
  declare function mimeAllowed(accept: string[], mime: string): boolean;
22
11
  declare function mediaKindForMime(mime: string): MediaInputKind | undefined;
23
- /** Require a host-declared model spec for an allowed profile model id. */
24
- declare function requireModelSpec(profile: Profile, modelId: ModelId): ModelSpec;
25
- /** Clamp a requested thinking level to what the model spec accepts. */
26
- declare function clampThinkingLevel(spec: ModelSpec, level: ThinkingLevel): ThinkingLevel;
27
- /** Look up a model spec by provider-native API id within a host specs map. */
28
- declare function modelEntryByApiId(specs: Record<string, ModelSpec>, apiId: string): ModelSpec | undefined;
29
- /** Clamp thinking level using a provider-native API id within a host specs map. */
30
- declare function clampThinkingLevelForApiId(specs: Record<string, ModelSpec>, apiId: string, level: ThinkingLevel): ThinkingLevel;
31
- export { CATALOG, clampThinkingLevel, clampThinkingLevelForApiId, getTool, listBuiltinIds, mediaKindForMime, mimeAllowed, mimeEssence, modelEntryByApiId, registerTools, requireModelSpec, resetTools, };
12
+ /** The `accept` list a profile declares for one input channel, if it declares one. */
13
+ declare function profileAccept(profile: Profile, channel: MediaInputChannel): string[] | undefined;
14
+ /**
15
+ * Which `TurnInput` channel of a profile accepts this MIME, or `undefined` when
16
+ * the profile accepts it nowhere (or the kernel cannot classify it at all).
17
+ *
18
+ * The one public answer to "does this profile take this file". Hosts route and
19
+ * filter channel ingress with it instead of keeping their own MIME table: the
20
+ * profile's `accept` lists are the whole declaration.
21
+ */
22
+ declare function mediaChannelForMime(profile: Profile, mime: string): MediaInputChannel | undefined;
23
+ /** Require a host-declared model binding for a profile model id. */
24
+ declare function requireModelBinding(profile: ModelProfile, modelId: ModelId): ModelBinding;
25
+ /** Clamp a requested thinking level to what the model binding accepts. */
26
+ declare function clampThinkingLevel(binding: ModelBinding, level: ThinkingLevel): ThinkingLevel;
27
+ /** Look up a model binding by provider-native API id within a host map. */
28
+ declare function modelEntryByApiId(bindings: Record<string, ModelBinding>, apiId: string): ModelBinding | undefined;
29
+ /** Clamp thinking level using a provider-native API id within a host map. */
30
+ declare function clampThinkingLevelForApiId(bindings: Record<string, ModelBinding>, apiId: string, level: ThinkingLevel): ThinkingLevel;
31
+ export type { MediaInputChannel };
32
+ export { clampThinkingLevel, clampThinkingLevelForApiId, mediaChannelForMime, mediaKindForMime, mimeAllowed, mimeEssence, modelEntryByApiId, profileAccept, requireModelBinding, };