theorum 1.0.0 → 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 (204) hide show
  1. package/README.md +81 -25
  2. package/esm/mod.d.ts +48 -29
  3. package/esm/mod.js +37 -24
  4. package/esm/src/cli/commands/bench.js +13 -16
  5. package/esm/src/cli/commands/fuzz-canary.js +25 -29
  6. package/esm/src/cli/commands/guardrails-eval.d.ts +14 -0
  7. package/esm/src/cli/commands/guardrails-eval.js +15 -0
  8. package/esm/src/cli/commands/profile.js +12 -3
  9. package/esm/src/cli/commands/run.js +8 -9
  10. package/esm/src/cli/commands/test.js +8 -8
  11. package/esm/src/cli/event-log.d.ts +1 -1
  12. package/esm/src/cli/index.js +12 -0
  13. package/esm/src/cli/matrix/synthesizer.d.ts +6 -6
  14. package/esm/src/cli/matrix/synthesizer.js +23 -22
  15. package/esm/src/guardrails/canary-gate.d.ts +2 -1
  16. package/esm/src/guardrails/canary-gate.js +2 -1
  17. package/esm/src/guardrails/canary.d.ts +9 -1
  18. package/esm/src/guardrails/canary.js +21 -10
  19. package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +1 -0
  20. package/esm/src/guardrails/corpus/fuzz-inbound.js +12 -15
  21. package/esm/src/guardrails/corpus/inbound-payloads.js +1 -0
  22. package/esm/src/guardrails/corpus/live-attacks.js +0 -1
  23. package/esm/src/guardrails/corpus/mod.d.ts +1 -0
  24. package/esm/src/guardrails/corpus/secrets.d.ts +1 -0
  25. package/esm/src/guardrails/corpus/secrets.js +1 -0
  26. package/esm/src/guardrails/corpus/strings.d.ts +1 -0
  27. package/esm/src/guardrails/corpus/strings.js +1 -0
  28. package/esm/src/guardrails/corpus/types.d.ts +1 -0
  29. package/esm/src/guardrails/egress.d.ts +26 -3
  30. package/esm/src/guardrails/egress.js +69 -18
  31. package/esm/src/guardrails/error.d.ts +14 -23
  32. package/esm/src/guardrails/error.js +86 -77
  33. package/esm/src/guardrails/eval/corpus.d.ts +108 -0
  34. package/esm/src/guardrails/eval/corpus.js +978 -0
  35. package/esm/src/guardrails/eval/mod.d.ts +51 -0
  36. package/esm/src/guardrails/eval/mod.js +133 -0
  37. package/esm/src/guardrails/eval/score.d.ts +66 -0
  38. package/esm/src/guardrails/eval/score.js +114 -0
  39. package/esm/src/guardrails/events.d.ts +25 -0
  40. package/esm/src/guardrails/events.js +56 -0
  41. package/esm/src/guardrails/hits.d.ts +24 -0
  42. package/esm/src/guardrails/hits.js +45 -0
  43. package/esm/src/guardrails/lexicon.d.ts +39 -0
  44. package/esm/src/guardrails/lexicon.js +200 -0
  45. package/esm/src/guardrails/live-outbound-gate.d.ts +15 -13
  46. package/esm/src/guardrails/live-outbound-gate.js +131 -89
  47. package/esm/src/guardrails/mod.d.ts +19 -4
  48. package/esm/src/guardrails/mod.js +12 -3
  49. package/esm/src/guardrails/network.d.ts +19 -0
  50. package/esm/src/guardrails/network.js +234 -0
  51. package/esm/src/guardrails/policy.d.ts +35 -0
  52. package/esm/src/guardrails/policy.js +50 -0
  53. package/esm/src/guardrails/progressive-yield.d.ts +51 -0
  54. package/esm/src/guardrails/progressive-yield.js +98 -0
  55. package/esm/src/guardrails/quota.d.ts +17 -3
  56. package/esm/src/guardrails/quota.js +18 -4
  57. package/esm/src/guardrails/sanitize.d.ts +36 -6
  58. package/esm/src/guardrails/sanitize.js +152 -60
  59. package/esm/src/guardrails/serialize.d.ts +35 -0
  60. package/esm/src/guardrails/serialize.js +58 -0
  61. package/esm/src/guardrails/testing.d.ts +7 -0
  62. package/esm/src/guardrails/testing.js +4 -0
  63. package/esm/src/guardrails/theorum-error.d.ts +12 -0
  64. package/esm/src/guardrails/theorum-error.js +15 -0
  65. package/esm/src/guardrails/tool-directives.d.ts +48 -0
  66. package/esm/src/guardrails/tool-directives.js +124 -0
  67. package/esm/src/guardrails/tool-result.d.ts +93 -0
  68. package/esm/src/guardrails/tool-result.js +276 -0
  69. package/esm/src/guardrails/types.d.ts +291 -0
  70. package/esm/src/guardrails/types.js +72 -0
  71. package/esm/src/host/client-turn.js +4 -0
  72. package/esm/src/host/mint-trace.d.ts +1 -1
  73. package/esm/src/kernel/auth/crypto.d.ts +42 -0
  74. package/esm/src/kernel/auth/crypto.js +106 -0
  75. package/esm/src/kernel/auth/mod.d.ts +11 -0
  76. package/esm/src/kernel/auth/mod.js +11 -0
  77. package/esm/src/kernel/auth/oauth.d.ts +47 -0
  78. package/esm/src/kernel/auth/oauth.js +278 -0
  79. package/esm/src/kernel/auth/types.d.ts +133 -0
  80. package/esm/src/kernel/auth/types.js +13 -0
  81. package/esm/src/kernel/engine/delta.js +43 -2
  82. package/esm/src/kernel/engine/live-inbound.d.ts +15 -3
  83. package/esm/src/kernel/engine/live-inbound.js +22 -8
  84. package/esm/src/kernel/engine/live-ingress.d.ts +19 -0
  85. package/esm/src/kernel/engine/live-ingress.js +47 -0
  86. package/esm/src/kernel/engine/repair.js +13 -12
  87. package/esm/src/kernel/engine/runner/gates.js +127 -40
  88. package/esm/src/kernel/engine/runner/mod.d.ts +6 -4
  89. package/esm/src/kernel/engine/runner/mod.js +182 -43
  90. package/esm/src/kernel/engine/runner/schema-validation.js +3 -3
  91. package/esm/src/kernel/engine/runner/stages.d.ts +39 -0
  92. package/esm/src/kernel/engine/runner/stages.js +89 -0
  93. package/esm/src/kernel/engine/runner/state.d.ts +24 -0
  94. package/esm/src/kernel/engine/runner/steps.js +128 -61
  95. package/esm/src/kernel/engine/runner/stream.d.ts +9 -2
  96. package/esm/src/kernel/engine/runner/stream.js +114 -55
  97. package/esm/src/kernel/engine/session/mod.d.ts +3 -1
  98. package/esm/src/kernel/engine/session/mod.js +386 -34
  99. package/esm/src/kernel/interaction-parts.d.ts +14 -0
  100. package/esm/src/kernel/interaction-parts.js +23 -0
  101. package/esm/src/kernel/mod.d.ts +19 -7
  102. package/esm/src/kernel/mod.js +10 -5
  103. package/esm/src/kernel/profile-graph.d.ts +159 -0
  104. package/esm/src/kernel/profile-graph.js +156 -0
  105. package/esm/src/kernel/registry/attachments.d.ts +10 -10
  106. package/esm/src/kernel/registry/attachments.js +29 -26
  107. package/esm/src/kernel/registry/catalog.d.ts +25 -11
  108. package/esm/src/kernel/registry/catalog.js +59 -24
  109. package/esm/src/kernel/registry/ingress.js +34 -22
  110. package/esm/src/kernel/registry/profile-outputs.d.ts +4 -0
  111. package/esm/src/kernel/registry/profile-outputs.js +8 -0
  112. package/esm/src/kernel/registry/profiles.d.ts +34 -14
  113. package/esm/src/kernel/registry/profiles.js +306 -59
  114. package/esm/src/kernel/registry/provider-request.js +2 -0
  115. package/esm/src/kernel/registry/resolve.d.ts +7 -6
  116. package/esm/src/kernel/registry/resolve.js +102 -117
  117. package/esm/src/kernel/registry/schemas.js +1 -1
  118. package/esm/src/kernel/registry/sole-model.d.ts +8 -0
  119. package/esm/src/kernel/registry/sole-model.js +10 -0
  120. package/esm/src/kernel/registry/system-prompt.d.ts +10 -0
  121. package/esm/src/kernel/registry/system-prompt.js +40 -0
  122. package/esm/src/kernel/registry/system-role.d.ts +8 -0
  123. package/esm/src/kernel/registry/system-role.js +14 -0
  124. package/esm/src/kernel/registry/vault.d.ts +2 -2
  125. package/esm/src/kernel/registry/vault.js +4 -4
  126. package/esm/src/kernel/schema.d.ts +97 -11
  127. package/esm/src/kernel/schema.js +256 -111
  128. package/esm/src/kernel/stages.d.ts +175 -0
  129. package/esm/src/kernel/stages.js +476 -0
  130. package/esm/src/kernel/stop.d.ts +65 -11
  131. package/esm/src/kernel/stop.js +46 -11
  132. package/esm/src/kernel/tools/events.d.ts +41 -0
  133. package/esm/src/kernel/tools/events.js +71 -0
  134. package/esm/src/kernel/tools/execute.d.ts +63 -24
  135. package/esm/src/kernel/tools/execute.js +475 -224
  136. package/esm/src/kernel/tools/harness.js +16 -14
  137. package/esm/src/kernel/tools/invoke.js +26 -8
  138. package/esm/src/kernel/tools/mod.d.ts +3 -1
  139. package/esm/src/kernel/tools/mod.js +2 -1
  140. package/esm/src/kernel/tools/permission.d.ts +15 -0
  141. package/esm/src/kernel/tools/permission.js +47 -0
  142. package/esm/src/kernel/tools/project.js +5 -3
  143. package/esm/src/kernel/tools/registry.js +20 -10
  144. package/esm/src/kernel/tools/remote.d.ts +94 -0
  145. package/esm/src/kernel/tools/remote.js +577 -0
  146. package/esm/src/kernel/tools/resolve.d.ts +17 -7
  147. package/esm/src/kernel/tools/resolve.js +38 -17
  148. package/esm/src/kernel/tools/schema.d.ts +2 -0
  149. package/esm/src/kernel/tools/schema.js +23 -6
  150. package/esm/src/kernel/tools/stage-run.d.ts +105 -0
  151. package/esm/src/kernel/tools/stage-run.js +155 -0
  152. package/esm/src/kernel/tools/types.d.ts +198 -20
  153. package/esm/src/kernel/types.d.ts +253 -114
  154. package/esm/src/kernel/util/find-last.d.ts +2 -0
  155. package/esm/src/kernel/util/find-last.js +10 -0
  156. package/esm/src/observability/destinations.d.ts +31 -0
  157. package/esm/src/observability/destinations.js +67 -0
  158. package/esm/src/observability/mod.d.ts +10 -3
  159. package/esm/src/observability/mod.js +6 -2
  160. package/esm/src/observability/policy.d.ts +27 -0
  161. package/esm/src/observability/policy.js +80 -0
  162. package/esm/src/observability/resolve-policy.d.ts +16 -0
  163. package/esm/src/observability/resolve-policy.js +64 -0
  164. package/esm/src/observability/trace-attach.d.ts +3 -1
  165. package/esm/src/observability/trace-attach.js +17 -10
  166. package/esm/src/observability/trace-record.d.ts +12 -4
  167. package/esm/src/observability/trace-record.js +63 -19
  168. package/esm/src/observability/trace-sink.d.ts +19 -0
  169. package/esm/src/observability/trace-sink.js +10 -0
  170. package/esm/src/observability/trace.d.ts +14 -11
  171. package/esm/src/observability/trace.js +23 -14
  172. package/esm/src/observability/types.d.ts +113 -0
  173. package/esm/src/observability/types.js +11 -0
  174. package/esm/src/providers/create-provider.d.ts +7 -4
  175. package/esm/src/providers/create-provider.js +21 -7
  176. package/esm/src/providers/google/interactions/framing.d.ts +8 -0
  177. package/esm/src/providers/google/interactions/framing.js +74 -13
  178. package/esm/src/providers/google/live/framing.d.ts +5 -2
  179. package/esm/src/providers/google/live/framing.js +49 -12
  180. package/esm/src/providers/google/live/openapi-schema.js +3 -2
  181. package/esm/src/providers/google/live/stream.d.ts +9 -0
  182. package/esm/src/providers/google/live/stream.js +16 -3
  183. package/esm/src/providers/openrouter/cache-control.d.ts +24 -0
  184. package/esm/src/providers/openrouter/cache-control.js +23 -0
  185. package/esm/src/providers/openrouter/chat.d.ts +21 -1
  186. package/esm/src/providers/openrouter/chat.js +51 -6
  187. package/esm/src/providers/openrouter/image.js +8 -19
  188. package/esm/src/providers/openrouter/openai/chat-payload.js +23 -1
  189. package/esm/src/providers/openrouter/openai/compat.d.ts +7 -1
  190. package/esm/src/providers/openrouter/openai/compat.js +23 -4
  191. package/esm/src/providers/openrouter/openai/image-payload.js +8 -2
  192. package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +1 -1
  193. package/esm/src/providers/openrouter/openai/sdk-messages.js +32 -5
  194. package/package.json +1 -1
  195. package/esm/src/interface/blocks.d.ts +0 -20
  196. package/esm/src/interface/blocks.js +0 -180
  197. package/esm/src/interface/from-profile.d.ts +0 -14
  198. package/esm/src/interface/from-profile.js +0 -104
  199. package/esm/src/interface/inputs.d.ts +0 -8
  200. package/esm/src/interface/inputs.js +0 -127
  201. package/esm/src/interface/mod.d.ts +0 -10
  202. package/esm/src/interface/mod.js +0 -9
  203. package/esm/src/interface/types.d.ts +0 -153
  204. package/esm/src/interface/types.js +0 -13
