theorum 0.1.14 → 1.0.0
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 +178 -89
- package/esm/mod.d.ts +21 -11
- package/esm/mod.js +15 -8
- package/esm/src/cli/commands/bench.js +6 -3
- package/esm/src/cli/commands/fuzz-canary.d.ts +13 -0
- package/esm/src/cli/commands/fuzz-canary.js +195 -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/profile.js +25 -14
- package/esm/src/cli/commands/run.d.ts +3 -0
- package/esm/src/cli/commands/run.js +22 -30
- package/esm/src/cli/commands/test.d.ts +10 -1
- package/esm/src/cli/commands/test.js +31 -31
- 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 +45 -11
- package/esm/src/cli/matrix/synthesizer.d.ts +7 -9
- package/esm/src/cli/matrix/synthesizer.js +32 -106
- package/esm/src/guardrails/canary-gate.d.ts +20 -0
- package/esm/src/guardrails/canary-gate.js +31 -0
- package/esm/src/guardrails/canary.d.ts +26 -0
- package/esm/src/guardrails/canary.js +139 -0
- package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +16 -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 +216 -0
- package/esm/src/guardrails/corpus/inbound-payloads.d.ts +10 -0
- package/esm/src/guardrails/corpus/inbound-payloads.js +124 -0
- package/esm/src/guardrails/corpus/live-attacks.d.ts +20 -0
- package/esm/src/guardrails/corpus/live-attacks.js +232 -0
- package/esm/src/guardrails/corpus/mod.d.ts +13 -0
- package/esm/src/guardrails/corpus/mod.js +11 -0
- package/esm/src/guardrails/corpus/secrets.d.ts +16 -0
- package/esm/src/guardrails/corpus/secrets.js +16 -0
- package/esm/src/guardrails/corpus/strings.d.ts +27 -0
- package/esm/src/guardrails/corpus/strings.js +33 -0
- package/esm/src/guardrails/corpus/types.d.ts +37 -0
- package/esm/src/guardrails/corpus/types.js +6 -0
- package/esm/src/guardrails/egress.d.ts +9 -0
- package/esm/src/guardrails/egress.js +36 -0
- package/esm/src/guardrails/error.js +6 -4
- package/esm/src/guardrails/injection.js +28 -5
- package/esm/src/guardrails/live-outbound-gate.d.ts +39 -0
- package/esm/src/guardrails/live-outbound-gate.js +180 -0
- package/esm/src/guardrails/mod.d.ts +13 -4
- package/esm/src/guardrails/mod.js +10 -4
- package/esm/src/guardrails/quota.js +1 -1
- package/esm/src/guardrails/sanitize.d.ts +11 -15
- package/esm/src/guardrails/sanitize.js +40 -49
- package/esm/src/guardrails/sensitive.js +2 -1
- package/esm/src/guardrails/testing.d.ts +10 -0
- package/esm/src/guardrails/testing.js +9 -0
- package/esm/src/host/client-turn.d.ts +19 -0
- package/esm/src/host/client-turn.js +32 -0
- package/esm/src/host/mod.d.ts +5 -3
- package/esm/src/host/mod.js +4 -3
- package/esm/src/interface/blocks.d.ts +20 -0
- package/esm/src/interface/blocks.js +180 -0
- package/esm/src/interface/from-profile.d.ts +14 -0
- package/esm/src/interface/from-profile.js +104 -0
- package/esm/src/interface/inputs.d.ts +8 -0
- package/esm/src/interface/inputs.js +127 -0
- package/esm/src/interface/mod.d.ts +10 -0
- package/esm/src/interface/mod.js +9 -0
- package/esm/src/interface/types.d.ts +153 -0
- package/esm/src/interface/types.js +13 -0
- package/esm/src/kernel/engine/delta.d.ts +24 -2
- package/esm/src/kernel/engine/delta.js +519 -29
- package/esm/src/kernel/engine/live-inbound.d.ts +9 -0
- package/esm/src/kernel/engine/live-inbound.js +17 -0
- package/esm/src/kernel/engine/repair.js +1 -1
- package/esm/src/kernel/engine/runner/gates.d.ts +1 -1
- package/esm/src/kernel/engine/runner/gates.js +7 -7
- package/esm/src/kernel/engine/runner/mod.js +13 -13
- package/esm/src/kernel/engine/runner/state.d.ts +7 -0
- package/esm/src/kernel/engine/runner/steps.d.ts +1 -1
- package/esm/src/kernel/engine/runner/steps.js +171 -37
- package/esm/src/kernel/engine/runner/stream.d.ts +1 -2
- package/esm/src/kernel/engine/runner/stream.js +66 -29
- package/esm/src/kernel/engine/session/mod.d.ts +23 -0
- package/esm/src/kernel/engine/session/mod.js +205 -0
- package/esm/src/kernel/mod.d.ts +9 -10
- package/esm/src/kernel/mod.js +6 -8
- package/esm/src/kernel/registry/attachments.d.ts +4 -2
- package/esm/src/kernel/registry/attachments.js +6 -3
- package/esm/src/kernel/registry/catalog.d.ts +3 -16
- package/esm/src/kernel/registry/catalog.js +5 -81
- package/esm/src/kernel/registry/ingress.d.ts +9 -4
- package/esm/src/kernel/registry/ingress.js +73 -63
- package/esm/src/kernel/registry/profiles.d.ts +35 -12
- package/esm/src/kernel/registry/profiles.js +159 -66
- package/esm/src/kernel/registry/provider-request.js +11 -7
- package/esm/src/kernel/registry/resolve.d.ts +5 -6
- package/esm/src/kernel/registry/resolve.js +100 -70
- package/esm/src/kernel/registry/vault.d.ts +12 -7
- package/esm/src/kernel/registry/vault.js +30 -8
- package/esm/src/kernel/schema.d.ts +145 -0
- package/esm/src/kernel/schema.js +462 -0
- package/esm/src/kernel/stop.d.ts +15 -10
- package/esm/src/kernel/stop.js +5 -5
- package/esm/src/kernel/tools/execute.d.ts +45 -0
- package/esm/src/kernel/tools/execute.js +363 -0
- package/esm/src/kernel/tools/harness.d.ts +8 -0
- package/esm/src/kernel/tools/harness.js +44 -0
- package/esm/src/kernel/tools/invoke.d.ts +10 -0
- package/esm/src/kernel/tools/invoke.js +83 -0
- package/esm/src/kernel/tools/mod.d.ts +11 -0
- package/esm/src/kernel/tools/mod.js +10 -0
- package/esm/src/kernel/tools/project.d.ts +12 -0
- package/esm/src/kernel/tools/project.js +34 -0
- package/esm/src/kernel/tools/registry.d.ts +23 -0
- package/esm/src/kernel/tools/registry.js +71 -0
- package/esm/src/kernel/tools/resolve.d.ts +29 -0
- package/esm/src/kernel/tools/resolve.js +262 -0
- package/esm/src/kernel/tools/schema.d.ts +13 -0
- package/esm/src/kernel/tools/schema.js +159 -0
- package/esm/src/kernel/tools/types.d.ts +216 -0
- package/esm/src/kernel/tools/types.js +9 -0
- package/esm/src/kernel/types.d.ts +338 -193
- package/esm/src/observability/trace-attach.d.ts +6 -4
- package/esm/src/observability/trace-attach.js +39 -25
- package/esm/src/observability/trace-record.d.ts +11 -9
- package/esm/src/observability/trace-record.js +36 -23
- 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 +9 -1
- package/esm/src/observability/trace.js +11 -3
- 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 +14 -14
- package/esm/src/providers/create-provider.js +55 -23
- package/esm/src/providers/google/interactions/framing.d.ts +15 -0
- package/esm/src/providers/google/interactions/framing.js +208 -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 +46 -0
- package/esm/src/providers/google/live/framing.js +515 -0
- package/esm/src/providers/google/live/openapi-schema.d.ts +6 -0
- package/esm/src/providers/google/live/openapi-schema.js +45 -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 +36 -0
- package/esm/src/providers/google/live/stream.js +201 -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/chat.d.ts +87 -0
- package/esm/src/providers/{openrouter.js → openrouter/chat.js} +70 -229
- package/esm/src/providers/openrouter/image.d.ts +34 -0
- package/esm/src/providers/openrouter/image.js +286 -0
- package/esm/src/providers/openrouter/openai/chat-payload.d.ts +24 -0
- package/esm/src/providers/openrouter/openai/chat-payload.js +60 -0
- package/esm/src/providers/openrouter/openai/compat.d.ts +47 -0
- package/esm/src/providers/openrouter/openai/compat.js +194 -0
- package/esm/src/providers/openrouter/openai/image-payload.d.ts +18 -0
- package/esm/src/providers/openrouter/openai/image-payload.js +84 -0
- package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +22 -0
- package/esm/src/providers/openrouter/openai/sdk-messages.js +95 -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 -201
- 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 -176
- 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
|
@@ -150,9 +150,9 @@ function gateStatusToAction(status, terminalStatus = 'terminal') {
|
|
|
150
150
|
return null;
|
|
151
151
|
}
|
|
152
152
|
async function* executeSingleAttemptCycle(args) {
|
|
153
|
-
const { flow, state, profile, system, provider,
|
|
154
|
-
const validation = profile.outputs
|
|
155
|
-
const egress = profile.guardrails
|
|
153
|
+
const { flow, state, profile, system, provider, upstream, maxRetries } = args;
|
|
154
|
+
const validation = profile.outputs?.validation;
|
|
155
|
+
const egress = profile.guardrails?.egress;
|
|
156
156
|
state.attemptEvents = [];
|
|
157
157
|
const { latestStructured } = yield* executeAttempt({
|
|
158
158
|
safe: flow.currentReq,
|
|
@@ -160,7 +160,7 @@ async function* executeSingleAttemptCycle(args) {
|
|
|
160
160
|
generation: flow.currentGen,
|
|
161
161
|
system,
|
|
162
162
|
provider,
|
|
163
|
-
|
|
163
|
+
upstream,
|
|
164
164
|
state,
|
|
165
165
|
});
|
|
166
166
|
if (egress?.enforce) {
|
|
@@ -183,8 +183,8 @@ async function* executeSingleAttemptCycle(args) {
|
|
|
183
183
|
}
|
|
184
184
|
return { status: 'success' };
|
|
185
185
|
}
|
|
186
|
-
async function* runAttemptsWithValidation(safe, profile, generation, system, provider,
|
|
187
|
-
const maxRetries = Math.max(profile.outputs
|
|
186
|
+
async function* runAttemptsWithValidation(safe, profile, generation, system, provider, upstream, state) {
|
|
187
|
+
const maxRetries = Math.max(profile.outputs?.validation?.maxRetries ?? 0, profile.guardrails?.egress?.maxRetries ?? 0);
|
|
188
188
|
const flow = {
|
|
189
189
|
currentAttempt: 0,
|
|
190
190
|
currentGen: generation,
|
|
@@ -198,7 +198,7 @@ async function* runAttemptsWithValidation(safe, profile, generation, system, pro
|
|
|
198
198
|
profile,
|
|
199
199
|
system,
|
|
200
200
|
provider,
|
|
201
|
-
|
|
201
|
+
upstream,
|
|
202
202
|
maxRetries,
|
|
203
203
|
});
|
|
204
204
|
if (step.status === 'terminal' || step.status === 'success') {
|
|
@@ -7,18 +7,18 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
|
+
import { bindCanary } from '../../../guardrails/canary.js';
|
|
10
11
|
import { throwIfAborted } from '../../../guardrails/error.js';
|
|
11
12
|
import { sanitizeTurnRequest } from '../../../guardrails/sanitize.js';
|
|
12
13
|
import { noopSink, writeTrace } from '../../../observability/trace.js';
|
|
13
14
|
import { buildRecord } from '../../../observability/trace-record.js';
|
|
14
15
|
import { pickSystemRole, resolveTurn } from '../../registry/resolve.js';
|
|
15
16
|
import { CONTINUE_INSTRUCTION } from '../../stop.js';
|
|
16
|
-
import {
|
|
17
|
+
import { expandT1Policy } from '../../tools/resolve.js';
|
|
17
18
|
import { resolveCompactionTokens, shouldCompact, splitForCompaction } from '../compaction.js';
|
|
18
19
|
import { runAttemptsWithValidation } from './gates.js';
|
|
19
20
|
import { shouldSkipStreamEvent, systemFromProfile } from './stream.js';
|
|
20
21
|
import { calculateFallbackTokens } from './tokens.js';
|
|
21
|
-
import { invokeFromUi } from './tools.js';
|
|
22
22
|
function getCompactionSpec(profile, modelId) {
|
|
23
23
|
return profile.model.config[modelId]?.compaction;
|
|
24
24
|
}
|
|
@@ -94,11 +94,7 @@ async function attachAfterCompaction(event, args) {
|
|
|
94
94
|
return { ...event, compaction: signal };
|
|
95
95
|
}
|
|
96
96
|
async function* emitTurn(args) {
|
|
97
|
-
const { safe, profile, generation, system, provider,
|
|
98
|
-
if (safe.toolInvoke) {
|
|
99
|
-
yield* invokeFromUi(profile, safe);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
97
|
+
const { safe, profile, generation, system, provider, upstream } = args;
|
|
102
98
|
const state = {
|
|
103
99
|
currentHistory: [...(generation.history ?? [])],
|
|
104
100
|
stepCount: 0,
|
|
@@ -106,7 +102,7 @@ async function* emitTurn(args) {
|
|
|
106
102
|
allEmittedEvents: [],
|
|
107
103
|
attemptEvents: [],
|
|
108
104
|
};
|
|
109
|
-
yield* runAttemptsWithValidation(safe, profile, generation, system, provider,
|
|
105
|
+
yield* runAttemptsWithValidation(safe, profile, generation, system, provider, upstream, state);
|
|
110
106
|
if (!state.sawTokensEvent) {
|
|
111
107
|
yield* calculateFallbackTokens(safe, system, state.allEmittedEvents);
|
|
112
108
|
}
|
|
@@ -121,12 +117,13 @@ async function flushTurnTrace(sink, ctx) {
|
|
|
121
117
|
events: ctx.seen,
|
|
122
118
|
started: ctx.started,
|
|
123
119
|
model: ctx.model,
|
|
124
|
-
|
|
120
|
+
keySlot: ctx.keySlot,
|
|
125
121
|
thrown: ctx.thrown,
|
|
126
|
-
|
|
122
|
+
upstreamLog: ctx.upstream,
|
|
127
123
|
canary: ctx.canary,
|
|
128
124
|
system: ctx.system,
|
|
129
125
|
generation: ctx.generation,
|
|
126
|
+
protocol: ctx.protocol,
|
|
130
127
|
sanitizedReq: ctx.safe,
|
|
131
128
|
}));
|
|
132
129
|
}
|
|
@@ -137,7 +134,7 @@ async function* runTurn(req, provider, sink = noopSink()) {
|
|
|
137
134
|
seen: [],
|
|
138
135
|
started: Date.now(),
|
|
139
136
|
canary: '',
|
|
140
|
-
|
|
137
|
+
upstream: [],
|
|
141
138
|
};
|
|
142
139
|
try {
|
|
143
140
|
yield* runTurnBody(ctx, provider);
|
|
@@ -152,10 +149,13 @@ async function* runTurnBody(ctx, provider) {
|
|
|
152
149
|
ctx.safe = sanitizeTurnRequest(ctx.req);
|
|
153
150
|
throwIfAborted(ctx.safe.signal);
|
|
154
151
|
const { profile, generation: gen } = resolveTurn(ctx.safe);
|
|
152
|
+
await expandT1Policy(gen.tools, profile, ctx.safe);
|
|
153
|
+
gen.builtins = gen.tools.builtins;
|
|
155
154
|
ctx.generation = gen;
|
|
156
155
|
ctx.model = gen.model;
|
|
157
|
-
ctx.
|
|
156
|
+
ctx.keySlot = gen.keySlot;
|
|
158
157
|
ctx.canary = gen.canary;
|
|
158
|
+
ctx.protocol = profile.model.protocol;
|
|
159
159
|
const isCompacting = ctx.req.metadata?._compacting === true;
|
|
160
160
|
const compactionSpec = isCompacting ? undefined : getCompactionSpec(profile, gen.model);
|
|
161
161
|
await maybeCompactBefore(ctx, gen, compactionSpec, provider);
|
|
@@ -188,7 +188,7 @@ async function* streamTurnEvents(ctx, profile, gen, provider, compactionSpec, is
|
|
|
188
188
|
generation: gen,
|
|
189
189
|
system: ctx.system,
|
|
190
190
|
provider,
|
|
191
|
-
|
|
191
|
+
upstream: ctx.upstream,
|
|
192
192
|
})) {
|
|
193
193
|
const out = await maybeAttachAfter(event, ctx, gen, compactionSpec, isCompacting);
|
|
194
194
|
ctx.seen.push(out);
|
|
@@ -7,6 +7,13 @@ interface StepExecutionState {
|
|
|
7
7
|
attemptEvents: TurnEvent[];
|
|
8
8
|
/** Last provider stop from a discarded provider `done` event. */
|
|
9
9
|
lastStop?: TurnStop;
|
|
10
|
+
/** Latest Google Interactions id observed on the current provider stream. */
|
|
11
|
+
lastInteractionId?: string;
|
|
12
|
+
/** Pending Interactions `function_result` continuation for the next provider step. */
|
|
13
|
+
interactionsContinuation?: {
|
|
14
|
+
previousInteractionId: string;
|
|
15
|
+
input: Record<string, unknown>[];
|
|
16
|
+
};
|
|
10
17
|
}
|
|
11
18
|
interface AttemptFlowState {
|
|
12
19
|
currentAttempt: number;
|
|
@@ -6,7 +6,7 @@ declare function executeAttempt(args: {
|
|
|
6
6
|
generation: ResolvedGeneration;
|
|
7
7
|
system: string;
|
|
8
8
|
provider: ModelProvider;
|
|
9
|
-
|
|
9
|
+
upstream: Record<string, unknown>[];
|
|
10
10
|
state: StepExecutionState;
|
|
11
11
|
}): AsyncGenerator<TurnEvent, {
|
|
12
12
|
pendingTools: TurnEvent[];
|
|
@@ -1,29 +1,48 @@
|
|
|
1
1
|
import { throwIfAborted } from '../../../guardrails/error.js';
|
|
2
|
+
import { executeRegisteredTool, formatToolFailureForModel, formatToolResult, newCallId, } from '../../tools/execute.js';
|
|
2
3
|
import { recordStepEvent } from './state.js';
|
|
3
4
|
import { yieldProviderEvents } from './stream.js';
|
|
4
|
-
import { executeDynamicDeclaration, findDynamicDeclaration, formatToolFinding, isActionableDynamicDeclaration, } from './tools.js';
|
|
5
5
|
function isStepLimitReached(step, maxSteps) {
|
|
6
|
-
if (maxSteps <= 0) {
|
|
6
|
+
if (maxSteps === undefined || maxSteps <= 0) {
|
|
7
7
|
return false;
|
|
8
8
|
}
|
|
9
9
|
return step >= maxSteps;
|
|
10
10
|
}
|
|
11
|
+
function generationForProviderStep(generation, state) {
|
|
12
|
+
if (state.interactionsContinuation) {
|
|
13
|
+
const { previousInteractionId, input } = state.interactionsContinuation;
|
|
14
|
+
state.interactionsContinuation = undefined;
|
|
15
|
+
return {
|
|
16
|
+
...generation,
|
|
17
|
+
history: [],
|
|
18
|
+
input: [],
|
|
19
|
+
previousInteractionId,
|
|
20
|
+
interactionOnlyInput: input,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return { ...generation, history: state.currentHistory };
|
|
24
|
+
}
|
|
25
|
+
function captureInteractionId(event, state) {
|
|
26
|
+
if (event.interactionId) {
|
|
27
|
+
state.lastInteractionId = event.interactionId;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
11
30
|
async function* executeAutonomousStep(args, state, buffer = {
|
|
12
31
|
holdLate: false,
|
|
13
32
|
holdUserVisible: false,
|
|
14
33
|
}) {
|
|
15
|
-
const {
|
|
16
|
-
const genForStep =
|
|
34
|
+
const { generation, system, provider, upstream, signal } = args;
|
|
35
|
+
const genForStep = generationForProviderStep(generation, state);
|
|
17
36
|
const pendingTools = [];
|
|
18
37
|
let latestStructured;
|
|
19
38
|
for await (const event of yieldProviderEvents({
|
|
20
|
-
profile,
|
|
21
39
|
generation: genForStep,
|
|
22
40
|
system,
|
|
23
41
|
provider,
|
|
24
|
-
|
|
42
|
+
upstream,
|
|
25
43
|
signal,
|
|
26
44
|
})) {
|
|
45
|
+
captureInteractionId(event, state);
|
|
27
46
|
if (event.type === 'structured') {
|
|
28
47
|
latestStructured = event.structured;
|
|
29
48
|
}
|
|
@@ -39,8 +58,6 @@ async function* executeAutonomousStep(args, state, buffer = {
|
|
|
39
58
|
}
|
|
40
59
|
recordStepEvent(event, state);
|
|
41
60
|
const isUserVisible = event.type === 'thought' || event.type === 'text';
|
|
42
|
-
// Egress must not stream user-visible text before the gate runs.
|
|
43
|
-
// Validation-only may stream thought/text live and only hold structured.
|
|
44
61
|
const streamNow = !buffer.holdLate || event.type === 'tokens' || (isUserVisible && !buffer.holdUserVisible);
|
|
45
62
|
if (streamNow) {
|
|
46
63
|
yield event;
|
|
@@ -48,12 +65,24 @@ async function* executeAutonomousStep(args, state, buffer = {
|
|
|
48
65
|
}
|
|
49
66
|
return { pendingTools, latestStructured };
|
|
50
67
|
}
|
|
51
|
-
function
|
|
68
|
+
function appendInteractionsToolResultToHistory(history, toolEv, result) {
|
|
52
69
|
const tool = toolEv.tool;
|
|
53
70
|
if (!tool) {
|
|
54
71
|
return;
|
|
55
72
|
}
|
|
56
|
-
|
|
73
|
+
history.push({
|
|
74
|
+
role: 'tool',
|
|
75
|
+
tool_call_id: tool.id ?? tool.callId ?? `call_${tool.name}`,
|
|
76
|
+
name: tool.name,
|
|
77
|
+
content: formatToolResult(result),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function appendToolTurnToHistory(history, toolEv, result) {
|
|
81
|
+
const tool = toolEv.tool;
|
|
82
|
+
if (!tool) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const callId = tool.id ?? tool.callId ?? newCallId(tool.name);
|
|
57
86
|
history.push({
|
|
58
87
|
role: 'assistant',
|
|
59
88
|
tool_calls: [
|
|
@@ -71,51 +100,156 @@ function appendToolTurnToHistory(history, toolEv, res) {
|
|
|
71
100
|
role: 'tool',
|
|
72
101
|
tool_call_id: callId,
|
|
73
102
|
name: tool.name,
|
|
74
|
-
content:
|
|
103
|
+
content: formatToolResult(result),
|
|
75
104
|
});
|
|
76
105
|
}
|
|
77
|
-
|
|
78
|
-
|
|
106
|
+
function queueInteractionsToolContinuation(state, toolEv, result, fallbackInteractionId) {
|
|
107
|
+
const tool = toolEv.tool;
|
|
108
|
+
if (!tool) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const previousInteractionId = state.lastInteractionId ?? fallbackInteractionId;
|
|
112
|
+
if (!previousInteractionId) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const step = {
|
|
116
|
+
type: 'function_result',
|
|
117
|
+
name: tool.name,
|
|
118
|
+
call_id: tool.id ?? tool.callId ?? `call_${tool.name}`,
|
|
119
|
+
result: [{ type: 'text', text: formatToolResult(result) }],
|
|
120
|
+
};
|
|
121
|
+
if (state.interactionsContinuation &&
|
|
122
|
+
state.interactionsContinuation.previousInteractionId === previousInteractionId) {
|
|
123
|
+
state.interactionsContinuation.input.push(step);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
state.interactionsContinuation = {
|
|
127
|
+
previousInteractionId,
|
|
128
|
+
input: [step],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function recordToolModelResult(state, toolEv, modelResult, generation, useInteractionsContinuation) {
|
|
132
|
+
if (useInteractionsContinuation) {
|
|
133
|
+
queueInteractionsToolContinuation(state, toolEv, modelResult, generation.previousInteractionId);
|
|
134
|
+
if (!state.interactionsContinuation) {
|
|
135
|
+
appendInteractionsToolResultToHistory(state.currentHistory, toolEv, modelResult);
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
appendToolTurnToHistory(state.currentHistory, toolEv, modelResult);
|
|
140
|
+
}
|
|
141
|
+
function enrichToolEvent(tool, callId, patch) {
|
|
142
|
+
return {
|
|
143
|
+
type: 'tool',
|
|
144
|
+
tool: {
|
|
145
|
+
...tool,
|
|
146
|
+
...patch,
|
|
147
|
+
callId,
|
|
148
|
+
id: tool.id ?? callId,
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
async function* handlePendingTools(pendingTools, generation, profile, state) {
|
|
153
|
+
let executed = false;
|
|
154
|
+
let sawPause = false;
|
|
155
|
+
const useInteractionsContinuation = generation.transport === 'interactions';
|
|
79
156
|
for (const toolEv of pendingTools) {
|
|
80
157
|
const tool = toolEv.tool;
|
|
81
158
|
if (!tool) {
|
|
82
159
|
continue;
|
|
83
160
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
161
|
+
executed = true;
|
|
162
|
+
const callId = tool.id ?? tool.callId ?? newCallId(tool.name || 'unknown');
|
|
163
|
+
// Provider cancelled an in-flight call (e.g. live barge-in). Do not execute.
|
|
164
|
+
if (tool.phase === 'cancel') {
|
|
165
|
+
const enriched = enrichToolEvent(tool, callId);
|
|
166
|
+
state.allEmittedEvents.push(enriched);
|
|
167
|
+
yield enriched;
|
|
88
168
|
continue;
|
|
89
169
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
170
|
+
// Provider already failed this call (e.g. malformed arguments JSON).
|
|
171
|
+
if (tool.phase === 'error' && tool.failure) {
|
|
172
|
+
const enriched = enrichToolEvent(tool, callId);
|
|
173
|
+
state.allEmittedEvents.push(enriched);
|
|
174
|
+
yield enriched;
|
|
175
|
+
recordToolModelResult(state, toolEv, formatToolFailureForModel(tool.failure), generation, useInteractionsContinuation);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
// Empty name is a protocol defect — never route through the registry as unknown_tool.
|
|
179
|
+
if (!tool.name) {
|
|
180
|
+
const failure = {
|
|
181
|
+
code: 'malformed_arguments',
|
|
182
|
+
message: 'Provider tool call is missing a function name',
|
|
183
|
+
};
|
|
184
|
+
const enriched = enrichToolEvent(tool, callId, {
|
|
185
|
+
phase: 'error',
|
|
186
|
+
failure,
|
|
187
|
+
name: '',
|
|
188
|
+
});
|
|
189
|
+
state.allEmittedEvents.push(enriched);
|
|
190
|
+
yield enriched;
|
|
191
|
+
recordToolModelResult(state, toolEv, formatToolFailureForModel(failure), generation, useInteractionsContinuation);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
let modelResult;
|
|
195
|
+
let paused = false;
|
|
196
|
+
const exec = executeRegisteredTool({
|
|
94
197
|
profile,
|
|
95
|
-
|
|
198
|
+
name: tool.name,
|
|
199
|
+
input: tool.arguments ?? {},
|
|
200
|
+
callId,
|
|
201
|
+
ctx: {
|
|
202
|
+
sessionPermissions: generation.sessionPermissions,
|
|
203
|
+
path: generation.tools.path,
|
|
204
|
+
turn: { step: state.stepCount },
|
|
205
|
+
},
|
|
206
|
+
snapshot: generation.tools,
|
|
96
207
|
});
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
208
|
+
let next = await exec.next();
|
|
209
|
+
while (!next.done) {
|
|
210
|
+
const event = next.value;
|
|
211
|
+
const enriched = enrichToolEvent(tool, callId, event.tool);
|
|
212
|
+
state.allEmittedEvents.push(enriched);
|
|
213
|
+
yield enriched;
|
|
214
|
+
if (event.tool?.phase === 'error' && event.tool.failure) {
|
|
215
|
+
modelResult = formatToolFailureForModel(event.tool.failure);
|
|
216
|
+
}
|
|
217
|
+
if (event.tool?.phase === 'pause') {
|
|
218
|
+
modelResult = undefined;
|
|
219
|
+
paused = true;
|
|
220
|
+
}
|
|
221
|
+
next = await exec.next();
|
|
222
|
+
}
|
|
223
|
+
if (next.value !== undefined) {
|
|
224
|
+
modelResult = next.value;
|
|
225
|
+
}
|
|
226
|
+
if (paused) {
|
|
227
|
+
sawPause = true;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (!modelResult) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
recordToolModelResult(state, toolEv, modelResult, generation, useInteractionsContinuation);
|
|
234
|
+
}
|
|
235
|
+
if (sawPause) {
|
|
236
|
+
state.lastStop = { kind: 'tool' };
|
|
237
|
+
return false;
|
|
104
238
|
}
|
|
105
|
-
return
|
|
239
|
+
return executed;
|
|
106
240
|
}
|
|
107
241
|
async function* executeAttempt(args) {
|
|
108
|
-
const { profile, generation, system, provider,
|
|
242
|
+
const { profile, generation, system, provider, upstream, state } = args;
|
|
109
243
|
let latestStructured;
|
|
110
244
|
let pendingTools = [];
|
|
111
245
|
let stepInAttempt = 0;
|
|
112
|
-
const holdUserVisible = Boolean(profile.guardrails
|
|
113
|
-
const holdLate = Boolean(profile.outputs
|
|
114
|
-
while (!isStepLimitReached(stepInAttempt, generation.maxSteps)) {
|
|
246
|
+
const holdUserVisible = Boolean(profile.guardrails?.egress?.enforce);
|
|
247
|
+
const holdLate = Boolean(profile.outputs?.validation) || holdUserVisible;
|
|
248
|
+
while (!isStepLimitReached(stepInAttempt, generation.maxSteps ?? 0)) {
|
|
115
249
|
throwIfAborted(args.safe.signal);
|
|
116
250
|
stepInAttempt++;
|
|
117
251
|
state.stepCount++;
|
|
118
|
-
const stepResult = yield* executeAutonomousStep({ profile, generation, system, provider,
|
|
252
|
+
const stepResult = yield* executeAutonomousStep({ profile, generation, system, provider, upstream, signal: args.safe.signal }, state, { holdLate, holdUserVisible });
|
|
119
253
|
if (stepResult.latestStructured !== undefined) {
|
|
120
254
|
latestStructured = stepResult.latestStructured;
|
|
121
255
|
}
|
|
@@ -123,8 +257,8 @@ async function* executeAttempt(args) {
|
|
|
123
257
|
if (pendingTools.length === 0) {
|
|
124
258
|
break;
|
|
125
259
|
}
|
|
126
|
-
const
|
|
127
|
-
if (!
|
|
260
|
+
const executed = yield* handlePendingTools(pendingTools, generation, profile, state);
|
|
261
|
+
if (!executed) {
|
|
128
262
|
break;
|
|
129
263
|
}
|
|
130
264
|
}
|
|
@@ -2,11 +2,10 @@ import type { ModelProvider, Profile, ResolvedGeneration, TurnEvent } from '../.
|
|
|
2
2
|
declare function systemFromProfile(profile: Profile, role: string): string;
|
|
3
3
|
declare function shouldSkipStreamEvent(event: TurnEvent, profile: Profile): boolean;
|
|
4
4
|
declare function yieldProviderEvents(args: {
|
|
5
|
-
profile: Profile;
|
|
6
5
|
generation: ResolvedGeneration;
|
|
7
6
|
system: string;
|
|
8
7
|
provider: ModelProvider;
|
|
9
|
-
|
|
8
|
+
upstream: Record<string, unknown>[];
|
|
10
9
|
signal?: AbortSignal;
|
|
11
10
|
}): AsyncGenerator<TurnEvent>;
|
|
12
11
|
export { shouldSkipStreamEvent, systemFromProfile, yieldProviderEvents };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
import { createCanaryStreamGate, eventHasCanary, isStreamedCanaryEvent, redactCanary, } from '../../../guardrails/canary.js';
|
|
1
2
|
import { publicError, throwIfAborted, toErrorEvent } from '../../../guardrails/error.js';
|
|
2
3
|
import { providerCompleteRequest } from '../../registry/provider-request.js';
|
|
3
|
-
import { eventHasCanary, redactCanary } from '../boundary.js';
|
|
4
|
-
import { dispatchModelTool } from './tools.js';
|
|
5
4
|
function systemFromProfile(profile, role) {
|
|
6
5
|
const { identity } = profile;
|
|
7
6
|
const { systemByRole, system } = identity;
|
|
@@ -16,29 +15,11 @@ function systemFromProfile(profile, role) {
|
|
|
16
15
|
}
|
|
17
16
|
return '';
|
|
18
17
|
}
|
|
19
|
-
function* interceptProviderTool(event, profile, generation) {
|
|
20
|
-
const tool = event.tool;
|
|
21
|
-
if (!tool) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
const isDynamic = generation.dynamicTools?.some((d) => d.name === tool.name);
|
|
25
|
-
if (isDynamic) {
|
|
26
|
-
yield event;
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
for (const item of dispatchModelTool(profile, event, generation.custom)) {
|
|
30
|
-
yield item;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
18
|
function shouldSkipStreamEvent(event, profile) {
|
|
35
|
-
return event.type === 'thought' && profile.outputs
|
|
19
|
+
return event.type === 'thought' && profile.outputs?.streaming?.streamThoughts === false;
|
|
36
20
|
}
|
|
37
|
-
function* processNormalEvent(event
|
|
38
|
-
if (event.type === '
|
|
39
|
-
yield* interceptProviderTool(event, profile, generation);
|
|
40
|
-
}
|
|
41
|
-
else if (event.type === 'error') {
|
|
21
|
+
function* processNormalEvent(event) {
|
|
22
|
+
if (event.type === 'error') {
|
|
42
23
|
const internal = event.errorInternal ?? event.error ?? '';
|
|
43
24
|
yield {
|
|
44
25
|
type: 'error',
|
|
@@ -50,24 +31,80 @@ function* processNormalEvent(event, profile, generation) {
|
|
|
50
31
|
yield event;
|
|
51
32
|
}
|
|
52
33
|
}
|
|
34
|
+
function* yieldCanaryLeak(canary, event) {
|
|
35
|
+
yield redactCanary(event, canary);
|
|
36
|
+
yield toErrorEvent('canary leaked');
|
|
37
|
+
}
|
|
38
|
+
function* yieldGatedStreamEvent(event, gate, canary) {
|
|
39
|
+
const fragment = event.text ?? '';
|
|
40
|
+
const result = gate.process(fragment);
|
|
41
|
+
if (result.leak) {
|
|
42
|
+
yield* yieldCanaryLeak(canary, event);
|
|
43
|
+
return 'stop';
|
|
44
|
+
}
|
|
45
|
+
if (result.emit) {
|
|
46
|
+
yield* processNormalEvent({ ...event, text: result.emit });
|
|
47
|
+
}
|
|
48
|
+
return 'continue';
|
|
49
|
+
}
|
|
50
|
+
function* flushCanaryGate(gate, _canary, lastType) {
|
|
51
|
+
const result = gate.flush();
|
|
52
|
+
if (result.leak) {
|
|
53
|
+
yield toErrorEvent('canary leaked');
|
|
54
|
+
return 'stop';
|
|
55
|
+
}
|
|
56
|
+
if (result.emit) {
|
|
57
|
+
const emitType = lastType ?? 'text';
|
|
58
|
+
yield* processNormalEvent({ type: emitType, text: result.emit });
|
|
59
|
+
}
|
|
60
|
+
return 'pass';
|
|
61
|
+
}
|
|
53
62
|
async function* yieldProviderEvents(args) {
|
|
54
|
-
const {
|
|
63
|
+
const { generation, system, provider, upstream, signal } = args;
|
|
55
64
|
const { canary } = generation;
|
|
65
|
+
const gate = canary ? createCanaryStreamGate(canary) : null;
|
|
66
|
+
let lastStreamType;
|
|
56
67
|
throwIfAborted(signal);
|
|
57
68
|
for await (const event of provider.complete({
|
|
58
69
|
...providerCompleteRequest(generation, system),
|
|
59
70
|
signal,
|
|
60
|
-
|
|
61
|
-
|
|
71
|
+
tapUpstream: (row) => {
|
|
72
|
+
upstream.push(row);
|
|
62
73
|
},
|
|
63
74
|
})) {
|
|
64
75
|
throwIfAborted(signal);
|
|
76
|
+
if (gate && isStreamedCanaryEvent(event)) {
|
|
77
|
+
if (lastStreamType && lastStreamType !== event.type) {
|
|
78
|
+
const status = yield* flushCanaryGate(gate, canary, lastStreamType);
|
|
79
|
+
if (status === 'stop') {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
lastStreamType = event.type;
|
|
84
|
+
const status = yield* yieldGatedStreamEvent(event, gate, canary);
|
|
85
|
+
if (status === 'stop') {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (gate && lastStreamType) {
|
|
91
|
+
const status = yield* flushCanaryGate(gate, canary, lastStreamType);
|
|
92
|
+
if (status === 'stop') {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
lastStreamType = undefined;
|
|
96
|
+
}
|
|
65
97
|
if (canary && eventHasCanary(event, canary)) {
|
|
66
|
-
yield
|
|
67
|
-
|
|
98
|
+
yield* yieldCanaryLeak(canary, event);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
yield* processNormalEvent(event);
|
|
102
|
+
}
|
|
103
|
+
if (gate) {
|
|
104
|
+
const status = yield* flushCanaryGate(gate, canary, lastStreamType);
|
|
105
|
+
if (status === 'stop') {
|
|
68
106
|
return;
|
|
69
107
|
}
|
|
70
|
-
yield* processNormalEvent(event, profile, generation);
|
|
71
108
|
}
|
|
72
109
|
}
|
|
73
110
|
export { shouldSkipStreamEvent, systemFromProfile, yieldProviderEvents };
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import type { GeminiTransport } from '../../../providers/google/keys.js';
|
|
10
|
+
import type { LiveSession, SessionRequest } from '../../types.js';
|
|
11
|
+
export type { LiveSession, SessionRequest };
|
|
12
|
+
export interface RunSessionOptions {
|
|
13
|
+
gemini: GeminiTransport;
|
|
14
|
+
/** Override socket open (Cloudflare fetch-upgrade, tests). Default: `new WebSocket(url)`. */
|
|
15
|
+
openWebSocket?: (url: string) => Promise<WebSocket>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Open a gated Gemini Live session for a `type: 'live'` profile.
|
|
19
|
+
*
|
|
20
|
+
* Hosts bridge browser sockets and tool dispatch; THEORUM owns Gemini WS,
|
|
21
|
+
* framing, inbound prep, and outbound canary/egress gates.
|
|
22
|
+
*/
|
|
23
|
+
export declare function runSession(req: SessionRequest, options: RunSessionOptions): Promise<LiveSession>;
|