theorum 1.0.0 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -25
- package/esm/mod.d.ts +48 -29
- package/esm/mod.js +37 -24
- package/esm/src/cli/commands/bench.js +13 -16
- package/esm/src/cli/commands/fuzz-canary.js +25 -29
- 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 +12 -3
- package/esm/src/cli/commands/run.js +8 -9
- package/esm/src/cli/commands/test.js +8 -8
- package/esm/src/cli/event-log.d.ts +1 -1
- package/esm/src/cli/index.js +12 -0
- package/esm/src/cli/matrix/synthesizer.d.ts +6 -6
- package/esm/src/cli/matrix/synthesizer.js +23 -22
- package/esm/src/guardrails/canary-gate.d.ts +2 -1
- package/esm/src/guardrails/canary-gate.js +2 -1
- package/esm/src/guardrails/canary.d.ts +9 -1
- package/esm/src/guardrails/canary.js +21 -10
- package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +1 -0
- package/esm/src/guardrails/corpus/fuzz-inbound.js +12 -15
- package/esm/src/guardrails/corpus/inbound-payloads.js +1 -0
- package/esm/src/guardrails/corpus/live-attacks.js +0 -1
- package/esm/src/guardrails/corpus/mod.d.ts +1 -0
- package/esm/src/guardrails/corpus/secrets.d.ts +1 -0
- package/esm/src/guardrails/corpus/secrets.js +1 -0
- package/esm/src/guardrails/corpus/strings.d.ts +1 -0
- package/esm/src/guardrails/corpus/strings.js +1 -0
- package/esm/src/guardrails/corpus/types.d.ts +1 -0
- package/esm/src/guardrails/egress.d.ts +26 -3
- package/esm/src/guardrails/egress.js +69 -18
- package/esm/src/guardrails/error.d.ts +14 -23
- package/esm/src/guardrails/error.js +86 -77
- 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/lexicon.d.ts +39 -0
- package/esm/src/guardrails/lexicon.js +200 -0
- package/esm/src/guardrails/live-outbound-gate.d.ts +15 -13
- package/esm/src/guardrails/live-outbound-gate.js +131 -89
- package/esm/src/guardrails/mod.d.ts +19 -4
- package/esm/src/guardrails/mod.js +12 -3
- 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 +36 -6
- package/esm/src/guardrails/sanitize.js +152 -60
- package/esm/src/guardrails/serialize.d.ts +35 -0
- package/esm/src/guardrails/serialize.js +58 -0
- package/esm/src/guardrails/testing.d.ts +7 -0
- package/esm/src/guardrails/testing.js +4 -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.js +4 -0
- package/esm/src/host/mint-trace.d.ts +1 -1
- 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.js +43 -2
- package/esm/src/kernel/engine/live-inbound.d.ts +15 -3
- package/esm/src/kernel/engine/live-inbound.js +22 -8
- 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.js +127 -40
- package/esm/src/kernel/engine/runner/mod.d.ts +6 -4
- package/esm/src/kernel/engine/runner/mod.js +182 -43
- 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 +24 -0
- package/esm/src/kernel/engine/runner/steps.js +128 -61
- package/esm/src/kernel/engine/runner/stream.d.ts +9 -2
- package/esm/src/kernel/engine/runner/stream.js +114 -55
- package/esm/src/kernel/engine/session/mod.d.ts +3 -1
- package/esm/src/kernel/engine/session/mod.js +386 -34
- 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 +19 -7
- package/esm/src/kernel/mod.js +10 -5
- 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 +10 -10
- package/esm/src/kernel/registry/attachments.js +29 -26
- package/esm/src/kernel/registry/catalog.d.ts +25 -11
- package/esm/src/kernel/registry/catalog.js +59 -24
- package/esm/src/kernel/registry/ingress.js +34 -22
- 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 +34 -14
- package/esm/src/kernel/registry/profiles.js +306 -59
- package/esm/src/kernel/registry/provider-request.js +2 -0
- package/esm/src/kernel/registry/resolve.d.ts +7 -6
- package/esm/src/kernel/registry/resolve.js +102 -117
- 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 +2 -2
- package/esm/src/kernel/registry/vault.js +4 -4
- package/esm/src/kernel/schema.d.ts +97 -11
- package/esm/src/kernel/schema.js +256 -111
- package/esm/src/kernel/stages.d.ts +175 -0
- package/esm/src/kernel/stages.js +476 -0
- package/esm/src/kernel/stop.d.ts +65 -11
- package/esm/src/kernel/stop.js +46 -11
- 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 +63 -24
- package/esm/src/kernel/tools/execute.js +475 -224
- package/esm/src/kernel/tools/harness.js +16 -14
- package/esm/src/kernel/tools/invoke.js +26 -8
- package/esm/src/kernel/tools/mod.d.ts +3 -1
- package/esm/src/kernel/tools/mod.js +2 -1
- 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.js +5 -3
- package/esm/src/kernel/tools/registry.js +20 -10
- 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 +17 -7
- package/esm/src/kernel/tools/resolve.js +38 -17
- package/esm/src/kernel/tools/schema.d.ts +2 -0
- package/esm/src/kernel/tools/schema.js +23 -6
- 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 +198 -20
- package/esm/src/kernel/types.d.ts +253 -114
- 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 +3 -1
- package/esm/src/observability/trace-attach.js +17 -10
- package/esm/src/observability/trace-record.d.ts +12 -4
- package/esm/src/observability/trace-record.js +63 -19
- package/esm/src/observability/trace-sink.d.ts +19 -0
- package/esm/src/observability/trace-sink.js +10 -0
- package/esm/src/observability/trace.d.ts +14 -11
- package/esm/src/observability/trace.js +23 -14
- package/esm/src/observability/types.d.ts +113 -0
- package/esm/src/observability/types.js +11 -0
- package/esm/src/providers/create-provider.d.ts +7 -4
- package/esm/src/providers/create-provider.js +21 -7
- package/esm/src/providers/google/interactions/framing.d.ts +8 -0
- package/esm/src/providers/google/interactions/framing.js +74 -13
- package/esm/src/providers/google/live/framing.d.ts +5 -2
- package/esm/src/providers/google/live/framing.js +49 -12
- package/esm/src/providers/google/live/openapi-schema.js +3 -2
- package/esm/src/providers/google/live/stream.d.ts +9 -0
- package/esm/src/providers/google/live/stream.js +16 -3
- 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 +21 -1
- package/esm/src/providers/openrouter/chat.js +51 -6
- package/esm/src/providers/openrouter/image.js +8 -19
- package/esm/src/providers/openrouter/openai/chat-payload.js +23 -1
- package/esm/src/providers/openrouter/openai/compat.d.ts +7 -1
- package/esm/src/providers/openrouter/openai/compat.js +23 -4
- package/esm/src/providers/openrouter/openai/image-payload.js +8 -2
- package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +1 -1
- package/esm/src/providers/openrouter/openai/sdk-messages.js +32 -5
- package/package.json +1 -1
- package/esm/src/interface/blocks.d.ts +0 -20
- package/esm/src/interface/blocks.js +0 -180
- package/esm/src/interface/from-profile.d.ts +0 -14
- package/esm/src/interface/from-profile.js +0 -104
- package/esm/src/interface/inputs.d.ts +0 -8
- package/esm/src/interface/inputs.js +0 -127
- package/esm/src/interface/mod.d.ts +0 -10
- package/esm/src/interface/mod.js +0 -9
- package/esm/src/interface/types.d.ts +0 -153
- package/esm/src/interface/types.js +0 -13
|
@@ -8,27 +8,51 @@
|
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
10
|
import { bindCanary } from '../../../guardrails/canary.js';
|
|
11
|
-
import { throwIfAborted } from '../../../guardrails/error.js';
|
|
12
|
-
import {
|
|
11
|
+
import { isAbortError, throwIfAborted } from '../../../guardrails/error.js';
|
|
12
|
+
import { projectGuardrailTurnEvent } from '../../../guardrails/events.js';
|
|
13
|
+
import { resolveGuardrailPolicy } from '../../../guardrails/policy.js';
|
|
14
|
+
import { sanitizeTurnRequestWithEvents } from '../../../guardrails/sanitize.js';
|
|
15
|
+
import { resolveTraceWriter } from '../../../observability/policy.js';
|
|
13
16
|
import { noopSink, writeTrace } from '../../../observability/trace.js';
|
|
14
17
|
import { buildRecord } from '../../../observability/trace-record.js';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import { expandT1Policy } from '../../tools/resolve.js';
|
|
18
|
+
import { getProfile } from '../../registry/profiles.js';
|
|
19
|
+
import { resolveTurn } from '../../registry/resolve.js';
|
|
20
|
+
import { cloneTurnToolSnapshot, expandT1Policy } from '../../tools/resolve.js';
|
|
18
21
|
import { resolveCompactionTokens, shouldCompact, splitForCompaction } from '../compaction.js';
|
|
19
22
|
import { runAttemptsWithValidation } from './gates.js';
|
|
20
|
-
import {
|
|
23
|
+
import { applyTurnStage } from './stages.js';
|
|
24
|
+
import { shouldSkipStreamEvent } from './stream.js';
|
|
21
25
|
import { calculateFallbackTokens } from './tokens.js';
|
|
26
|
+
function projectForObs(event, policy) {
|
|
27
|
+
return projectGuardrailTurnEvent(event, policy?.include.guardrailMatchPreview ?? false);
|
|
28
|
+
}
|
|
29
|
+
function* emitObservedStage(ctx, stageEv, profile) {
|
|
30
|
+
const stageOut = projectForObs(stageEv, ctx.observability);
|
|
31
|
+
ctx.seen.push(stageOut);
|
|
32
|
+
if (!shouldSkipStreamEvent(stageOut, profile))
|
|
33
|
+
yield stageOut;
|
|
34
|
+
}
|
|
22
35
|
function getCompactionSpec(profile, modelId) {
|
|
23
|
-
return profile.
|
|
36
|
+
return profile.models[modelId]?.compaction;
|
|
37
|
+
}
|
|
38
|
+
/** Fold one history message to a compaction transcript line (media → markers). */
|
|
39
|
+
function compactionTranscriptLine(m) {
|
|
40
|
+
const text = m.content ?? '';
|
|
41
|
+
const mediaMarkers = m.parts
|
|
42
|
+
?.filter((p) => p.type !== 'text')
|
|
43
|
+
.map((p) => `[${p.type}]`)
|
|
44
|
+
.join('') ?? '';
|
|
45
|
+
const fromTextParts = !text && m.parts
|
|
46
|
+
? m.parts
|
|
47
|
+
.filter((p) => p.type === 'text')
|
|
48
|
+
.map((p) => p.text)
|
|
49
|
+
.join('')
|
|
50
|
+
: '';
|
|
51
|
+
const content = `${text || fromTextParts}${mediaMarkers}`;
|
|
52
|
+
return `[${m.role}]: ${content}`;
|
|
24
53
|
}
|
|
25
54
|
async function runCompactionTurn(toCompact, spec, provider, signal) {
|
|
26
|
-
const compactText = toCompact
|
|
27
|
-
.map((m) => {
|
|
28
|
-
const content = m.content ?? m.parts?.map((p) => ('text' in p ? p.text : '')).join('') ?? '';
|
|
29
|
-
return `[${m.role}]: ${content}`;
|
|
30
|
-
})
|
|
31
|
-
.join('\n');
|
|
55
|
+
const compactText = toCompact.map(compactionTranscriptLine).join('\n');
|
|
32
56
|
const events = [];
|
|
33
57
|
for await (const event of runTurn({
|
|
34
58
|
profile: spec.profile,
|
|
@@ -102,14 +126,95 @@ async function* emitTurn(args) {
|
|
|
102
126
|
allEmittedEvents: [],
|
|
103
127
|
attemptEvents: [],
|
|
104
128
|
};
|
|
129
|
+
args.outState.state = state;
|
|
130
|
+
const pre = yield* applyTurnStage({
|
|
131
|
+
profile,
|
|
132
|
+
generation,
|
|
133
|
+
state,
|
|
134
|
+
stage: 'pre_turn',
|
|
135
|
+
step: 1,
|
|
136
|
+
onStage: safe.onStage,
|
|
137
|
+
signal: safe.signal,
|
|
138
|
+
foldInput: true,
|
|
139
|
+
host: generation.host,
|
|
140
|
+
});
|
|
141
|
+
if (pre.abort) {
|
|
142
|
+
const stop = {
|
|
143
|
+
kind: 'cancelled',
|
|
144
|
+
...(typeof pre.abort === 'object' && pre.abort.reason ? { native: pre.abort.reason } : {}),
|
|
145
|
+
};
|
|
146
|
+
const done = { type: 'done', stop };
|
|
147
|
+
state.allEmittedEvents.push(done);
|
|
148
|
+
yield done;
|
|
149
|
+
yield* applyTurnStage({
|
|
150
|
+
profile,
|
|
151
|
+
generation,
|
|
152
|
+
state,
|
|
153
|
+
stage: 'post_turn',
|
|
154
|
+
step: 1,
|
|
155
|
+
onStage: safe.onStage,
|
|
156
|
+
signal: safe.signal,
|
|
157
|
+
stop,
|
|
158
|
+
host: generation.host,
|
|
159
|
+
});
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
105
162
|
yield* runAttemptsWithValidation(safe, profile, generation, system, provider, upstream, state);
|
|
106
163
|
if (!state.sawTokensEvent) {
|
|
107
164
|
yield* calculateFallbackTokens(safe, system, state.allEmittedEvents);
|
|
108
165
|
}
|
|
109
|
-
|
|
166
|
+
const stop = state.lastStop ?? { kind: 'completed' };
|
|
167
|
+
const done = {
|
|
110
168
|
type: 'done',
|
|
111
|
-
stop
|
|
169
|
+
stop,
|
|
170
|
+
...(stop.kind === 'tool' && state.toolSnapshot
|
|
171
|
+
? { tools: cloneTurnToolSnapshot(state.toolSnapshot) }
|
|
172
|
+
: {}),
|
|
173
|
+
...(stop.kind === 'gate' && state.toolSnapshot
|
|
174
|
+
? { tools: cloneTurnToolSnapshot(state.toolSnapshot) }
|
|
175
|
+
: {}),
|
|
112
176
|
};
|
|
177
|
+
state.allEmittedEvents.push(done);
|
|
178
|
+
yield done;
|
|
179
|
+
}
|
|
180
|
+
async function* streamTurnEvents(ctx, profile, gen, provider, compactionSpec, isCompacting) {
|
|
181
|
+
if (!ctx.safe || ctx.system === undefined)
|
|
182
|
+
return;
|
|
183
|
+
const outState = {};
|
|
184
|
+
for await (const event of emitTurn({
|
|
185
|
+
safe: ctx.safe,
|
|
186
|
+
profile,
|
|
187
|
+
generation: gen,
|
|
188
|
+
system: ctx.system,
|
|
189
|
+
provider,
|
|
190
|
+
upstream: ctx.upstream,
|
|
191
|
+
outState,
|
|
192
|
+
})) {
|
|
193
|
+
const attached = await maybeAttachAfter(event, ctx, gen, compactionSpec, isCompacting);
|
|
194
|
+
const out = projectForObs(attached, ctx.observability);
|
|
195
|
+
ctx.seen.push(out);
|
|
196
|
+
if (!shouldSkipStreamEvent(out, profile))
|
|
197
|
+
yield out;
|
|
198
|
+
if (out.type === 'done' && outState.state) {
|
|
199
|
+
// Skip duplicate post_turn when pre_turn abort already emitted it inside emitTurn.
|
|
200
|
+
const alreadyPost = outState.state.allEmittedEvents.some((e) => e.type === 'stage' && e.stage === 'post_turn');
|
|
201
|
+
if (!alreadyPost) {
|
|
202
|
+
for await (const stageEv of applyTurnStage({
|
|
203
|
+
profile,
|
|
204
|
+
generation: gen,
|
|
205
|
+
state: outState.state,
|
|
206
|
+
stage: 'post_turn',
|
|
207
|
+
step: Math.max(outState.state.stepCount, 1),
|
|
208
|
+
onStage: ctx.safe.onStage,
|
|
209
|
+
signal: ctx.safe.signal,
|
|
210
|
+
stop: out.stop,
|
|
211
|
+
host: gen.host,
|
|
212
|
+
})) {
|
|
213
|
+
yield* emitObservedStage(ctx, stageEv, profile);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
113
218
|
}
|
|
114
219
|
async function flushTurnTrace(sink, ctx) {
|
|
115
220
|
await writeTrace(sink, buildRecord({
|
|
@@ -125,10 +230,11 @@ async function flushTurnTrace(sink, ctx) {
|
|
|
125
230
|
generation: ctx.generation,
|
|
126
231
|
protocol: ctx.protocol,
|
|
127
232
|
sanitizedReq: ctx.safe,
|
|
233
|
+
observability: ctx.observability,
|
|
128
234
|
}));
|
|
129
235
|
}
|
|
130
236
|
/** Execute one host turn against a provider adapter. */
|
|
131
|
-
async function* runTurn(req, provider,
|
|
237
|
+
async function* runTurn(req, provider, sinkOverride) {
|
|
132
238
|
const ctx = {
|
|
133
239
|
req,
|
|
134
240
|
seen: [],
|
|
@@ -136,18 +242,72 @@ async function* runTurn(req, provider, sink = noopSink()) {
|
|
|
136
242
|
canary: '',
|
|
137
243
|
upstream: [],
|
|
138
244
|
};
|
|
245
|
+
let sink = sinkOverride ?? noopSink();
|
|
139
246
|
try {
|
|
247
|
+
const profile = getProfile(req.profile);
|
|
248
|
+
const resolved = resolveTraceWriter({
|
|
249
|
+
override: sinkOverride,
|
|
250
|
+
observability: profile.observability,
|
|
251
|
+
});
|
|
252
|
+
sink = resolved.sink;
|
|
253
|
+
ctx.observability = resolved.policy;
|
|
140
254
|
yield* runTurnBody(ctx, provider);
|
|
141
255
|
}
|
|
142
256
|
catch (err) {
|
|
257
|
+
if (isAbortError(err)) {
|
|
258
|
+
yield* emitCancelledDoneAfterAbort(ctx);
|
|
259
|
+
await flushTurnTrace(sink, { ...ctx, thrown: err });
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
143
262
|
await flushTurnTrace(sink, { ...ctx, thrown: err });
|
|
144
263
|
throw err;
|
|
145
264
|
}
|
|
146
265
|
await flushTurnTrace(sink, ctx);
|
|
147
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* Slice 1: host AbortSignal ends with cancelled `done` + `post_turn`, not a bare throw.
|
|
269
|
+
* Skip when a terminal `done` already reached the host stream.
|
|
270
|
+
*/
|
|
271
|
+
async function* emitCancelledDoneAfterAbort(ctx) {
|
|
272
|
+
if (ctx.seen.some((e) => e.type === 'done'))
|
|
273
|
+
return;
|
|
274
|
+
const stop = { kind: 'cancelled' };
|
|
275
|
+
const done = { type: 'done', stop };
|
|
276
|
+
const outDone = projectForObs(done, ctx.observability);
|
|
277
|
+
ctx.seen.push(outDone);
|
|
278
|
+
yield outDone;
|
|
279
|
+
const profile = getProfile(ctx.req.profile);
|
|
280
|
+
const gen = ctx.generation;
|
|
281
|
+
if (!gen || !ctx.safe)
|
|
282
|
+
return;
|
|
283
|
+
const state = {
|
|
284
|
+
currentHistory: [...(gen.history ?? [])],
|
|
285
|
+
stepCount: 0,
|
|
286
|
+
sawTokensEvent: false,
|
|
287
|
+
allEmittedEvents: [...ctx.seen],
|
|
288
|
+
attemptEvents: [],
|
|
289
|
+
};
|
|
290
|
+
for await (const stageEv of applyTurnStage({
|
|
291
|
+
profile,
|
|
292
|
+
generation: gen,
|
|
293
|
+
state,
|
|
294
|
+
stage: 'post_turn',
|
|
295
|
+
step: 1,
|
|
296
|
+
onStage: ctx.safe.onStage,
|
|
297
|
+
stop,
|
|
298
|
+
host: gen.host,
|
|
299
|
+
})) {
|
|
300
|
+
yield* emitObservedStage(ctx, stageEv, profile);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
148
303
|
async function* runTurnBody(ctx, provider) {
|
|
149
|
-
|
|
150
|
-
|
|
304
|
+
const sanitized = sanitizeTurnRequestWithEvents(ctx.req);
|
|
305
|
+
ctx.safe = sanitized.request;
|
|
306
|
+
for (const event of sanitized.events) {
|
|
307
|
+
const out = projectForObs(event, ctx.observability);
|
|
308
|
+
ctx.seen.push(out);
|
|
309
|
+
yield out;
|
|
310
|
+
}
|
|
151
311
|
const { profile, generation: gen } = resolveTurn(ctx.safe);
|
|
152
312
|
await expandT1Policy(gen.tools, profile, ctx.safe);
|
|
153
313
|
gen.builtins = gen.tools.builtins;
|
|
@@ -155,16 +315,12 @@ async function* runTurnBody(ctx, provider) {
|
|
|
155
315
|
ctx.model = gen.model;
|
|
156
316
|
ctx.keySlot = gen.keySlot;
|
|
157
317
|
ctx.canary = gen.canary;
|
|
158
|
-
ctx.protocol = profile.model
|
|
318
|
+
ctx.protocol = profile.models[gen.model]?.protocol;
|
|
319
|
+
throwIfAborted(ctx.safe.signal);
|
|
159
320
|
const isCompacting = ctx.req.metadata?._compacting === true;
|
|
160
321
|
const compactionSpec = isCompacting ? undefined : getCompactionSpec(profile, gen.model);
|
|
161
322
|
await maybeCompactBefore(ctx, gen, compactionSpec, provider);
|
|
162
|
-
|
|
163
|
-
const continueSys = ctx.safe.continueFrom ? CONTINUE_INSTRUCTION : '';
|
|
164
|
-
const combinedSys = [systemFromProfile(profile, role), ctx.safe.system, continueSys]
|
|
165
|
-
.filter(Boolean)
|
|
166
|
-
.join('\n\n');
|
|
167
|
-
ctx.system = bindCanary(combinedSys, ctx.canary);
|
|
323
|
+
ctx.system = bindCanary(gen.resolvedSystem, ctx.canary, resolveGuardrailPolicy(profile.guardrails).canaryBindNote);
|
|
168
324
|
yield* streamTurnEvents(ctx, profile, gen, provider, compactionSpec, isCompacting);
|
|
169
325
|
}
|
|
170
326
|
async function maybeCompactBefore(ctx, gen, compactionSpec, provider) {
|
|
@@ -179,23 +335,6 @@ async function maybeCompactBefore(ctx, gen, compactionSpec, provider) {
|
|
|
179
335
|
signal: ctx.safe.signal,
|
|
180
336
|
});
|
|
181
337
|
}
|
|
182
|
-
async function* streamTurnEvents(ctx, profile, gen, provider, compactionSpec, isCompacting) {
|
|
183
|
-
if (!ctx.safe || ctx.system === undefined)
|
|
184
|
-
return;
|
|
185
|
-
for await (const event of emitTurn({
|
|
186
|
-
safe: ctx.safe,
|
|
187
|
-
profile,
|
|
188
|
-
generation: gen,
|
|
189
|
-
system: ctx.system,
|
|
190
|
-
provider,
|
|
191
|
-
upstream: ctx.upstream,
|
|
192
|
-
})) {
|
|
193
|
-
const out = await maybeAttachAfter(event, ctx, gen, compactionSpec, isCompacting);
|
|
194
|
-
ctx.seen.push(out);
|
|
195
|
-
if (!shouldSkipStreamEvent(out, profile))
|
|
196
|
-
yield out;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
338
|
async function maybeAttachAfter(event, ctx, gen, compactionSpec, isCompacting) {
|
|
200
339
|
if (!(event.type === 'done' && compactionSpec?.timing === 'after' && !isCompacting && ctx.safe)) {
|
|
201
340
|
return event;
|
|
@@ -207,4 +346,4 @@ async function maybeAttachAfter(event, ctx, gen, compactionSpec, isCompacting) {
|
|
|
207
346
|
seen: ctx.seen,
|
|
208
347
|
});
|
|
209
348
|
}
|
|
210
|
-
export { runTurn };
|
|
349
|
+
export { compactionTranscriptLine, runTurn };
|
|
@@ -41,7 +41,7 @@ function joinPath(prefix, key) {
|
|
|
41
41
|
return prefix ? `${prefix}.${key}` : key;
|
|
42
42
|
}
|
|
43
43
|
function pushMissing(path, failures) {
|
|
44
|
-
failures.push({ path, error: `required field '${path}' is missing` });
|
|
44
|
+
failures.push({ path, error: `required field '${path}' is missing` }); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
45
45
|
}
|
|
46
46
|
async function runFieldValidator(path, value, validator, slots, failures) {
|
|
47
47
|
if (!validator) {
|
|
@@ -53,7 +53,7 @@ async function runFieldValidator(path, value, validator, slots, failures) {
|
|
|
53
53
|
}
|
|
54
54
|
failures.push({
|
|
55
55
|
path,
|
|
56
|
-
error: check.error || check.finding || `Validation failed for '${path}'`,
|
|
56
|
+
error: check.error || check.finding || `Validation failed for '${path}'`, // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
59
|
async function visitProperty(args) {
|
|
@@ -95,7 +95,7 @@ async function walkObject(schema, value, pathPrefix, fields, slots, failures) {
|
|
|
95
95
|
async function collectValidationFailures(jsonSchema, structured, fields, slots) {
|
|
96
96
|
const root = asObjectSchema(jsonSchema);
|
|
97
97
|
if (!root) {
|
|
98
|
-
throw new TheorumError('structured validation requires a JSON Schema object root');
|
|
98
|
+
throw new TheorumError('structured validation requires a JSON Schema object root'); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
99
99
|
}
|
|
100
100
|
const failures = [];
|
|
101
101
|
if (!asRecord(structured)) {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text `runTurn` wiring around the stage spine: record stage events in step
|
|
3
|
+
* state, fold the opening input, and append sanitized injects to turn history.
|
|
4
|
+
*
|
|
5
|
+
* Contract: `docs/contracts/stages.md`. The stage itself runs in `runStage`.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { type StageApplyWarning, type StageCallBag, type StageContext, type StageHandler } from '../../stages.js';
|
|
10
|
+
import type { Profile, ResolvedGeneration, TurnEvent, TurnHistoryMessage } from '../../types.js';
|
|
11
|
+
import type { StepExecutionState } from './state.js';
|
|
12
|
+
export interface ApplyTurnStageArgs extends StageCallBag {
|
|
13
|
+
profile: Profile;
|
|
14
|
+
generation: ResolvedGeneration;
|
|
15
|
+
state: StepExecutionState;
|
|
16
|
+
stage: StageContext['stage'];
|
|
17
|
+
step: number;
|
|
18
|
+
onStage?: StageHandler;
|
|
19
|
+
signal?: AbortSignal;
|
|
20
|
+
/** Fold generation.input into history when true (pre_turn + handler present). */
|
|
21
|
+
foldInput?: boolean;
|
|
22
|
+
/** Another provider step would exceed maxSteps — reject inject. */
|
|
23
|
+
injectWouldExceedMaxSteps?: boolean;
|
|
24
|
+
host?: unknown;
|
|
25
|
+
}
|
|
26
|
+
export interface ApplyTurnStageResult {
|
|
27
|
+
abort?: boolean | {
|
|
28
|
+
reason?: string;
|
|
29
|
+
};
|
|
30
|
+
injectCount: number;
|
|
31
|
+
warnings: StageApplyWarning[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Append already-sanitized inject messages to turn history. Mirrors them into
|
|
35
|
+
* the Interactions continuation when one is active. Returns how many landed.
|
|
36
|
+
*/
|
|
37
|
+
export declare function applyStageInjects(state: StepExecutionState, inject: readonly TurnHistoryMessage[]): number;
|
|
38
|
+
/** Run a turn stage, recording every stage event on step state. */
|
|
39
|
+
export declare function applyTurnStage(args: ApplyTurnStageArgs): AsyncGenerator<TurnEvent, ApplyTurnStageResult>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text `runTurn` wiring around the stage spine: record stage events in step
|
|
3
|
+
* state, fold the opening input, and append sanitized injects to turn history.
|
|
4
|
+
*
|
|
5
|
+
* Contract: `docs/contracts/stages.md`. The stage itself runs in `runStage`.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { throwIfAborted } from '../../../guardrails/error.js';
|
|
10
|
+
import { wireInteractionPart } from '../../interaction-parts.js';
|
|
11
|
+
import { runStage, } from '../../stages.js';
|
|
12
|
+
import { profileAllowsInject } from '../../stop.js';
|
|
13
|
+
function stageMessageToInteractionStep(msg) {
|
|
14
|
+
const type = msg.role === 'assistant' ? 'model_output' : 'user_input';
|
|
15
|
+
if (msg.parts && msg.parts.length > 0) {
|
|
16
|
+
return {
|
|
17
|
+
type,
|
|
18
|
+
content: msg.parts.map(wireInteractionPart),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return { type, content: [{ type: 'text', text: msg.content ?? '' }] };
|
|
22
|
+
}
|
|
23
|
+
/** Move opening user `generation.input` into history (Interactions-safe fold). */
|
|
24
|
+
function foldGenerationInputIntoHistory(generation, state) {
|
|
25
|
+
if (state.foldedForGeneration === generation)
|
|
26
|
+
return;
|
|
27
|
+
state.foldedForGeneration = generation;
|
|
28
|
+
if (generation.input.length === 0)
|
|
29
|
+
return;
|
|
30
|
+
const textOnly = generation.input.every((p) => p.type === 'text');
|
|
31
|
+
if (textOnly) {
|
|
32
|
+
state.currentHistory.push({
|
|
33
|
+
role: 'user',
|
|
34
|
+
content: generation.input.map((p) => (p.type === 'text' ? p.text : '')).join(''),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
state.currentHistory.push({
|
|
39
|
+
role: 'user',
|
|
40
|
+
parts: [...generation.input],
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
generation.input = [];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Append already-sanitized inject messages to turn history. Mirrors them into
|
|
47
|
+
* the Interactions continuation when one is active. Returns how many landed.
|
|
48
|
+
*/
|
|
49
|
+
export function applyStageInjects(state, inject) {
|
|
50
|
+
if (inject.length === 0)
|
|
51
|
+
return 0;
|
|
52
|
+
state.currentHistory.push(...inject);
|
|
53
|
+
if (state.interactionsContinuation) {
|
|
54
|
+
for (const msg of inject) {
|
|
55
|
+
if (msg.role === 'tool')
|
|
56
|
+
continue;
|
|
57
|
+
state.interactionsContinuation.input.push(stageMessageToInteractionStep(msg));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return inject.length;
|
|
61
|
+
}
|
|
62
|
+
/** Run a turn stage, recording every stage event on step state. */
|
|
63
|
+
export async function* applyTurnStage(args) {
|
|
64
|
+
const { profile, generation, state, onStage, foldInput, host, ...call } = args;
|
|
65
|
+
throwIfAborted(call.signal);
|
|
66
|
+
if (foldInput && onStage) {
|
|
67
|
+
foldGenerationInputIntoHistory(generation, state);
|
|
68
|
+
}
|
|
69
|
+
const run = runStage({
|
|
70
|
+
...call,
|
|
71
|
+
history: state.currentHistory,
|
|
72
|
+
handlers: onStage ? [onStage] : [],
|
|
73
|
+
guardrails: profile.guardrails,
|
|
74
|
+
injectAllowed: profileAllowsInject(profile),
|
|
75
|
+
host: host ?? generation.host,
|
|
76
|
+
});
|
|
77
|
+
let next = await run.next();
|
|
78
|
+
while (!next.done) {
|
|
79
|
+
state.allEmittedEvents.push(next.value);
|
|
80
|
+
yield next.value;
|
|
81
|
+
next = await run.next();
|
|
82
|
+
}
|
|
83
|
+
const out = next.value;
|
|
84
|
+
return {
|
|
85
|
+
abort: out.abort,
|
|
86
|
+
injectCount: applyStageInjects(state, out.inject),
|
|
87
|
+
warnings: out.warnings,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { TurnTaint } from '../../../guardrails/types.js';
|
|
2
|
+
import type { TurnToolSnapshot } from '../../tools/types.js';
|
|
1
3
|
import type { ResolvedGeneration, TurnEvent, TurnHistoryMessage, TurnRequest, TurnStop } from '../../types.js';
|
|
2
4
|
interface StepExecutionState {
|
|
3
5
|
currentHistory: TurnHistoryMessage[];
|
|
@@ -5,8 +7,25 @@ interface StepExecutionState {
|
|
|
5
7
|
sawTokensEvent: boolean;
|
|
6
8
|
allEmittedEvents: TurnEvent[];
|
|
7
9
|
attemptEvents: TurnEvent[];
|
|
10
|
+
/**
|
|
11
|
+
* True when progressive yield withheld user-visible events during this attempt.
|
|
12
|
+
*
|
|
13
|
+
* The attempt gate needs it: if the mid-stream window tripped but the final
|
|
14
|
+
* verdict on the whole text passes, nothing was streamed, so the buffered
|
|
15
|
+
* text must be released rather than silently dropped.
|
|
16
|
+
*/
|
|
17
|
+
withheldVisible?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Untrusted remote content this turn has already read.
|
|
20
|
+
*
|
|
21
|
+
* Accumulates across tool calls so a later call can be judged against what the
|
|
22
|
+
* turn has ingested, not just its own arguments.
|
|
23
|
+
*/
|
|
24
|
+
taint?: TurnTaint;
|
|
8
25
|
/** Last provider stop from a discarded provider `done` event. */
|
|
9
26
|
lastStop?: TurnStop;
|
|
27
|
+
/** Tool snapshot at tool pause — emitted on terminal `done` when `stop.kind === 'tool'`. */
|
|
28
|
+
toolSnapshot?: TurnToolSnapshot;
|
|
10
29
|
/** Latest Google Interactions id observed on the current provider stream. */
|
|
11
30
|
lastInteractionId?: string;
|
|
12
31
|
/** Pending Interactions `function_result` continuation for the next provider step. */
|
|
@@ -14,6 +33,11 @@ interface StepExecutionState {
|
|
|
14
33
|
previousInteractionId: string;
|
|
15
34
|
input: Record<string, unknown>[];
|
|
16
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* Generation whose opening `input` was folded into `currentHistory` for steering.
|
|
38
|
+
* Compared by identity so repair retries (new generation) fold again.
|
|
39
|
+
*/
|
|
40
|
+
foldedForGeneration?: ResolvedGeneration;
|
|
17
41
|
}
|
|
18
42
|
interface AttemptFlowState {
|
|
19
43
|
currentAttempt: number;
|