@@ -8,8 +8,9 @@
8
8
  import { wrapUserData } from '../../guardrails/canary.js';
9
9
  import { TheorumError } from '../../guardrails/error.js';
10
10
  import { synthesizeRepairPrompt } from '../engine/repair.js';
11
- import { assertAttachmentLimits, requireMediaLimits } from './attachments.js';
12
- import { mediaKindForMime, mimeAllowed, mimeEssence } from './catalog.js';
11
+ import { isSpeechFormatAllowedForProtocol } from '../schema.js';
12
+ import { assertAttachmentLimits, isTurnMediaRef, requireMediaLimits } from './attachments.js';
13
+ import { mediaKindForMime, mimeAllowed, mimeEssence, profileAccept, } from './catalog.js';
13
14
  import { getStructured } from './schemas.js';
14
15
  function usesStructuredResponseFormat(structuredId) {
15
16
  if (!structuredId) {
@@ -41,22 +42,29 @@ function assertOutputMode(profile, structuredId) {
41
42
  if (active.length <= 1) {
42
43
  return;
43
44
  }
44
- throw new TheorumError(`Profile ${profile.id} declares multiple output wire formats (${active.join(', ')}). ` +
45
- `Only one of responseFormat JSON schema (outputs.structured with enforced ` +
45
+ throw new TheorumError(`Profile ${profile.id} declares multiple output wire formats (${active.join(', ')}). ` + // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
46
+ `Only one of responseFormat JSON schema (outputs.structured with enforced ` + // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
46
47
  `'responseFormat'), image, or speech may be active.`);
47
48
  }
48
49
  function assertImagePins(profile) {
49
50
  if (profile.type !== 'image') {
50
- throw new TheorumError(`Profile ${profile.id} is not type 'image'`);
51
+ throw new TheorumError(`Profile ${profile.id} is not type 'image'`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
51
52
  }
52
53
  return profile.image;
53
54
  }
55
+ function defaultBinding(profile) {
56
+ const ids = Object.keys(profile.models);
57
+ const id = profile.defaultModel ?? (ids.length === 1 ? ids[0] : undefined);
58
+ return id ? profile.models[id] : undefined;
59
+ }
54
60
  function assertSpeechRole(profile) {
55
61
  if (profile.type !== 'speech') {
56
62
  return;
57
63
  }
58
- if (profile.speech.format === 'mp3' && profile.model.protocol === 'geminiInteractions') {
59
- throw new TheorumError(`Profile ${profile.id}: speech.format 'mp3' requires protocol 'openAi' ` +
64
+ const format = profile.speech.format;
65
+ const binding = defaultBinding(profile);
66
+ if (format && binding && !isSpeechFormatAllowedForProtocol(binding.protocol, format)) {
67
+ throw new TheorumError(`Profile ${profile.id}: speech.format '${format}' requires protocol 'openAi' ` + // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
60
68
  `(geminiInteractions speech returns PCM and emits WAV)`);
61
69
  }
62
70
  }
@@ -76,45 +84,49 @@ function resolveImageFormat(profile) {
76
84
  function assertMediaMime(mime) {
77
85
  const kind = mediaKindForMime(mime);
78
86
  if (!kind) {
79
- throw new TheorumError(`MIME '${mime}' is not a supported media input type`);
87
+ throw new TheorumError(`MIME '${mime}' is not a supported media input type`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
80
88
  }
81
89
  return kind;
82
90
  }
83
91
  function profileInputs(profile) {
84
- if (profile.type === 'speech') {
92
+ if (profile.type === 'speech' || profile.type === 'live' || profile.type === 'host') {
85
93
  return undefined;
86
94
  }
87
95
  return profile.inputs;
88
96
  }
97
+ /**
98
+ * Normalize accepted attachments into provider parts. Inline blobs and
99
+ * references share MIME acceptance and kind resolution; references carry the
100
+ * uri through untouched (no base64, no byte limits — the host owns the upload).
101
+ */
89
102
  function mediaParts(profile, model, blobs, channel) {
90
- const inputs = profileInputs(profile);
91
- const accept = channel === 'voice' ? inputs?.voice?.accept : inputs?.attachments?.accept;
103
+ const accept = profileAccept(profile, channel);
92
104
  if (!accept) {
93
- throw new TheorumError(`Profile ${profile.id} does not accept ${channel}`);
105
+ throw new TheorumError(`Profile ${profile.id} does not accept ${channel}`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
94
106
  }
95
107
  const maxInputImages = profile.type === 'image' ? profile.image.maxInputImages : undefined;
96
108
  const imageCount = blobs.filter((blob) => mediaKindForMime(blob.mimeType) === 'image').length;
97
109
  if (maxInputImages !== undefined && imageCount > maxInputImages) {
98
- throw new TheorumError(`At most ${maxInputImages} reference images on ${model}`);
110
+ throw new TheorumError(`At most ${maxInputImages} reference images on ${model}`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
99
111
  }
100
112
  return blobs.map((blob) => {
101
113
  const kind = assertMediaMime(blob.mimeType);
102
114
  if (!mimeAllowed(accept, blob.mimeType)) {
103
- throw new TheorumError(`MIME '${blob.mimeType}' is not accepted on ${profile.id}`);
115
+ throw new TheorumError(`MIME '${blob.mimeType}' is not accepted on ${profile.id}`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
104
116
  }
105
117
  const essence = mimeEssence(blob.mimeType);
106
- return {
107
- type: kind,
108
- mimeType: essence === 'image/jpg' ? 'image/jpeg' : essence,
109
- data: blob.data,
110
- };
118
+ const mimeType = essence === 'image/jpg' ? 'image/jpeg' : essence;
119
+ if (isTurnMediaRef(blob)) {
120
+ return { type: kind, mimeType, uri: blob.uri };
121
+ }
122
+ return { type: kind, mimeType, data: blob.data };
111
123
  });
112
124
  }
113
125
  function extractTextPart(profile, req) {
114
126
  const { text, repair, history } = req.input ?? {};
115
127
  if (profile.type === 'speech') {
116
128
  if (!text?.trim()) {
117
- throw new TheorumError(`Profile ${profile.id} (speech) requires text input`);
129
+ throw new TheorumError(`Profile ${profile.id} (speech) requires text input`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
118
130
  }
119
131
  let promptText = text;
120
132
  if (repair) {
@@ -125,7 +137,7 @@ function extractTextPart(profile, req) {
125
137
  const inputs = profileInputs(profile);
126
138
  if (inputs?.text === false) {
127
139
  if (text) {
128
- throw new TheorumError(`Profile ${profile.id} does not accept text input`);
140
+ throw new TheorumError(`Profile ${profile.id} does not accept text input`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
129
141
  }
130
142
  return null;
131
143
  }
@@ -142,7 +154,7 @@ function extractMediaParts(profile, model, req) {
142
154
  if (profile.type === 'speech') {
143
155
  const { attachments, voice } = req.input ?? {};
144
156
  if ((attachments?.length ?? 0) + (voice?.length ?? 0) > 0) {
145
- throw new TheorumError(`Profile ${profile.id} (speech) does not accept media input`);
157
+ throw new TheorumError(`Profile ${profile.id} (speech) does not accept media input`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
146
158
  }
147
159
  return [];
148
160
  }
@@ -0,0 +1,4 @@
1
+ import type { Profile, ProfileOutputsSpec } from '../types.js';
2
+ /** Turn-based `outputs` pins — absent on `type: 'live'` and `type: 'host'`. */
3
+ declare function profileTurnOutputs(profile: Profile): ProfileOutputsSpec | undefined;
4
+ export { profileTurnOutputs };
@@ -0,0 +1,8 @@
1
+ /** Turn-based `outputs` pins — absent on `type: 'live'` and `type: 'host'`. */
2
+ function profileTurnOutputs(profile) {
3
+ if (profile.type === 'live' || profile.type === 'host') {
4
+ return undefined;
5
+ }
6
+ return profile.outputs;
7
+ }
8
+ export { profileTurnOutputs };
@@ -2,45 +2,65 @@
2
2
  * Runtime profile registry for host-owned THEORUM profiles.
3
3
  *
4
4
  * THEORUM ships profile types — not application profiles and not invented defaults.
5
- * Hosts must pass required fields explicitly (`type`, `model.protocol`, `model.provider`, …).
5
+ * Hosts must pass required fields explicitly (`type`, `models`, …).
6
6
  *
7
7
  * @module
8
8
  */
9
- import type { ImageProfile, LiveProfile, LiveProfileModelSpec, Profile, ProfileGuardrailsSpec, ProfileIdentity, ProfileInputsSpec, ProfileModelSpec, ProfileOutputsSpec, ProfileToolsSpec, ProfileTurnResumptionSpec, SpeechProfile, TurnProfileModelSpec } from '../types.js';
10
- export type ProfileDefinitionBase<P extends ProfileModelSpec = ProfileModelSpec> = {
9
+ import { type HostGuardrailsSpec, type ProfileGuardrailsSpec } from '../../guardrails/types.js';
10
+ import type { ProfileObservabilitySpec } from '../../observability/types.js';
11
+ import type { HostProfile, HostProfileToolsSpec, ImageProfile, LiveProfile, LiveProfileToolsSpec, ModelBinding, ModelId, Profile, ProfileIdentity, ProfileInputsSpec, ProfileModelFields, ProfileOutputsSpec, ProfileToolsSpec, ProfileTurnBehaviourSpec, SpeechProfile } from '../types.js';
12
+ export type ProfileDefinitionBase = {
11
13
  id: Profile['id'];
12
14
  identity: ProfileIdentity;
13
- model: P;
15
+ models: Record<ModelId, ModelBinding>;
16
+ defaultModel?: ModelId;
17
+ allowModelSelect?: boolean;
18
+ maxSteps?: number;
19
+ key?: ProfileModelFields['key'];
14
20
  outputs?: ProfileOutputsSpec;
15
21
  guardrails?: ProfileGuardrailsSpec;
22
+ observability?: ProfileObservabilitySpec;
16
23
  };
17
- export type TextProfileDefinition = ProfileDefinitionBase<TurnProfileModelSpec> & {
24
+ export type TextProfileDefinition = ProfileDefinitionBase & {
18
25
  type: 'text';
19
26
  tools: ProfileToolsSpec;
20
27
  inputs: ProfileInputsSpec;
21
- turnResumption?: ProfileTurnResumptionSpec;
28
+ turnBehaviour?: ProfileTurnBehaviourSpec;
22
29
  };
23
- export type ImageProfileDefinition = ProfileDefinitionBase<TurnProfileModelSpec> & {
30
+ export type ImageProfileDefinition = ProfileDefinitionBase & {
24
31
  type: 'image';
25
32
  image: NonNullable<ImageProfile['image']>;
26
33
  tools: ProfileToolsSpec;
27
34
  inputs: ProfileInputsSpec;
28
- turnResumption?: ProfileTurnResumptionSpec;
35
+ turnBehaviour?: ProfileTurnBehaviourSpec;
29
36
  };
30
- export type SpeechProfileDefinition = ProfileDefinitionBase<TurnProfileModelSpec> & {
37
+ export type SpeechProfileDefinition = ProfileDefinitionBase & {
31
38
  type: 'speech';
32
39
  speech: NonNullable<SpeechProfile['speech']>;
33
- turnResumption?: ProfileTurnResumptionSpec;
40
+ turnBehaviour?: ProfileTurnBehaviourSpec;
34
41
  };
35
- export type LiveProfileDefinition = ProfileDefinitionBase<LiveProfileModelSpec> & {
42
+ export type LiveProfileDefinition = ProfileDefinitionBase & {
36
43
  type: 'live';
37
44
  live: NonNullable<LiveProfile['live']>;
38
- tools: ProfileToolsSpec;
39
- inputs?: ProfileInputsSpec;
45
+ tools: LiveProfileToolsSpec;
46
+ /** Inject gate only — resumption is `live.sessionResumption`. */
47
+ turnBehaviour?: Pick<ProfileTurnBehaviourSpec, 'allowSteering'>;
48
+ };
49
+ /** Host-driven tool ceiling — no models, identity, inputs, outputs, turnBehaviour, key, or maxSteps. */
50
+ export type HostProfileDefinition = {
51
+ type: 'host';
52
+ id: Profile['id'];
53
+ tools: HostProfileToolsSpec;
54
+ /** Only the guards that fire on the `invokeTool` path — see {@link HostGuardrailsSpec}. */
55
+ guardrails?: HostGuardrailsSpec;
56
+ observability?: ProfileObservabilitySpec;
40
57
  };
41
58
  /** Host-authored profile definition — discriminated on `type`. No THEORUM defaults. */
42
- export type ProfileDefinition = TextProfileDefinition | ImageProfileDefinition | SpeechProfileDefinition | LiveProfileDefinition;
59
+ export type ProfileDefinition = TextProfileDefinition | ImageProfileDefinition | SpeechProfileDefinition | LiveProfileDefinition | HostProfileDefinition;
43
60
  /** Define a typed profile. Required fields must be set explicitly; optional fields stay optional. */
61
+ declare function defineProfile(input: LiveProfileDefinition): LiveProfile;
62
+ declare function defineProfile(input: HostProfileDefinition): HostProfile;
63
+ declare function defineProfile(input: Exclude<ProfileDefinition, LiveProfileDefinition | HostProfileDefinition>): Exclude<Profile, LiveProfile | HostProfile>;
44
64
  declare function defineProfile(input: ProfileDefinition): Profile;
45
65
  /** Register one host-owned profile in the process-local registry. */
46
66
  declare function registerProfile(profileInput: Profile | ProfileDefinition): void;