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
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `runSession` — long-lived live profile execution.
|
|
3
|
+
*
|
|
4
|
+
* Shares resolve / tools / canary / system / outbound gate with `runTurn`.
|
|
5
|
+
* Does not use `ModelProvider.complete()` — live is a session, not one turn.
|
|
6
|
+
*
|
|
7
|
+
* Stages: `docs/contracts/stages.md` (cycle map + `executeTool`).
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import { bindCanary } from '../../../guardrails/canary.js';
|
|
12
|
+
import { publicError, TheorumError, throwIfAborted, toErrorEvent, } from '../../../guardrails/error.js';
|
|
13
|
+
import { projectGuardrailTurnEvent } from '../../../guardrails/events.js';
|
|
14
|
+
import { abortLiveOutboundTurn, createLiveOutboundGateSession, finalizeLiveOutboundTurn, processLiveOutboundBatch, } from '../../../guardrails/live-outbound-gate.js';
|
|
15
|
+
import { resolveGuardrailPolicy } from '../../../guardrails/policy.js';
|
|
16
|
+
import { sanitizeTurnRequest } from '../../../guardrails/sanitize.js';
|
|
17
|
+
import { resolveObservabilityPolicy } from '../../../observability/resolve-policy.js';
|
|
18
|
+
import { buildGeminiLiveRealtimeInput, buildGeminiLiveRealtimeText, buildGeminiLiveToolResponse, buildGeminiLiveToolResponses, } from '../../../providers/google/live/framing.js';
|
|
19
|
+
import { openGoogleLiveSession } from '../../../providers/google/live/session.js';
|
|
20
|
+
import { providerCompleteRequest } from '../../registry/provider-request.js';
|
|
21
|
+
import { resolveTurn } from '../../registry/resolve.js';
|
|
22
|
+
import { runStage } from '../../stages.js';
|
|
23
|
+
import { profileAllowsInject } from '../../stop.js';
|
|
24
|
+
import { executeRegisteredTool, formatToolFailureForModel, formatToolResult, } from '../../tools/execute.js';
|
|
25
|
+
import { cloneTurnToolSnapshot } from '../../tools/resolve.js';
|
|
26
|
+
import { prepareLiveInboundText } from '../live-inbound.js';
|
|
27
|
+
import { assertLiveIngress } from '../live-ingress.js';
|
|
28
|
+
/** Inject on live is realtime text ingress only: no tool role, no media parts. */
|
|
29
|
+
function liveInjectTexts(messages) {
|
|
30
|
+
const out = [];
|
|
31
|
+
for (const msg of messages) {
|
|
32
|
+
if (msg.role === 'tool')
|
|
33
|
+
continue;
|
|
34
|
+
if (msg.parts?.length)
|
|
35
|
+
continue;
|
|
36
|
+
const text = msg.content?.trim();
|
|
37
|
+
if (text)
|
|
38
|
+
out.push(text);
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
function assertLiveProfile(profile) {
|
|
43
|
+
if (profile.type !== 'live') {
|
|
44
|
+
throw new TheorumError(`runSession requires profile.type 'live' (got '${profile.type}' for ${profile.id})`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Accept a registry-resolved snapshot from the process that owns the tool
|
|
49
|
+
* registry. The profile's `tools.allow` stays the ceiling: a custom tool id
|
|
50
|
+
* outside it is refused rather than declared.
|
|
51
|
+
*/
|
|
52
|
+
function sessionSnapshotWithinAllow(profile, snapshot) {
|
|
53
|
+
const allow = new Set(profile.tools.allow);
|
|
54
|
+
const builtins = new Set(snapshot.builtins);
|
|
55
|
+
const outside = new Set();
|
|
56
|
+
for (const id of [...snapshot.gated, ...snapshot.visible, ...snapshot.executable]) {
|
|
57
|
+
if (!allow.has(id) && !builtins.has(id)) {
|
|
58
|
+
outside.add(id);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (outside.size > 0) {
|
|
62
|
+
// lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
63
|
+
const detail = `session snapshot declares tools outside tools.allow: ${[...outside].join(', ')}`;
|
|
64
|
+
throw new TheorumError(`Profile ${profile.id}: ${detail}`);
|
|
65
|
+
}
|
|
66
|
+
return cloneTurnToolSnapshot(snapshot);
|
|
67
|
+
}
|
|
68
|
+
function toTurnRequest(req) {
|
|
69
|
+
return {
|
|
70
|
+
profile: req.profile,
|
|
71
|
+
system: req.system,
|
|
72
|
+
path: req.path,
|
|
73
|
+
sessionPermissions: req.sessionPermissions,
|
|
74
|
+
sessionResumptionHandle: req.sessionResumptionHandle,
|
|
75
|
+
signal: req.signal,
|
|
76
|
+
metadata: req.metadata,
|
|
77
|
+
host: req.host,
|
|
78
|
+
input: {
|
|
79
|
+
text: '',
|
|
80
|
+
history: req.history,
|
|
81
|
+
sessionResumptionHandle: req.sessionResumptionHandle,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function applyVoiceOverride(generation, voice) {
|
|
86
|
+
if (!voice || !generation.live) {
|
|
87
|
+
return generation;
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
...generation,
|
|
91
|
+
live: {
|
|
92
|
+
...generation.live,
|
|
93
|
+
voice,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function applyInitialInput(generation, input) {
|
|
98
|
+
if (!input || input.length === 0) {
|
|
99
|
+
return generation;
|
|
100
|
+
}
|
|
101
|
+
return { ...generation, input };
|
|
102
|
+
}
|
|
103
|
+
async function applyOutbound(gate, events, turnPhase, onWithhold) {
|
|
104
|
+
if (turnPhase === 'abort') {
|
|
105
|
+
abortLiveOutboundTurn(gate);
|
|
106
|
+
// Keep tool calls + interrupted marker; drop buffered speech via abortLiveOutboundTurn.
|
|
107
|
+
return events.filter((ev) => ev.type === 'tool' ||
|
|
108
|
+
ev.type === 'session' ||
|
|
109
|
+
(ev.type === 'done' && ev.interrupted === true));
|
|
110
|
+
}
|
|
111
|
+
const batch = await processLiveOutboundBatch(gate, events);
|
|
112
|
+
const out = [];
|
|
113
|
+
if (batch.action === 'withhold') {
|
|
114
|
+
onWithhold(batch.error);
|
|
115
|
+
return [...(batch.events ?? []), { type: 'error', error: batch.error }];
|
|
116
|
+
}
|
|
117
|
+
if (batch.action === 'emit') {
|
|
118
|
+
out.push(...batch.events);
|
|
119
|
+
}
|
|
120
|
+
if (turnPhase === 'complete') {
|
|
121
|
+
const finalized = await finalizeLiveOutboundTurn(gate);
|
|
122
|
+
if (finalized.action === 'withhold') {
|
|
123
|
+
onWithhold(finalized.error);
|
|
124
|
+
return [...out, { type: 'error', error: finalized.error }];
|
|
125
|
+
}
|
|
126
|
+
if (finalized.action === 'emit') {
|
|
127
|
+
out.push(...finalized.events);
|
|
128
|
+
}
|
|
129
|
+
// Conversational turn boundary — session stays open.
|
|
130
|
+
out.push({ type: 'done', stop: { kind: 'completed' } });
|
|
131
|
+
}
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
function* drainPendingHostEvents(pendingHostEvents) {
|
|
135
|
+
while (pendingHostEvents.length > 0) {
|
|
136
|
+
const pending = pendingHostEvents.shift();
|
|
137
|
+
if (pending)
|
|
138
|
+
yield pending;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function boundaryDoneEvents(doneBatch, turnPhase, interrupted) {
|
|
142
|
+
if (doneBatch.length > 0)
|
|
143
|
+
return doneBatch;
|
|
144
|
+
if (turnPhase === 'abort' || interrupted) {
|
|
145
|
+
return [{ type: 'done', stop: { kind: 'interrupted' }, interrupted: true }];
|
|
146
|
+
}
|
|
147
|
+
return [{ type: 'done', stop: { kind: 'completed' } }];
|
|
148
|
+
}
|
|
149
|
+
/** Yield non-done batch events; return the done subset for boundary handling. */
|
|
150
|
+
function* yieldLiveNonDoneEvents(gated, includeMatch, withholdClose, recordAssistantText) {
|
|
151
|
+
const doneBatch = gated.filter((ev) => ev.type === 'done');
|
|
152
|
+
for (const ev of gated) {
|
|
153
|
+
if (ev.type === 'done')
|
|
154
|
+
continue;
|
|
155
|
+
if (ev.type === 'error') {
|
|
156
|
+
yield {
|
|
157
|
+
...ev,
|
|
158
|
+
error: publicError(ev.error ?? withholdClose ?? 'guardrail withheld'),
|
|
159
|
+
};
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (ev.type === 'text' && typeof ev.text === 'string') {
|
|
163
|
+
recordAssistantText(ev.text);
|
|
164
|
+
}
|
|
165
|
+
yield projectGuardrailTurnEvent(ev, includeMatch ?? false);
|
|
166
|
+
}
|
|
167
|
+
return doneBatch;
|
|
168
|
+
}
|
|
169
|
+
function buildLiveSession(args) {
|
|
170
|
+
const { profile, canary, connection, gate, signal, onStage, host: sessionHost, credentials: sessionCredentials, sessionPermissions, path, snapshot, } = args;
|
|
171
|
+
let closed = false;
|
|
172
|
+
let withholdClose;
|
|
173
|
+
const pendingHostEvents = [];
|
|
174
|
+
const includeMatch = resolveObservabilityPolicy(profile.observability).include
|
|
175
|
+
.guardrailMatchPreview;
|
|
176
|
+
let cycle = 'idle';
|
|
177
|
+
let cycleStep = 0;
|
|
178
|
+
const history = args.historySeed?.length
|
|
179
|
+
? structuredClone(args.historySeed)
|
|
180
|
+
: [];
|
|
181
|
+
/** Serialize stage + ingress so concurrent send* cannot interleave cycles. */
|
|
182
|
+
let ingressChain = Promise.resolve();
|
|
183
|
+
const recordUserText = (text) => {
|
|
184
|
+
const trimmed = text.trim();
|
|
185
|
+
if (trimmed)
|
|
186
|
+
history.push({ role: 'user', content: trimmed });
|
|
187
|
+
};
|
|
188
|
+
const recordAssistantText = (text) => {
|
|
189
|
+
const trimmed = text.trim();
|
|
190
|
+
if (!trimmed)
|
|
191
|
+
return;
|
|
192
|
+
const last = history.at(-1);
|
|
193
|
+
if (last?.role === 'assistant' && typeof last.content === 'string' && !last.tool_calls) {
|
|
194
|
+
last.content = `${last.content}${trimmed}`;
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
history.push({ role: 'assistant', content: trimmed });
|
|
198
|
+
};
|
|
199
|
+
const recordToolSettle = (tool) => {
|
|
200
|
+
const args = tool.input && typeof tool.input === 'object' && !Array.isArray(tool.input)
|
|
201
|
+
? tool.input
|
|
202
|
+
: {};
|
|
203
|
+
const modelResult = tool.failure
|
|
204
|
+
? formatToolFailureForModel(tool.failure)
|
|
205
|
+
: tool.output !== undefined
|
|
206
|
+
? {
|
|
207
|
+
finding: typeof tool.output === 'string' ? tool.output : JSON.stringify(tool.output),
|
|
208
|
+
data: tool.output,
|
|
209
|
+
}
|
|
210
|
+
: formatToolFailureForModel({
|
|
211
|
+
code: 'error',
|
|
212
|
+
message: 'Tool settled without output', // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
213
|
+
});
|
|
214
|
+
history.push({
|
|
215
|
+
role: 'assistant',
|
|
216
|
+
tool_calls: [
|
|
217
|
+
{
|
|
218
|
+
id: tool.callId,
|
|
219
|
+
type: 'function',
|
|
220
|
+
function: {
|
|
221
|
+
name: tool.name,
|
|
222
|
+
arguments: JSON.stringify(args),
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
}, {
|
|
227
|
+
role: 'tool',
|
|
228
|
+
tool_call_id: tool.callId,
|
|
229
|
+
name: tool.name,
|
|
230
|
+
content: formatToolResult(modelResult),
|
|
231
|
+
});
|
|
232
|
+
};
|
|
233
|
+
const enqueuePending = (ev) => {
|
|
234
|
+
pendingHostEvents.push(projectGuardrailTurnEvent(ev, includeMatch));
|
|
235
|
+
};
|
|
236
|
+
const sendJson = (payload) => {
|
|
237
|
+
if (closed) {
|
|
238
|
+
throw new TheorumError('Live session is closed'); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
239
|
+
}
|
|
240
|
+
connection.send(JSON.stringify(payload));
|
|
241
|
+
};
|
|
242
|
+
const runCycleStage = async (stage, extra) => {
|
|
243
|
+
const gen = runStage({
|
|
244
|
+
...extra,
|
|
245
|
+
stage,
|
|
246
|
+
step: Math.max(1, cycleStep),
|
|
247
|
+
history,
|
|
248
|
+
handlers: onStage ? [onStage] : [],
|
|
249
|
+
guardrails: profile.guardrails,
|
|
250
|
+
injectAllowed: profileAllowsInject(profile),
|
|
251
|
+
host: sessionHost,
|
|
252
|
+
signal,
|
|
253
|
+
});
|
|
254
|
+
let result = await gen.next();
|
|
255
|
+
while (!result.done) {
|
|
256
|
+
enqueuePending(result.value);
|
|
257
|
+
result = await gen.next();
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
abort: result.value.abort,
|
|
261
|
+
injectTexts: liveInjectTexts(result.value.inject),
|
|
262
|
+
};
|
|
263
|
+
};
|
|
264
|
+
const ingestPreparedLiveText = (text) => {
|
|
265
|
+
const prepared = prepareLiveInboundText(profile, text);
|
|
266
|
+
if (prepared.guardrail) {
|
|
267
|
+
enqueuePending(prepared.guardrail);
|
|
268
|
+
}
|
|
269
|
+
recordUserText(prepared.text);
|
|
270
|
+
sendJson(buildGeminiLiveRealtimeText(prepared.text));
|
|
271
|
+
};
|
|
272
|
+
const applyInjectTexts = (texts) => {
|
|
273
|
+
for (const text of texts) {
|
|
274
|
+
// Cycle already open — write without re-entering pre_turn.
|
|
275
|
+
assertLiveIngress(profile, 'text');
|
|
276
|
+
ingestPreparedLiveText(text);
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
const openCycleIfNeeded = async () => {
|
|
280
|
+
if (cycle === 'open')
|
|
281
|
+
return { aborted: false };
|
|
282
|
+
cycle = 'open';
|
|
283
|
+
cycleStep += 1;
|
|
284
|
+
const pre = await runCycleStage('pre_turn');
|
|
285
|
+
if (pre.abort) {
|
|
286
|
+
const done = {
|
|
287
|
+
type: 'done',
|
|
288
|
+
stop: { kind: 'cancelled' },
|
|
289
|
+
interrupted: true,
|
|
290
|
+
};
|
|
291
|
+
enqueuePending(done);
|
|
292
|
+
await runCycleStage('post_turn', { stop: { kind: 'cancelled' } });
|
|
293
|
+
cycle = 'idle';
|
|
294
|
+
return { aborted: true };
|
|
295
|
+
}
|
|
296
|
+
if (pre.injectTexts.length) {
|
|
297
|
+
await applyInjectTexts(pre.injectTexts);
|
|
298
|
+
}
|
|
299
|
+
return { aborted: false };
|
|
300
|
+
};
|
|
301
|
+
const endCycleAroundDone = async function* (doneEvents) {
|
|
302
|
+
if (cycle !== 'open') {
|
|
303
|
+
for (const ev of doneEvents)
|
|
304
|
+
yield ev;
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const before = await runCycleStage('before_end', {
|
|
308
|
+
stop: doneEvents.find((e) => e.type === 'done')?.stop,
|
|
309
|
+
});
|
|
310
|
+
if (before.abort) {
|
|
311
|
+
yield { type: 'done', stop: { kind: 'cancelled' }, interrupted: true };
|
|
312
|
+
await runCycleStage('post_turn', { stop: { kind: 'cancelled' } });
|
|
313
|
+
cycle = 'idle';
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
if (before.injectTexts.length) {
|
|
317
|
+
await applyInjectTexts(before.injectTexts);
|
|
318
|
+
}
|
|
319
|
+
for (const ev of doneEvents) {
|
|
320
|
+
yield ev;
|
|
321
|
+
}
|
|
322
|
+
const terminal = doneEvents.find((e) => e.type === 'done');
|
|
323
|
+
await runCycleStage('post_turn', { stop: terminal?.stop });
|
|
324
|
+
cycle = 'idle';
|
|
325
|
+
};
|
|
326
|
+
const withIngress = (fn) => {
|
|
327
|
+
const next = ingressChain.then(fn, fn);
|
|
328
|
+
ingressChain = next.then(() => undefined, () => undefined);
|
|
329
|
+
return next;
|
|
330
|
+
};
|
|
331
|
+
const session = {
|
|
332
|
+
profileId: profile.id,
|
|
333
|
+
canary,
|
|
334
|
+
async *events() {
|
|
335
|
+
try {
|
|
336
|
+
for await (const item of connection.batches()) {
|
|
337
|
+
throwIfAborted(signal);
|
|
338
|
+
yield* drainPendingHostEvents(pendingHostEvents);
|
|
339
|
+
if (item.type === 'closed') {
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
if (item.type === 'error') {
|
|
343
|
+
yield toErrorEvent(item.error);
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
const gated = await applyOutbound(gate, item.events, item.turnPhase, (error) => {
|
|
347
|
+
withholdClose = error;
|
|
348
|
+
});
|
|
349
|
+
const doneBatch = yield* yieldLiveNonDoneEvents(gated, includeMatch, withholdClose, recordAssistantText);
|
|
350
|
+
const interrupted = doneBatch.some((ev) => ev.type === 'done' && ev.interrupted);
|
|
351
|
+
const completeBoundary = item.turnPhase === 'complete' || item.turnPhase === 'abort' || doneBatch.length > 0;
|
|
352
|
+
// Boundary batches (`interactionStatus: IDLE`, or bare `turnComplete` when the
|
|
353
|
+
// provider sends no status) often have no folded `done` — still end the cycle.
|
|
354
|
+
if (completeBoundary && cycle === 'open') {
|
|
355
|
+
const boundaryDone = boundaryDoneEvents(doneBatch, item.turnPhase, interrupted);
|
|
356
|
+
for await (const ev of endCycleAroundDone(boundaryDone)) {
|
|
357
|
+
yield projectGuardrailTurnEvent(ev, includeMatch);
|
|
358
|
+
}
|
|
359
|
+
yield* drainPendingHostEvents(pendingHostEvents);
|
|
360
|
+
}
|
|
361
|
+
else if (doneBatch.length > 0) {
|
|
362
|
+
for (const ev of doneBatch) {
|
|
363
|
+
yield projectGuardrailTurnEvent(ev, includeMatch);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
if (withholdClose) {
|
|
367
|
+
connection.close(1011, 'guardrail withheld');
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
yield* drainPendingHostEvents(pendingHostEvents);
|
|
372
|
+
}
|
|
373
|
+
finally {
|
|
374
|
+
closed = true;
|
|
375
|
+
connection.close();
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
sendAudio(audio) {
|
|
379
|
+
return withIngress(async () => {
|
|
380
|
+
if (!audio.data)
|
|
381
|
+
return;
|
|
382
|
+
assertLiveIngress(profile, 'audio');
|
|
383
|
+
const opened = await openCycleIfNeeded();
|
|
384
|
+
if (opened.aborted)
|
|
385
|
+
return;
|
|
386
|
+
sendJson(buildGeminiLiveRealtimeInput({
|
|
387
|
+
type: 'audio',
|
|
388
|
+
mimeType: audio.mimeType ?? 'audio/pcm;rate=16000',
|
|
389
|
+
data: audio.data,
|
|
390
|
+
}));
|
|
391
|
+
});
|
|
392
|
+
},
|
|
393
|
+
sendVideo(video) {
|
|
394
|
+
return withIngress(async () => {
|
|
395
|
+
assertLiveIngress(profile, 'video');
|
|
396
|
+
const opened = await openCycleIfNeeded();
|
|
397
|
+
if (opened.aborted)
|
|
398
|
+
return;
|
|
399
|
+
sendJson(buildGeminiLiveRealtimeInput({
|
|
400
|
+
type: 'video',
|
|
401
|
+
mimeType: video.mimeType ?? 'image/jpeg',
|
|
402
|
+
data: video.data,
|
|
403
|
+
}));
|
|
404
|
+
});
|
|
405
|
+
},
|
|
406
|
+
sendText(text) {
|
|
407
|
+
return withIngress(async () => {
|
|
408
|
+
assertLiveIngress(profile, 'text');
|
|
409
|
+
const opened = await openCycleIfNeeded();
|
|
410
|
+
if (opened.aborted)
|
|
411
|
+
return;
|
|
412
|
+
ingestPreparedLiveText(text);
|
|
413
|
+
});
|
|
414
|
+
},
|
|
415
|
+
async executeTool(toolArgs) {
|
|
416
|
+
if (closed) {
|
|
417
|
+
throw new TheorumError('Live session is closed'); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
418
|
+
}
|
|
419
|
+
const handlers = onStage ? [onStage] : [];
|
|
420
|
+
const exec = executeRegisteredTool({
|
|
421
|
+
profile,
|
|
422
|
+
name: toolArgs.name,
|
|
423
|
+
input: toolArgs.input ?? {},
|
|
424
|
+
callId: toolArgs.callId,
|
|
425
|
+
ctx: {
|
|
426
|
+
sessionPermissions,
|
|
427
|
+
credentials: toolArgs.credentials ?? sessionCredentials,
|
|
428
|
+
path,
|
|
429
|
+
signal,
|
|
430
|
+
resume: toolArgs.resume,
|
|
431
|
+
host: toolArgs.host ?? sessionHost,
|
|
432
|
+
turn: { step: Math.max(1, cycleStep) },
|
|
433
|
+
},
|
|
434
|
+
snapshot,
|
|
435
|
+
stages: {
|
|
436
|
+
handlers,
|
|
437
|
+
profile,
|
|
438
|
+
step: Math.max(1, cycleStep),
|
|
439
|
+
history: () => history,
|
|
440
|
+
injectAllowed: profileAllowsInject(profile),
|
|
441
|
+
host: toolArgs.host ?? sessionHost,
|
|
442
|
+
signal,
|
|
443
|
+
},
|
|
444
|
+
});
|
|
445
|
+
let settlement;
|
|
446
|
+
while (true) {
|
|
447
|
+
const next = await exec.next();
|
|
448
|
+
if (next.done) {
|
|
449
|
+
settlement = next.value;
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
enqueuePending(next.value);
|
|
453
|
+
}
|
|
454
|
+
if (!settlement || typeof settlement !== 'object') {
|
|
455
|
+
return {};
|
|
456
|
+
}
|
|
457
|
+
const s = settlement;
|
|
458
|
+
if (s.gated) {
|
|
459
|
+
return { gated: s.gated };
|
|
460
|
+
}
|
|
461
|
+
// post_tool inject on live → schedule text ingress
|
|
462
|
+
if (s.pendingInject?.length) {
|
|
463
|
+
const texts = liveInjectTexts(s.pendingInject);
|
|
464
|
+
if (texts.length) {
|
|
465
|
+
await withIngress(async () => {
|
|
466
|
+
const opened = await openCycleIfNeeded();
|
|
467
|
+
if (!opened.aborted)
|
|
468
|
+
await applyInjectTexts(texts);
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
const outputModel = s.modelResult;
|
|
473
|
+
if (outputModel !== undefined || s.failure) {
|
|
474
|
+
recordToolSettle({
|
|
475
|
+
name: toolArgs.name,
|
|
476
|
+
callId: toolArgs.callId,
|
|
477
|
+
input: toolArgs.input,
|
|
478
|
+
output: s.outputRaw ?? outputModel?.data ?? outputModel,
|
|
479
|
+
failure: s.failure,
|
|
480
|
+
});
|
|
481
|
+
const upstream = outputModel ??
|
|
482
|
+
{
|
|
483
|
+
finding: s.failure ? `Tool error (${s.failure.code}): ${s.failure.message}` : 'error',
|
|
484
|
+
data: s.failure,
|
|
485
|
+
};
|
|
486
|
+
sendJson(buildGeminiLiveToolResponse(toolArgs.callId, toolArgs.name, upstream.data ?? upstream));
|
|
487
|
+
}
|
|
488
|
+
return {
|
|
489
|
+
outputRaw: s.outputRaw,
|
|
490
|
+
outputModel,
|
|
491
|
+
failure: s.failure,
|
|
492
|
+
awaiting: s.awaiting,
|
|
493
|
+
};
|
|
494
|
+
},
|
|
495
|
+
sendToolResponse(id, name, output) {
|
|
496
|
+
sendJson(buildGeminiLiveToolResponse(id, name, output));
|
|
497
|
+
},
|
|
498
|
+
sendToolResponses(responses) {
|
|
499
|
+
sendJson(buildGeminiLiveToolResponses(responses));
|
|
500
|
+
},
|
|
501
|
+
close(reason = 'session-closed') {
|
|
502
|
+
if (closed)
|
|
503
|
+
return Promise.resolve();
|
|
504
|
+
closed = true;
|
|
505
|
+
connection.close(1000, reason);
|
|
506
|
+
return Promise.resolve();
|
|
507
|
+
},
|
|
508
|
+
};
|
|
509
|
+
if (args.openInitialCycle) {
|
|
510
|
+
void withIngress(async () => {
|
|
511
|
+
await openCycleIfNeeded();
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
return session;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Open a gated Gemini Live session for a `type: 'live'` profile.
|
|
518
|
+
*
|
|
519
|
+
* Hosts bridge browser sockets and tool dispatch; THEORUM owns Gemini WS,
|
|
520
|
+
* framing, inbound prep, outbound canary/egress gates, and live stages.
|
|
521
|
+
*/
|
|
522
|
+
export async function runSession(req, options) {
|
|
523
|
+
const turnReq = toTurnRequest(req);
|
|
524
|
+
const safe = sanitizeTurnRequest(turnReq);
|
|
525
|
+
throwIfAborted(safe.signal);
|
|
526
|
+
const { profile, generation: gen0 } = resolveTurn(safe);
|
|
527
|
+
assertLiveProfile(profile);
|
|
528
|
+
if (req.snapshot) {
|
|
529
|
+
gen0.tools = sessionSnapshotWithinAllow(profile, req.snapshot);
|
|
530
|
+
}
|
|
531
|
+
gen0.builtins = gen0.tools.builtins;
|
|
532
|
+
let generation = applyVoiceOverride(gen0, req.voice);
|
|
533
|
+
const hasInitialInput = Boolean(req.input && req.input.length > 0);
|
|
534
|
+
generation = applyInitialInput(generation, req.input);
|
|
535
|
+
const system = bindCanary(generation.resolvedSystem, generation.canary, resolveGuardrailPolicy(profile.guardrails).canaryBindNote);
|
|
536
|
+
const completeReq = {
|
|
537
|
+
...providerCompleteRequest(generation, system),
|
|
538
|
+
signal: safe.signal,
|
|
539
|
+
};
|
|
540
|
+
const gate = createLiveOutboundGateSession(profile, generation.canary || undefined);
|
|
541
|
+
const connection = await openGoogleLiveSession(completeReq, options.gemini, options.openWebSocket);
|
|
542
|
+
return buildLiveSession({
|
|
543
|
+
profile,
|
|
544
|
+
canary: generation.canary,
|
|
545
|
+
connection,
|
|
546
|
+
gate,
|
|
547
|
+
signal: safe.signal,
|
|
548
|
+
onStage: req.onStage,
|
|
549
|
+
host: req.host,
|
|
550
|
+
credentials: req.credentials,
|
|
551
|
+
sessionPermissions: req.sessionPermissions,
|
|
552
|
+
path: req.path,
|
|
553
|
+
snapshot: gen0.tools,
|
|
554
|
+
historySeed: req.history,
|
|
555
|
+
openInitialCycle: hasInitialInput,
|
|
556
|
+
});
|
|
557
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InteractionPart wire helpers shared by kernel history + provider adapters.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { InteractionMediaRefPart, InteractionPart } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Map an InteractionPart to the Google Interactions / function_result wire shape.
|
|
9
|
+
* Reference parts emit `{ type, mimeType, uri }`; `toGoogleValue` snake-cases
|
|
10
|
+
* `mimeType` → `mime_type`, which is the documented Interactions file input.
|
|
11
|
+
*/
|
|
12
|
+
export declare function wireInteractionPart(part: InteractionPart): Record<string, string>;
|
|
13
|
+
/** True when the part carries a provider file reference instead of inline bytes. */
|
|
14
|
+
export declare function isMediaRefPart(part: InteractionPart): part is InteractionMediaRefPart;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InteractionPart wire helpers shared by kernel history + provider adapters.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Map an InteractionPart to the Google Interactions / function_result wire shape.
|
|
8
|
+
* Reference parts emit `{ type, mimeType, uri }`; `toGoogleValue` snake-cases
|
|
9
|
+
* `mimeType` → `mime_type`, which is the documented Interactions file input.
|
|
10
|
+
*/
|
|
11
|
+
export function wireInteractionPart(part) {
|
|
12
|
+
if (part.type === 'text') {
|
|
13
|
+
return { type: 'text', text: part.text };
|
|
14
|
+
}
|
|
15
|
+
if ('uri' in part) {
|
|
16
|
+
return { type: part.type, mimeType: part.mimeType, uri: part.uri };
|
|
17
|
+
}
|
|
18
|
+
return { type: part.type, mimeType: part.mimeType, data: part.data };
|
|
19
|
+
}
|
|
20
|
+
/** True when the part carries a provider file reference instead of inline bytes. */
|
|
21
|
+
export function isMediaRefPart(part) {
|
|
22
|
+
return part.type !== 'text' && 'uri' in part;
|
|
23
|
+
}
|
package/esm/src/kernel/mod.d.ts
CHANGED
|
@@ -1,22 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Profile, turn, tool, provider, egress, and event contracts for THEORUM.
|
|
3
3
|
*
|
|
4
|
-
* This entrypoint is type-first. Host applications import from here when they
|
|
5
|
-
* want to declare profiles, tool schemas, provider adapters, turn requests, or
|
|
6
|
-
* trace-safe event handlers without importing provider implementations.
|
|
7
|
-
*
|
|
8
4
|
* @module
|
|
9
5
|
*/
|
|
10
6
|
import "../../_dnt.polyfills.js";
|
|
7
|
+
export * from './auth/mod.js';
|
|
11
8
|
export type { CompactionSplit, CompactionTokens } from './engine/compaction.js';
|
|
12
9
|
export { compactionMeter, compactionNeeded, estimateHistoryTokens, HISTORY_MEDIA_TOKENS, HISTORY_TEXT_ENCODING, resolveCompactionTokens, resolveHistoryTokens, shouldCompact, splitForCompaction, } from './engine/compaction.js';
|
|
10
|
+
export type { LiveIngressChannel } from './engine/live-ingress.js';
|
|
11
|
+
export { assertLiveIngress, assertLiveIngressConfigured, hasAnyLiveIngress, liveIngressChannelDefault, liveIngressEnabled, liveIngressEnabledFromSpec, } from './engine/live-ingress.js';
|
|
13
12
|
export { runTurn } from './engine/runner.js';
|
|
14
|
-
export {
|
|
15
|
-
export
|
|
13
|
+
export type { RunSessionOptions } from './engine/session/mod.js';
|
|
14
|
+
export { runSession } from './engine/session/mod.js';
|
|
15
|
+
export { isMediaRefPart, wireInteractionPart } from './interaction-parts.js';
|
|
16
|
+
export type { ProfileGraphEditor, ProfileGraphFacet, ProfileGraphFacetId, ProfileGraphRole, } from './profile-graph.js';
|
|
17
|
+
export { PROFILE_GRAPH, profileGraphFacet, spineFacetsForProfileType, } from './profile-graph.js';
|
|
18
|
+
export type { MediaInputChannel } from './registry/catalog.js';
|
|
19
|
+
export { clampThinkingLevel, clampThinkingLevelForApiId, mediaChannelForMime, mediaKindForMime, mimeAllowed, mimeEssence, modelEntryByApiId, requireModelBinding, } from './registry/catalog.js';
|
|
20
|
+
export type { HostProfileDefinition, ImageProfileDefinition, LiveProfileDefinition, ProfileDefinition, ProfileDefinitionBase, SpeechProfileDefinition, TextProfileDefinition, } from './registry/profiles.js';
|
|
16
21
|
export { clearProfiles, defineProfile, getProfile, hasProfile, listProfiles, registerProfile, registerProfiles, } from './registry/profiles.js';
|
|
17
|
-
export { projectProfile, resolveTurn } from './registry/resolve.js';
|
|
22
|
+
export { projectProfile, projectProfileObject, requireModelProfile, resolveTurn, } from './registry/resolve.js';
|
|
18
23
|
export { getStructured, registerStructured } from './registry/schemas.js';
|
|
19
|
-
export {
|
|
20
|
-
export
|
|
21
|
-
export {
|
|
24
|
+
export type { AuthUnauthenticatedPolicy, CustomToolType, HttpMethod, PlaygroundAuthType, ToolAccess, ToolAuthType, ToolPermission, ToolType, } from './schema.js';
|
|
25
|
+
export { ATTACHMENT_ACCEPT_MIMES, AUTH_UNAUTHENTICATED_POLICIES, AWAITING_USER_INPUT_KINDS, AWAITING_USER_INPUT_STATUS, CACHE_MODES, CACHE_TTLS, COMPACTION_METERS, COMPACTION_TIMINGS, CONTINUE_STOP_KINDS, catalogPathFor, coerceProtocol, coerceProvider, coerceSpeechFormat, EXTRA_FIELDS, fieldMeta, HTTP_METHODS, isSpeechFormatAllowedForProtocol, isToolGateKind, isTurnInjectStage, isTurnStage, isValidPair, isValidProfileProtocol, KEY_SLOTS, MEDIA_INPUT_KIND_VALUES, MEDIA_INPUT_KINDS, MEDIA_WILDCARDS, OVERFLOW_KEY_SLOTS, PLAYGROUND_AUTH_TYPES, PROFILE_FIELDS, PROFILE_TYPE_PROTOCOLS, PROFILE_TYPES, PROTOCOL_PROVIDERS, PROTOCOLS, PROVIDERS, protocolsFor, protocolsForProfileType, providersFor, SCHEMA_ENFORCEMENTS, SPEECH_AUDIO_FORMATS, STREAM_MODES, SUMMARY_MODES, speechFormatsForProtocol, THINKING_LEVELS, TOOL_ACCESS, TOOL_AUTH_TYPES, TOOL_GATE_KINDS, TOOL_LOAD_TIERS, TOOL_PERMISSION, TOOL_TYPES, TURN_INJECT_STAGES, TURN_STAGES, TURN_STOP_KINDS, VOICE_ACCEPT_MIMES, } from './schema.js';
|
|
26
|
+
export type { AwaitingUserInput, StageAffordance, StageApplyInput, StageApplyOutput, StageApplyWarning, StageApplyWarningCode, StageContext, StageEventExtra, StageHandler, StageMutate, StageResult, } from './stages.js';
|
|
27
|
+
export { applyStageResult, isAwaitingUserInput, parseAwaitingUserInput, parseToolGate, STAGE_AFFORDANCE_MATRIX, STAGE_AFFORDANCES, stageAllowsAffordance, stageEventFields, } from './stages.js';
|
|
28
|
+
export type { ProfileTurnBehaviourSpec, ProfileTurnResumptionSpec, TurnContinueFrom, TurnStop, } from './stop.js';
|
|
29
|
+
export { AUTO_CONTINUE_DELAY_MS, CONTINUE_INSTRUCTION, DEFAULT_ALLOW_CONTINUE, DEFAULT_AUTO_CONTINUE, GenerationStopError, isContinueStopKind, isGenerationStopError, isResumeableStop, isUserCancelledStop, profileAllowsInject, profileAllowsSteering, profileTurnResumption, shouldAutoContinue, turnStopFromClientStreamEnd, turnStopFromInteractionStatus, turnStopFromOpenAiFinishReason, } from './stop.js';
|
|
30
|
+
export type { McpProtocolVersion, McpRpcResponse } from './tools/mod.js';
|
|
31
|
+
export { coerceToolResultParts, executeHttpTool, executeMcpTool, executeRegisteredTool, formatToolResult, getTool, hasTool, invokeTool, isUnsupportedMcpProtocolError, leanToolResultData, listBuiltinIds, listFunctionIds, listTools, MCP_PROTOCOL_VERSIONS, parseMcpRpcResponse, prepareTurnToolSnapshot, projectForModel, registerHarnessTools, registerTool, registerTools, requireTool, resetTools, resolveToolAuth, } from './tools/mod.js';
|
|
32
|
+
export type { ToolPause } from './tools/types.js';
|
|
22
33
|
export type * from './types.js';
|
package/esm/src/kernel/mod.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Profile, turn, tool, provider, egress, and event contracts for THEORUM.
|
|
3
3
|
*
|
|
4
|
-
* This entrypoint is type-first. Host applications import from here when they
|
|
5
|
-
* want to declare profiles, tool schemas, provider adapters, turn requests, or
|
|
6
|
-
* trace-safe event handlers without importing provider implementations.
|
|
7
|
-
*
|
|
8
4
|
* @module
|
|
9
5
|
*/
|
|
10
6
|
import "../../_dnt.polyfills.js";
|
|
7
|
+
export * from './auth/mod.js';
|
|
11
8
|
export { compactionMeter, compactionNeeded, estimateHistoryTokens, HISTORY_MEDIA_TOKENS, HISTORY_TEXT_ENCODING, resolveCompactionTokens, resolveHistoryTokens, shouldCompact, splitForCompaction, } from './engine/compaction.js';
|
|
9
|
+
export { assertLiveIngress, assertLiveIngressConfigured, hasAnyLiveIngress, liveIngressChannelDefault, liveIngressEnabled, liveIngressEnabledFromSpec, } from './engine/live-ingress.js';
|
|
12
10
|
export { runTurn } from './engine/runner.js';
|
|
13
|
-
export {
|
|
11
|
+
export { runSession } from './engine/session/mod.js';
|
|
12
|
+
export { isMediaRefPart, wireInteractionPart } from './interaction-parts.js';
|
|
13
|
+
export { PROFILE_GRAPH, profileGraphFacet, spineFacetsForProfileType, } from './profile-graph.js';
|
|
14
|
+
export { clampThinkingLevel, clampThinkingLevelForApiId, mediaChannelForMime, mediaKindForMime, mimeAllowed, mimeEssence, modelEntryByApiId, requireModelBinding, } from './registry/catalog.js';
|
|
14
15
|
export { clearProfiles, defineProfile, getProfile, hasProfile, listProfiles, registerProfile, registerProfiles, } from './registry/profiles.js';
|
|
15
|
-
export { projectProfile, resolveTurn } from './registry/resolve.js';
|
|
16
|
+
export { projectProfile, projectProfileObject, requireModelProfile, resolveTurn, } from './registry/resolve.js';
|
|
16
17
|
export { getStructured, registerStructured } from './registry/schemas.js';
|
|
17
|
-
export {
|
|
18
|
-
export {
|
|
18
|
+
export { ATTACHMENT_ACCEPT_MIMES, AUTH_UNAUTHENTICATED_POLICIES, AWAITING_USER_INPUT_KINDS, AWAITING_USER_INPUT_STATUS, CACHE_MODES, CACHE_TTLS, COMPACTION_METERS, COMPACTION_TIMINGS, CONTINUE_STOP_KINDS, catalogPathFor, coerceProtocol, coerceProvider, coerceSpeechFormat, EXTRA_FIELDS, fieldMeta, HTTP_METHODS, isSpeechFormatAllowedForProtocol, isToolGateKind, isTurnInjectStage, isTurnStage, isValidPair, isValidProfileProtocol, KEY_SLOTS, MEDIA_INPUT_KIND_VALUES, MEDIA_INPUT_KINDS, MEDIA_WILDCARDS, OVERFLOW_KEY_SLOTS, PLAYGROUND_AUTH_TYPES, PROFILE_FIELDS, PROFILE_TYPE_PROTOCOLS, PROFILE_TYPES, PROTOCOL_PROVIDERS, PROTOCOLS, PROVIDERS, protocolsFor, protocolsForProfileType, providersFor, SCHEMA_ENFORCEMENTS, SPEECH_AUDIO_FORMATS, STREAM_MODES, SUMMARY_MODES, speechFormatsForProtocol, THINKING_LEVELS, TOOL_ACCESS, TOOL_AUTH_TYPES, TOOL_GATE_KINDS, TOOL_LOAD_TIERS, TOOL_PERMISSION, TOOL_TYPES, TURN_INJECT_STAGES, TURN_STAGES, TURN_STOP_KINDS, VOICE_ACCEPT_MIMES, } from './schema.js';
|
|
19
|
+
export { applyStageResult, isAwaitingUserInput, parseAwaitingUserInput, parseToolGate, STAGE_AFFORDANCE_MATRIX, STAGE_AFFORDANCES, stageAllowsAffordance, stageEventFields, } from './stages.js';
|
|
20
|
+
export { AUTO_CONTINUE_DELAY_MS, CONTINUE_INSTRUCTION, DEFAULT_ALLOW_CONTINUE, DEFAULT_AUTO_CONTINUE, GenerationStopError, isContinueStopKind, isGenerationStopError, isResumeableStop, isUserCancelledStop, profileAllowsInject, profileAllowsSteering, profileTurnResumption, shouldAutoContinue, turnStopFromClientStreamEnd, turnStopFromInteractionStatus, turnStopFromOpenAiFinishReason, } from './stop.js';
|
|
21
|
+
export { coerceToolResultParts, executeHttpTool, executeMcpTool, executeRegisteredTool, formatToolResult, getTool, hasTool, invokeTool, isUnsupportedMcpProtocolError, leanToolResultData, listBuiltinIds, listFunctionIds, listTools, MCP_PROTOCOL_VERSIONS, parseMcpRpcResponse, prepareTurnToolSnapshot, projectForModel, registerHarnessTools, registerTool, registerTools, requireTool, resetTools, resolveToolAuth, } from './tools/mod.js';
|