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.
- package/README.md +241 -98
- package/esm/mod.d.ts +57 -28
- package/esm/mod.js +43 -23
- package/esm/src/cli/commands/bench.js +18 -18
- package/esm/src/cli/commands/fuzz-canary.d.ts +13 -0
- package/esm/src/cli/commands/fuzz-canary.js +191 -0
- package/esm/src/cli/commands/fuzz-guardrails.d.ts +3 -5
- package/esm/src/cli/commands/fuzz-guardrails.js +4 -581
- package/esm/src/cli/commands/guardrails-eval.d.ts +14 -0
- package/esm/src/cli/commands/guardrails-eval.js +15 -0
- package/esm/src/cli/commands/profile.js +35 -15
- package/esm/src/cli/commands/run.d.ts +3 -0
- package/esm/src/cli/commands/run.js +23 -32
- package/esm/src/cli/commands/test.d.ts +10 -1
- package/esm/src/cli/commands/test.js +34 -34
- package/esm/src/cli/event-log.d.ts +19 -0
- package/esm/src/cli/event-log.js +147 -0
- package/esm/src/cli/index.js +57 -11
- package/esm/src/cli/matrix/synthesizer.d.ts +10 -12
- package/esm/src/cli/matrix/synthesizer.js +45 -118
- package/esm/src/guardrails/canary-gate.d.ts +21 -0
- package/esm/src/guardrails/canary-gate.js +32 -0
- package/esm/src/guardrails/canary.d.ts +34 -0
- package/esm/src/guardrails/canary.js +150 -0
- package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +17 -0
- package/esm/src/guardrails/corpus/canary-egress-attacks.js +151 -0
- package/esm/src/guardrails/corpus/fuzz-inbound.d.ts +11 -0
- package/esm/src/guardrails/corpus/fuzz-inbound.js +213 -0
- package/esm/src/guardrails/corpus/inbound-payloads.d.ts +10 -0
- package/esm/src/guardrails/corpus/inbound-payloads.js +125 -0
- package/esm/src/guardrails/corpus/live-attacks.d.ts +20 -0
- package/esm/src/guardrails/corpus/live-attacks.js +231 -0
- package/esm/src/guardrails/corpus/mod.d.ts +14 -0
- package/esm/src/guardrails/corpus/mod.js +11 -0
- package/esm/src/guardrails/corpus/secrets.d.ts +17 -0
- package/esm/src/guardrails/corpus/secrets.js +17 -0
- package/esm/src/guardrails/corpus/strings.d.ts +28 -0
- package/esm/src/guardrails/corpus/strings.js +34 -0
- package/esm/src/guardrails/corpus/types.d.ts +38 -0
- package/esm/src/guardrails/corpus/types.js +6 -0
- package/esm/src/guardrails/egress.d.ts +32 -0
- package/esm/src/guardrails/egress.js +87 -0
- package/esm/src/guardrails/error.d.ts +14 -23
- package/esm/src/guardrails/error.js +87 -76
- package/esm/src/guardrails/eval/corpus.d.ts +108 -0
- package/esm/src/guardrails/eval/corpus.js +978 -0
- package/esm/src/guardrails/eval/mod.d.ts +51 -0
- package/esm/src/guardrails/eval/mod.js +133 -0
- package/esm/src/guardrails/eval/score.d.ts +66 -0
- package/esm/src/guardrails/eval/score.js +114 -0
- package/esm/src/guardrails/events.d.ts +25 -0
- package/esm/src/guardrails/events.js +56 -0
- package/esm/src/guardrails/hits.d.ts +24 -0
- package/esm/src/guardrails/hits.js +45 -0
- package/esm/src/guardrails/injection.js +28 -5
- package/esm/src/guardrails/lexicon.d.ts +39 -0
- package/esm/src/guardrails/lexicon.js +200 -0
- package/esm/src/guardrails/live-outbound-gate.d.ts +41 -0
- package/esm/src/guardrails/live-outbound-gate.js +222 -0
- package/esm/src/guardrails/mod.d.ts +30 -6
- package/esm/src/guardrails/mod.js +20 -5
- package/esm/src/guardrails/network.d.ts +19 -0
- package/esm/src/guardrails/network.js +234 -0
- package/esm/src/guardrails/policy.d.ts +35 -0
- package/esm/src/guardrails/policy.js +50 -0
- package/esm/src/guardrails/progressive-yield.d.ts +51 -0
- package/esm/src/guardrails/progressive-yield.js +98 -0
- package/esm/src/guardrails/quota.d.ts +17 -3
- package/esm/src/guardrails/quota.js +18 -4
- package/esm/src/guardrails/sanitize.d.ts +45 -19
- package/esm/src/guardrails/sanitize.js +177 -94
- package/esm/src/guardrails/sensitive.js +2 -1
- package/esm/src/guardrails/serialize.d.ts +35 -0
- package/esm/src/guardrails/serialize.js +58 -0
- package/esm/src/guardrails/testing.d.ts +17 -0
- package/esm/src/guardrails/testing.js +13 -0
- package/esm/src/guardrails/theorum-error.d.ts +12 -0
- package/esm/src/guardrails/theorum-error.js +15 -0
- package/esm/src/guardrails/tool-directives.d.ts +48 -0
- package/esm/src/guardrails/tool-directives.js +124 -0
- package/esm/src/guardrails/tool-result.d.ts +93 -0
- package/esm/src/guardrails/tool-result.js +276 -0
- package/esm/src/guardrails/types.d.ts +291 -0
- package/esm/src/guardrails/types.js +72 -0
- package/esm/src/host/client-turn.d.ts +19 -0
- package/esm/src/host/client-turn.js +36 -0
- package/esm/src/host/mint-trace.d.ts +1 -1
- package/esm/src/host/mod.d.ts +5 -3
- package/esm/src/host/mod.js +4 -3
- package/esm/src/kernel/auth/crypto.d.ts +42 -0
- package/esm/src/kernel/auth/crypto.js +106 -0
- package/esm/src/kernel/auth/mod.d.ts +11 -0
- package/esm/src/kernel/auth/mod.js +11 -0
- package/esm/src/kernel/auth/oauth.d.ts +47 -0
- package/esm/src/kernel/auth/oauth.js +278 -0
- package/esm/src/kernel/auth/types.d.ts +133 -0
- package/esm/src/kernel/auth/types.js +13 -0
- package/esm/src/kernel/engine/delta.d.ts +24 -2
- package/esm/src/kernel/engine/delta.js +478 -39
- package/esm/src/kernel/engine/live-inbound.d.ts +21 -0
- package/esm/src/kernel/engine/live-inbound.js +31 -0
- package/esm/src/kernel/engine/live-ingress.d.ts +19 -0
- package/esm/src/kernel/engine/live-ingress.js +47 -0
- package/esm/src/kernel/engine/repair.js +13 -12
- package/esm/src/kernel/engine/runner/gates.d.ts +1 -1
- package/esm/src/kernel/engine/runner/gates.js +130 -43
- package/esm/src/kernel/engine/runner/mod.d.ts +6 -4
- package/esm/src/kernel/engine/runner/mod.js +192 -53
- package/esm/src/kernel/engine/runner/schema-validation.js +3 -3
- package/esm/src/kernel/engine/runner/stages.d.ts +39 -0
- package/esm/src/kernel/engine/runner/stages.js +89 -0
- package/esm/src/kernel/engine/runner/state.d.ts +31 -0
- package/esm/src/kernel/engine/runner/steps.d.ts +1 -1
- package/esm/src/kernel/engine/runner/steps.js +244 -43
- package/esm/src/kernel/engine/runner/stream.d.ts +9 -3
- package/esm/src/kernel/engine/runner/stream.js +140 -44
- package/esm/src/kernel/engine/session/mod.d.ts +25 -0
- package/esm/src/kernel/engine/session/mod.js +557 -0
- package/esm/src/kernel/interaction-parts.d.ts +14 -0
- package/esm/src/kernel/interaction-parts.js +23 -0
- package/esm/src/kernel/mod.d.ts +21 -10
- package/esm/src/kernel/mod.js +11 -8
- package/esm/src/kernel/profile-graph.d.ts +159 -0
- package/esm/src/kernel/profile-graph.js +156 -0
- package/esm/src/kernel/registry/attachments.d.ts +12 -10
- package/esm/src/kernel/registry/attachments.js +33 -27
- package/esm/src/kernel/registry/catalog.d.ts +25 -24
- package/esm/src/kernel/registry/catalog.js +60 -101
- package/esm/src/kernel/registry/ingress.d.ts +9 -4
- package/esm/src/kernel/registry/ingress.js +97 -75
- package/esm/src/kernel/registry/profile-outputs.d.ts +4 -0
- package/esm/src/kernel/registry/profile-outputs.js +8 -0
- package/esm/src/kernel/registry/profiles.d.ts +55 -12
- package/esm/src/kernel/registry/profiles.js +413 -73
- package/esm/src/kernel/registry/provider-request.js +13 -7
- package/esm/src/kernel/registry/resolve.d.ts +8 -8
- package/esm/src/kernel/registry/resolve.js +169 -154
- package/esm/src/kernel/registry/schemas.js +1 -1
- package/esm/src/kernel/registry/sole-model.d.ts +8 -0
- package/esm/src/kernel/registry/sole-model.js +10 -0
- package/esm/src/kernel/registry/system-prompt.d.ts +10 -0
- package/esm/src/kernel/registry/system-prompt.js +40 -0
- package/esm/src/kernel/registry/system-role.d.ts +8 -0
- package/esm/src/kernel/registry/system-role.js +14 -0
- package/esm/src/kernel/registry/vault.d.ts +12 -7
- package/esm/src/kernel/registry/vault.js +32 -10
- package/esm/src/kernel/schema.d.ts +231 -0
- package/esm/src/kernel/schema.js +607 -0
- package/esm/src/kernel/stages.d.ts +175 -0
- package/esm/src/kernel/stages.js +476 -0
- package/esm/src/kernel/stop.d.ts +78 -19
- package/esm/src/kernel/stop.js +51 -16
- package/esm/src/kernel/tools/events.d.ts +41 -0
- package/esm/src/kernel/tools/events.js +71 -0
- package/esm/src/kernel/tools/execute.d.ts +84 -0
- package/esm/src/kernel/tools/execute.js +614 -0
- package/esm/src/kernel/tools/harness.d.ts +8 -0
- package/esm/src/kernel/tools/harness.js +46 -0
- package/esm/src/kernel/tools/invoke.d.ts +10 -0
- package/esm/src/kernel/tools/invoke.js +101 -0
- package/esm/src/kernel/tools/mod.d.ts +13 -0
- package/esm/src/kernel/tools/mod.js +11 -0
- package/esm/src/kernel/tools/permission.d.ts +15 -0
- package/esm/src/kernel/tools/permission.js +47 -0
- package/esm/src/kernel/tools/project.d.ts +12 -0
- package/esm/src/kernel/tools/project.js +36 -0
- package/esm/src/kernel/tools/registry.d.ts +23 -0
- package/esm/src/kernel/tools/registry.js +81 -0
- package/esm/src/kernel/tools/remote.d.ts +94 -0
- package/esm/src/kernel/tools/remote.js +577 -0
- package/esm/src/kernel/tools/resolve.d.ts +39 -0
- package/esm/src/kernel/tools/resolve.js +283 -0
- package/esm/src/kernel/tools/schema.d.ts +15 -0
- package/esm/src/kernel/tools/schema.js +176 -0
- package/esm/src/kernel/tools/stage-run.d.ts +105 -0
- package/esm/src/kernel/tools/stage-run.js +155 -0
- package/esm/src/kernel/tools/types.d.ts +394 -0
- package/esm/src/kernel/tools/types.js +9 -0
- package/esm/src/kernel/types.d.ts +540 -256
- package/esm/src/kernel/util/find-last.d.ts +2 -0
- package/esm/src/kernel/util/find-last.js +10 -0
- package/esm/src/observability/destinations.d.ts +31 -0
- package/esm/src/observability/destinations.js +67 -0
- package/esm/src/observability/mod.d.ts +10 -3
- package/esm/src/observability/mod.js +6 -2
- package/esm/src/observability/policy.d.ts +27 -0
- package/esm/src/observability/policy.js +80 -0
- package/esm/src/observability/resolve-policy.d.ts +16 -0
- package/esm/src/observability/resolve-policy.js +64 -0
- package/esm/src/observability/trace-attach.d.ts +8 -4
- package/esm/src/observability/trace-attach.js +50 -29
- package/esm/src/observability/trace-record.d.ts +23 -13
- package/esm/src/observability/trace-record.js +96 -39
- package/esm/src/observability/trace-sink.d.ts +19 -0
- package/esm/src/observability/trace-sink.js +10 -0
- package/esm/src/observability/trace-usage.d.ts +10 -3
- package/esm/src/observability/trace-usage.js +70 -17
- package/esm/src/observability/trace.d.ts +18 -7
- package/esm/src/observability/trace.js +34 -17
- package/esm/src/observability/types.d.ts +113 -0
- package/esm/src/observability/types.js +11 -0
- package/esm/src/presets/google/speech-voices.d.ts +11 -0
- package/esm/src/presets/google/speech-voices.js +41 -0
- package/esm/src/presets/google.d.ts +36 -24
- package/esm/src/presets/google.js +50 -63
- package/esm/src/presets/mod.d.ts +2 -2
- package/esm/src/presets/mod.js +1 -1
- package/esm/src/providers/create-provider.d.ts +20 -17
- package/esm/src/providers/create-provider.js +72 -26
- package/esm/src/providers/google/interactions/framing.d.ts +23 -0
- package/esm/src/providers/google/interactions/framing.js +269 -0
- package/esm/src/providers/google/interactions/mod.d.ts +7 -0
- package/esm/src/providers/google/interactions/mod.js +7 -0
- package/esm/src/providers/google/interactions/stream.d.ts +83 -0
- package/esm/src/providers/google/interactions/stream.js +588 -0
- package/esm/src/providers/google/keys.d.ts +26 -0
- package/esm/src/providers/{keys.js → google/keys.js} +19 -31
- package/esm/src/providers/google/live/framing.d.ts +49 -0
- package/esm/src/providers/google/live/framing.js +552 -0
- package/esm/src/providers/google/live/openapi-schema.d.ts +6 -0
- package/esm/src/providers/google/live/openapi-schema.js +46 -0
- package/esm/src/providers/google/live/session.d.ts +25 -0
- package/esm/src/providers/google/live/session.js +134 -0
- package/esm/src/providers/google/live/stream.d.ts +45 -0
- package/esm/src/providers/google/live/stream.js +214 -0
- package/esm/src/providers/google/urls.d.ts +6 -0
- package/esm/src/providers/google/urls.js +6 -0
- package/esm/src/providers/local/local.d.ts +30 -0
- package/esm/src/providers/{local.js → local/local.js} +66 -126
- package/esm/src/providers/local/mod.d.ts +9 -0
- package/esm/src/providers/local/mod.js +9 -0
- package/esm/src/providers/mod.d.ts +6 -3
- package/esm/src/providers/mod.js +3 -1
- package/esm/src/providers/openrouter/cache-control.d.ts +24 -0
- package/esm/src/providers/openrouter/cache-control.js +23 -0
- package/esm/src/providers/openrouter/chat.d.ts +107 -0
- package/esm/src/providers/{openrouter.js → openrouter/chat.js} +117 -231
- package/esm/src/providers/openrouter/image.d.ts +34 -0
- package/esm/src/providers/openrouter/image.js +275 -0
- package/esm/src/providers/openrouter/openai/chat-payload.d.ts +24 -0
- package/esm/src/providers/openrouter/openai/chat-payload.js +82 -0
- package/esm/src/providers/openrouter/openai/compat.d.ts +53 -0
- package/esm/src/providers/openrouter/openai/compat.js +213 -0
- package/esm/src/providers/openrouter/openai/image-payload.d.ts +18 -0
- package/esm/src/providers/openrouter/openai/image-payload.js +90 -0
- package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +22 -0
- package/esm/src/providers/openrouter/openai/sdk-messages.js +122 -0
- package/esm/src/providers/openrouter/resolve-api-key.d.ts +9 -0
- package/esm/src/providers/openrouter/resolve-api-key.js +24 -0
- package/esm/src/providers/openrouter/speech.d.ts +23 -0
- package/esm/src/providers/{speech.js → openrouter/speech.js} +32 -55
- package/esm/src/providers/probe.d.ts +1 -0
- package/esm/src/providers/probe.js +22 -0
- package/esm/src/providers/shared/pcm.d.ts +12 -0
- package/esm/src/providers/{pcm.js → shared/pcm.js} +16 -3
- package/esm/src/providers/shared/sse.d.ts +18 -0
- package/esm/src/providers/shared/sse.js +87 -0
- package/esm/src/providers/shared/tool-args.d.ts +17 -0
- package/esm/src/providers/shared/tool-args.js +45 -0
- package/esm/src/providers/shared/upstream-tap.d.ts +5 -0
- package/esm/src/providers/{google-tap.js → shared/upstream-tap.js} +4 -7
- package/esm/src/providers/shared/upstream-tape.d.ts +6 -0
- package/esm/src/providers/{gemini-tape.js → shared/upstream-tape.js} +12 -22
- package/esm/src/providers/types.d.ts +27 -0
- package/esm/src/providers/types.js +1 -0
- package/package.json +11 -7
- package/docs/cli.md +0 -97
- package/docs/guardrails.md +0 -178
- package/docs/host.md +0 -97
- package/docs/kernel.md +0 -404
- package/docs/observability.md +0 -105
- package/docs/openrouter.md +0 -125
- package/docs/presets-google.md +0 -91
- package/docs/presets.md +0 -88
- package/docs/providers.md +0 -202
- package/docs/streaming.md +0 -96
- package/esm/src/kernel/engine/boundary.d.ts +0 -10
- package/esm/src/kernel/engine/boundary.js +0 -55
- package/esm/src/kernel/engine/runner/tools.d.ts +0 -13
- package/esm/src/kernel/engine/runner/tools.js +0 -198
- package/esm/src/kernel/registry/tools.d.ts +0 -12
- package/esm/src/kernel/registry/tools.js +0 -36
- package/esm/src/providers/expose-for-tests.d.ts +0 -1
- package/esm/src/providers/expose-for-tests.js +0 -25
- package/esm/src/providers/gemini-tape.d.ts +0 -2
- package/esm/src/providers/google-tap.d.ts +0 -3
- package/esm/src/providers/interactions.d.ts +0 -5
- package/esm/src/providers/interactions.js +0 -169
- package/esm/src/providers/keys.d.ts +0 -19
- package/esm/src/providers/local.d.ts +0 -29
- package/esm/src/providers/openrouter-mod.d.ts +0 -13
- package/esm/src/providers/openrouter-mod.js +0 -12
- package/esm/src/providers/openrouter-payload.d.ts +0 -39
- package/esm/src/providers/openrouter-payload.js +0 -195
- package/esm/src/providers/openrouter.d.ts +0 -15
- package/esm/src/providers/pcm.d.ts +0 -7
- package/esm/src/providers/provider.d.ts +0 -15
- package/esm/src/providers/provider.js +0 -202
- package/esm/src/providers/speech.d.ts +0 -23
- package/esm/src/providers/sse.d.ts +0 -7
- package/esm/src/providers/sse.js +0 -55
- package/esm/src/streaming/mod.d.ts +0 -9
- package/esm/src/streaming/mod.js +0 -8
- /package/esm/src/{streaming → host}/readStreamingJsonStringField.d.ts +0 -0
- /package/esm/src/{streaming → host}/readStreamingJsonStringField.js +0 -0
|
@@ -1,86 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
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
6
|
import { TheorumError } from '../../guardrails/error.js';
|
|
10
|
-
|
|
11
|
-
type: 'object',
|
|
12
|
-
properties: {
|
|
13
|
-
kind: { type: 'string', enum: ['confirm', 'choice', 'text'] },
|
|
14
|
-
prompt: { type: 'string' },
|
|
15
|
-
options: { type: 'array', items: { type: 'string' } },
|
|
16
|
-
},
|
|
17
|
-
required: ['kind', 'prompt'],
|
|
18
|
-
};
|
|
19
|
-
/** Harness tools that always ship with THEORUM. */
|
|
20
|
-
const HARNESS_TOOLS = {
|
|
21
|
-
askUser: { kind: 'custom', ui: true, schema: ASK_USER_SCHEMA },
|
|
22
|
-
};
|
|
23
|
-
/** Live tool catalog. Starts with harness tools; presets/hosts register more. */
|
|
24
|
-
const CATALOG = {
|
|
25
|
-
tools: { ...HARNESS_TOOLS },
|
|
26
|
-
};
|
|
27
|
-
/** Register or replace tool descriptors (idempotent per id). */
|
|
28
|
-
function registerTools(entries) {
|
|
29
|
-
Object.assign(CATALOG.tools, entries);
|
|
30
|
-
}
|
|
31
|
-
/** Look up one registered tool descriptor. */
|
|
32
|
-
function getTool(id) {
|
|
33
|
-
return CATALOG.tools[id];
|
|
34
|
-
}
|
|
35
|
-
/** Ids of all registered provider builtins. */
|
|
36
|
-
function listBuiltinIds() {
|
|
37
|
-
return Object.entries(CATALOG.tools)
|
|
38
|
-
.filter(([, entry]) => entry.kind === 'builtin')
|
|
39
|
-
.map(([id]) => id);
|
|
40
|
-
}
|
|
41
|
-
/** Restore harness-only tools (tests / host reloads). */
|
|
42
|
-
function resetTools() {
|
|
43
|
-
for (const id of Object.keys(CATALOG.tools)) {
|
|
44
|
-
delete CATALOG.tools[id];
|
|
45
|
-
}
|
|
46
|
-
Object.assign(CATALOG.tools, HARNESS_TOOLS);
|
|
47
|
-
}
|
|
48
|
-
/** MIME essence → normalized media part category (shared ingress map). */
|
|
49
|
-
const MEDIA_INPUT_KINDS = {
|
|
50
|
-
'image/png': 'image',
|
|
51
|
-
'image/jpeg': 'image',
|
|
52
|
-
'image/jpg': 'image',
|
|
53
|
-
'image/webp': 'image',
|
|
54
|
-
'image/heic': 'image',
|
|
55
|
-
'image/heif': 'image',
|
|
56
|
-
'audio/wav': 'audio',
|
|
57
|
-
'audio/x-wav': 'audio',
|
|
58
|
-
'audio/mpeg': 'audio',
|
|
59
|
-
'audio/mp3': 'audio',
|
|
60
|
-
'audio/aiff': 'audio',
|
|
61
|
-
'audio/aac': 'audio',
|
|
62
|
-
'audio/ogg': 'audio',
|
|
63
|
-
'audio/flac': 'audio',
|
|
64
|
-
'audio/webm': 'audio',
|
|
65
|
-
'audio/mp4': 'audio',
|
|
66
|
-
'audio/pcm': 'audio',
|
|
67
|
-
'video/mp4': 'video',
|
|
68
|
-
'video/mpeg': 'video',
|
|
69
|
-
'video/quicktime': 'video',
|
|
70
|
-
'video/x-msvideo': 'video',
|
|
71
|
-
'video/x-flv': 'video',
|
|
72
|
-
'video/mpg': 'video',
|
|
73
|
-
'video/webm': 'video',
|
|
74
|
-
'video/wmv': 'video',
|
|
75
|
-
'video/x-ms-wmv': 'video',
|
|
76
|
-
'video/3gpp': 'video',
|
|
77
|
-
'application/pdf': 'document',
|
|
78
|
-
'text/plain': 'document',
|
|
79
|
-
'text/csv': 'document',
|
|
80
|
-
'text/markdown': 'document',
|
|
81
|
-
'text/html': 'document',
|
|
82
|
-
'application/json': 'document',
|
|
83
|
-
};
|
|
7
|
+
import { MEDIA_INPUT_KINDS } from '../schema.js';
|
|
84
8
|
function mimeEssence(mime) {
|
|
85
9
|
const [base] = mime.split(';');
|
|
86
10
|
return (base ?? '').trim().toLowerCase();
|
|
@@ -98,38 +22,73 @@ function mimeAllowed(accept, mime) {
|
|
|
98
22
|
function mediaKindForMime(mime) {
|
|
99
23
|
return MEDIA_INPUT_KINDS[mimeEssence(mime)];
|
|
100
24
|
}
|
|
101
|
-
/**
|
|
102
|
-
function
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
25
|
+
/** The `accept` list a profile declares for one input channel, if it declares one. */
|
|
26
|
+
function profileAccept(profile, channel) {
|
|
27
|
+
if (profile.type === 'speech' || profile.type === 'live' || profile.type === 'host') {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const inputs = profile.inputs;
|
|
31
|
+
return channel === 'voice' ? inputs?.voice?.accept : inputs?.attachments?.accept;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Which `TurnInput` channel of a profile accepts this MIME, or `undefined` when
|
|
35
|
+
* the profile accepts it nowhere (or the kernel cannot classify it at all).
|
|
36
|
+
*
|
|
37
|
+
* The one public answer to "does this profile take this file". Hosts route and
|
|
38
|
+
* filter channel ingress with it instead of keeping their own MIME table: the
|
|
39
|
+
* profile's `accept` lists are the whole declaration.
|
|
40
|
+
*/
|
|
41
|
+
function mediaChannelForMime(profile, mime) {
|
|
42
|
+
if (!mediaKindForMime(mime)) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
for (const channel of ['attachments', 'voice']) {
|
|
46
|
+
const accept = profileAccept(profile, channel);
|
|
47
|
+
if (accept && mimeAllowed(accept, mime)) {
|
|
48
|
+
return channel;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
/** Require a host-declared model binding for a profile model id. */
|
|
54
|
+
function requireModelBinding(profile, modelId) {
|
|
55
|
+
const binding = profile.models[modelId];
|
|
56
|
+
if (!binding) {
|
|
57
|
+
throw new TheorumError(`Profile ${profile.id} has no model binding for '${modelId}'`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
58
|
+
}
|
|
59
|
+
return binding;
|
|
60
|
+
}
|
|
61
|
+
function effortLevels(binding) {
|
|
62
|
+
if (!binding?.efforts) {
|
|
63
|
+
return [];
|
|
106
64
|
}
|
|
107
|
-
return
|
|
65
|
+
return Object.values(binding.efforts);
|
|
108
66
|
}
|
|
109
|
-
function clampLevels(
|
|
110
|
-
|
|
67
|
+
function clampLevels(binding, level) {
|
|
68
|
+
const legal = effortLevels(binding);
|
|
69
|
+
if (legal.length === 0) {
|
|
111
70
|
return level;
|
|
112
71
|
}
|
|
113
|
-
if (
|
|
72
|
+
if (legal.includes(level)) {
|
|
114
73
|
return level;
|
|
115
74
|
}
|
|
116
|
-
const
|
|
117
|
-
|
|
75
|
+
const fallbackAlias = binding?.defaultEffort;
|
|
76
|
+
const fallback = fallbackAlias ? binding?.efforts?.[fallbackAlias] : undefined;
|
|
77
|
+
if (fallback && legal.includes(fallback)) {
|
|
118
78
|
return fallback;
|
|
119
79
|
}
|
|
120
|
-
|
|
121
|
-
return first ?? level;
|
|
80
|
+
return legal[0] ?? level;
|
|
122
81
|
}
|
|
123
|
-
/** Clamp a requested thinking level to what the model
|
|
124
|
-
function clampThinkingLevel(
|
|
125
|
-
return clampLevels(
|
|
82
|
+
/** Clamp a requested thinking level to what the model binding accepts. */
|
|
83
|
+
function clampThinkingLevel(binding, level) {
|
|
84
|
+
return clampLevels(binding, level);
|
|
126
85
|
}
|
|
127
|
-
/** Look up a model
|
|
128
|
-
function modelEntryByApiId(
|
|
129
|
-
return Object.values(
|
|
86
|
+
/** Look up a model binding by provider-native API id within a host map. */
|
|
87
|
+
function modelEntryByApiId(bindings, apiId) {
|
|
88
|
+
return Object.values(bindings).find((m) => m.apiId === apiId);
|
|
130
89
|
}
|
|
131
|
-
/** Clamp thinking level using a provider-native API id within a host
|
|
132
|
-
function clampThinkingLevelForApiId(
|
|
133
|
-
return clampLevels(modelEntryByApiId(
|
|
90
|
+
/** Clamp thinking level using a provider-native API id within a host map. */
|
|
91
|
+
function clampThinkingLevelForApiId(bindings, apiId, level) {
|
|
92
|
+
return clampLevels(modelEntryByApiId(bindings, apiId), level);
|
|
134
93
|
}
|
|
135
|
-
export {
|
|
94
|
+
export { clampThinkingLevel, clampThinkingLevelForApiId, mediaChannelForMime, mediaKindForMime, mimeAllowed, mimeEssence, modelEntryByApiId, profileAccept, requireModelBinding, };
|
|
@@ -5,9 +5,14 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module
|
|
7
7
|
*/
|
|
8
|
-
import type {
|
|
8
|
+
import type { ImageResponseFormat, InteractionPart, ModelId, Profile, TurnRequest } from '../types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Provider wire formats (JSON schema, image, speech) are mutually exclusive.
|
|
11
|
+
* Typed profiles make illegal mixes unrepresentable; this remains a safety net
|
|
12
|
+
* for responseFormat structured on text vs accidental dual modes.
|
|
13
|
+
*/
|
|
14
|
+
declare function assertOutputMode(profile: Profile, structuredId: string | null): void;
|
|
9
15
|
declare function assertSpeechRole(profile: Profile): void;
|
|
10
|
-
declare function resolveImageFormat(profile: Profile
|
|
16
|
+
declare function resolveImageFormat(profile: Profile): ImageResponseFormat | null;
|
|
11
17
|
declare function resolveInputParts(profile: Profile, model: ModelId, req: TurnRequest): InteractionPart[];
|
|
12
|
-
|
|
13
|
-
export { assertImageGrounding, assertSpeechRole, resolveImageFormat, resolveInputParts };
|
|
18
|
+
export { assertOutputMode, assertSpeechRole, resolveImageFormat, resolveInputParts };
|
|
@@ -5,119 +5,139 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module
|
|
7
7
|
*/
|
|
8
|
+
import { wrapUserData } from '../../guardrails/canary.js';
|
|
8
9
|
import { TheorumError } from '../../guardrails/error.js';
|
|
9
|
-
import { wrapUserData } from '../engine/boundary.js';
|
|
10
10
|
import { synthesizeRepairPrompt } from '../engine/repair.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
import { isSpeechFormatAllowedForProtocol } from '../schema.js';
|
|
12
|
+
import { assertAttachmentLimits, isTurnMediaRef, requireMediaLimits } from './attachments.js';
|
|
13
|
+
import { mediaKindForMime, mimeAllowed, mimeEssence, profileAccept, } from './catalog.js';
|
|
14
|
+
import { getStructured } from './schemas.js';
|
|
15
|
+
function usesStructuredResponseFormat(structuredId) {
|
|
16
|
+
if (!structuredId) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
const spec = getStructured(structuredId);
|
|
20
|
+
return spec.enforced === 'responseFormat' && spec.jsonSchema != null;
|
|
21
|
+
}
|
|
22
|
+
function activePrimaryOutputModes(profile, structuredId) {
|
|
23
|
+
const modes = [];
|
|
24
|
+
if (usesStructuredResponseFormat(structuredId)) {
|
|
25
|
+
modes.push('structured');
|
|
16
26
|
}
|
|
17
|
-
if (
|
|
18
|
-
|
|
27
|
+
if (profile.type === 'image') {
|
|
28
|
+
modes.push('image');
|
|
19
29
|
}
|
|
20
|
-
if (
|
|
21
|
-
|
|
30
|
+
if (profile.type === 'speech') {
|
|
31
|
+
modes.push('speech');
|
|
22
32
|
}
|
|
23
|
-
return
|
|
33
|
+
return modes;
|
|
24
34
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return undefined;
|
|
35
|
-
}
|
|
36
|
-
const fromPin = listedValue(allow, pin);
|
|
37
|
-
if (!fromPin) {
|
|
38
|
-
throw new TheorumError(`Unknown image ${label} for ${profileId}`);
|
|
35
|
+
/**
|
|
36
|
+
* Provider wire formats (JSON schema, image, speech) are mutually exclusive.
|
|
37
|
+
* Typed profiles make illegal mixes unrepresentable; this remains a safety net
|
|
38
|
+
* for responseFormat structured on text vs accidental dual modes.
|
|
39
|
+
*/
|
|
40
|
+
function assertOutputMode(profile, structuredId) {
|
|
41
|
+
const active = activePrimaryOutputModes(profile, structuredId);
|
|
42
|
+
if (active.length <= 1) {
|
|
43
|
+
return;
|
|
39
44
|
}
|
|
40
|
-
|
|
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)
|
|
47
|
+
`'responseFormat'), image, or speech may be active.`);
|
|
41
48
|
}
|
|
42
|
-
function
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
throw new TheorumError(`Profile ${profile.id} requests image output but does not set outputs.image`);
|
|
49
|
+
function assertImagePins(profile) {
|
|
50
|
+
if (profile.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)
|
|
46
52
|
}
|
|
47
|
-
|
|
48
|
-
|
|
53
|
+
return profile.image;
|
|
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;
|
|
49
59
|
}
|
|
50
60
|
function assertSpeechRole(profile) {
|
|
51
|
-
if (
|
|
61
|
+
if (profile.type !== 'speech') {
|
|
52
62
|
return;
|
|
53
63
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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)
|
|
57
68
|
`(geminiInteractions speech returns PCM and emits WAV)`);
|
|
58
69
|
}
|
|
59
70
|
}
|
|
60
|
-
function
|
|
61
|
-
|
|
62
|
-
if (profile.outputs[other]) {
|
|
63
|
-
throw new TheorumError(`Profile ${profile.id} cannot mix outputs.${kind} with outputs.${other}`);
|
|
64
|
-
}
|
|
65
|
-
if (profile.outputs.structured !== null && profile.outputs.structured !== undefined) {
|
|
66
|
-
throw new TheorumError(`Profile ${profile.id} cannot mix structured JSON with native ${kind} output`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
function resolveImageFormat(profile, _model, slots) {
|
|
70
|
-
if (!profile.outputs.image) {
|
|
71
|
+
function resolveImageFormat(profile) {
|
|
72
|
+
if (profile.type !== 'image') {
|
|
71
73
|
return null;
|
|
72
74
|
}
|
|
73
|
-
const pins =
|
|
74
|
-
const aspectRatio = resolveSlotOrPin(profile.id, 'aspect', slots?.aspectRatio, pins.aspectRatio, profile.inputs.slots?.aspectRatio);
|
|
75
|
-
const size = resolveSlotOrPin(profile.id, 'size', slots?.size, pins.size, profile.inputs.slots?.size);
|
|
76
|
-
if (!(aspectRatio && size)) {
|
|
77
|
-
throw new TheorumError(`Unknown image aspect or size for ${profile.id}`);
|
|
78
|
-
}
|
|
75
|
+
const pins = assertImagePins(profile);
|
|
79
76
|
return {
|
|
80
77
|
type: 'image',
|
|
81
|
-
mimeType: pins.mimeType
|
|
82
|
-
aspectRatio,
|
|
83
|
-
size,
|
|
78
|
+
mimeType: pins.mimeType,
|
|
79
|
+
aspectRatio: pins.aspectRatio,
|
|
80
|
+
size: pins.size,
|
|
81
|
+
includeText: pins.includeText === true,
|
|
84
82
|
};
|
|
85
83
|
}
|
|
86
84
|
function assertMediaMime(mime) {
|
|
87
85
|
const kind = mediaKindForMime(mime);
|
|
88
86
|
if (!kind) {
|
|
89
|
-
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)
|
|
90
88
|
}
|
|
91
89
|
return kind;
|
|
92
90
|
}
|
|
91
|
+
function profileInputs(profile) {
|
|
92
|
+
if (profile.type === 'speech' || profile.type === 'live' || profile.type === 'host') {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
return profile.inputs;
|
|
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
|
+
*/
|
|
93
102
|
function mediaParts(profile, model, blobs, channel) {
|
|
94
|
-
const accept =
|
|
103
|
+
const accept = profileAccept(profile, channel);
|
|
95
104
|
if (!accept) {
|
|
96
|
-
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)
|
|
97
106
|
}
|
|
98
|
-
const maxInputImages = profile.
|
|
107
|
+
const maxInputImages = profile.type === 'image' ? profile.image.maxInputImages : undefined;
|
|
99
108
|
const imageCount = blobs.filter((blob) => mediaKindForMime(blob.mimeType) === 'image').length;
|
|
100
109
|
if (maxInputImages !== undefined && imageCount > maxInputImages) {
|
|
101
|
-
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)
|
|
102
111
|
}
|
|
103
112
|
return blobs.map((blob) => {
|
|
104
113
|
const kind = assertMediaMime(blob.mimeType);
|
|
105
114
|
if (!mimeAllowed(accept, blob.mimeType)) {
|
|
106
|
-
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)
|
|
107
116
|
}
|
|
108
117
|
const essence = mimeEssence(blob.mimeType);
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
};
|
|
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 };
|
|
114
123
|
});
|
|
115
124
|
}
|
|
116
125
|
function extractTextPart(profile, req) {
|
|
117
126
|
const { text, repair, history } = req.input ?? {};
|
|
118
|
-
if (profile.
|
|
127
|
+
if (profile.type === 'speech') {
|
|
128
|
+
if (!text?.trim()) {
|
|
129
|
+
throw new TheorumError(`Profile ${profile.id} (speech) requires text input`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
130
|
+
}
|
|
131
|
+
let promptText = text;
|
|
132
|
+
if (repair) {
|
|
133
|
+
promptText = synthesizeRepairPrompt({ profile, repair, history });
|
|
134
|
+
}
|
|
135
|
+
return { type: 'text', text: wrapUserData(promptText) };
|
|
136
|
+
}
|
|
137
|
+
const inputs = profileInputs(profile);
|
|
138
|
+
if (inputs?.text === false) {
|
|
119
139
|
if (text) {
|
|
120
|
-
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)
|
|
121
141
|
}
|
|
122
142
|
return null;
|
|
123
143
|
}
|
|
@@ -131,6 +151,13 @@ function extractTextPart(profile, req) {
|
|
|
131
151
|
return { type: 'text', text: wrapUserData(promptText) };
|
|
132
152
|
}
|
|
133
153
|
function extractMediaParts(profile, model, req) {
|
|
154
|
+
if (profile.type === 'speech') {
|
|
155
|
+
const { attachments, voice } = req.input ?? {};
|
|
156
|
+
if ((attachments?.length ?? 0) + (voice?.length ?? 0) > 0) {
|
|
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)
|
|
158
|
+
}
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
134
161
|
const { attachments, voice } = req.input ?? {};
|
|
135
162
|
const files = attachments ?? [];
|
|
136
163
|
const clips = voice ?? [];
|
|
@@ -155,9 +182,4 @@ function resolveInputParts(profile, model, req) {
|
|
|
155
182
|
parts.push(...extractMediaParts(profile, model, req));
|
|
156
183
|
return parts;
|
|
157
184
|
}
|
|
158
|
-
|
|
159
|
-
if (profile.outputs.image?.allowsGrounding === false && builtins.length > 0) {
|
|
160
|
-
throw new TheorumError(`Grounding tools are not valid on ${model}`);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
export { assertImageGrounding, assertSpeechRole, resolveImageFormat, resolveInputParts };
|
|
185
|
+
export { assertOutputMode, assertSpeechRole, resolveImageFormat, resolveInputParts };
|
|
@@ -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 };
|
|
@@ -1,23 +1,66 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Runtime profile registry for host-owned THEORUM profiles.
|
|
3
3
|
*
|
|
4
|
-
* THEORUM ships profile types
|
|
5
|
-
*
|
|
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
|
-
import type
|
|
10
|
-
|
|
11
|
-
|
|
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 = {
|
|
12
13
|
id: Profile['id'];
|
|
13
|
-
identity
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
identity: ProfileIdentity;
|
|
15
|
+
models: Record<ModelId, ModelBinding>;
|
|
16
|
+
defaultModel?: ModelId;
|
|
17
|
+
allowModelSelect?: boolean;
|
|
18
|
+
maxSteps?: number;
|
|
19
|
+
key?: ProfileModelFields['key'];
|
|
20
|
+
outputs?: ProfileOutputsSpec;
|
|
21
|
+
guardrails?: ProfileGuardrailsSpec;
|
|
22
|
+
observability?: ProfileObservabilitySpec;
|
|
19
23
|
};
|
|
20
|
-
|
|
24
|
+
export type TextProfileDefinition = ProfileDefinitionBase & {
|
|
25
|
+
type: 'text';
|
|
26
|
+
tools: ProfileToolsSpec;
|
|
27
|
+
inputs: ProfileInputsSpec;
|
|
28
|
+
turnBehaviour?: ProfileTurnBehaviourSpec;
|
|
29
|
+
};
|
|
30
|
+
export type ImageProfileDefinition = ProfileDefinitionBase & {
|
|
31
|
+
type: 'image';
|
|
32
|
+
image: NonNullable<ImageProfile['image']>;
|
|
33
|
+
tools: ProfileToolsSpec;
|
|
34
|
+
inputs: ProfileInputsSpec;
|
|
35
|
+
turnBehaviour?: ProfileTurnBehaviourSpec;
|
|
36
|
+
};
|
|
37
|
+
export type SpeechProfileDefinition = ProfileDefinitionBase & {
|
|
38
|
+
type: 'speech';
|
|
39
|
+
speech: NonNullable<SpeechProfile['speech']>;
|
|
40
|
+
turnBehaviour?: ProfileTurnBehaviourSpec;
|
|
41
|
+
};
|
|
42
|
+
export type LiveProfileDefinition = ProfileDefinitionBase & {
|
|
43
|
+
type: 'live';
|
|
44
|
+
live: NonNullable<LiveProfile['live']>;
|
|
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;
|
|
57
|
+
};
|
|
58
|
+
/** Host-authored profile definition — discriminated on `type`. No THEORUM defaults. */
|
|
59
|
+
export type ProfileDefinition = TextProfileDefinition | ImageProfileDefinition | SpeechProfileDefinition | LiveProfileDefinition | HostProfileDefinition;
|
|
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>;
|
|
21
64
|
declare function defineProfile(input: ProfileDefinition): Profile;
|
|
22
65
|
/** Register one host-owned profile in the process-local registry. */
|
|
23
66
|
declare function registerProfile(profileInput: Profile | ProfileDefinition): void;
|