@basein/runner 0.3.17 → 0.3.18
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/dist/bin/bir-scenario.d.ts +5 -1
- package/dist/bin/bir-scenario.js +155 -5
- package/dist/bin/bir.js +2 -2
- package/dist/bin/scenario-edit.d.ts +7 -0
- package/dist/bin/scenario-edit.js +9 -2
- package/dist/bin/scenario-liveness.d.ts +12 -1
- package/dist/bin/scenario-liveness.js +8 -4
- package/dist/bin/setup.js +3 -3
- package/dist/control/client.d.ts +5 -0
- package/dist/control/client.js +7 -0
- package/dist/control/ensure-hook.d.ts +14 -3
- package/dist/control/ensure-hook.js +18 -5
- package/dist/control/server.d.ts +165 -2
- package/dist/control/server.js +719 -21
- package/dist/control/transcript.d.ts +19 -0
- package/dist/control/transcript.js +57 -0
- package/dist/proxy/intercept.js +13 -0
- package/dist/proxy/session.d.ts +23 -0
- package/dist/proxy/session.js +71 -3
- package/dist/record/recorder.d.ts +146 -0
- package/dist/record/recorder.js +9 -0
- package/dist/record/remote-recorder.d.ts +59 -1
- package/dist/record/remote-recorder.js +297 -20
- package/dist/record/switchable-recorder.js +6 -0
- package/dist/replay/bundle.d.ts +8 -0
- package/dist/replay/bundle.js +20 -6
- package/dist/replay/controller.d.ts +33 -1
- package/dist/replay/controller.js +137 -12
- package/dist/replay/derive.d.ts +15 -0
- package/dist/replay/derive.js +5 -0
- package/dist/replay/plan.d.ts +90 -1
- package/dist/replay/plan.js +232 -10
- package/dist/replay/source-run.d.ts +2 -2
- package/dist/replay/source-run.js +3 -3
- package/dist/replay/targets.d.ts +40 -1
- package/dist/replay/targets.js +105 -3
- package/dist/replay/types.d.ts +6 -5
- package/package.json +1 -1
|
@@ -21,20 +21,27 @@ import { bashCommandFor } from "./bash-channel.js";
|
|
|
21
21
|
import { BuiltinNotRunnable, BuiltinTimeout, parseBashAllow, parseBuiltinTools, runBuiltin, } from "./builtins.js";
|
|
22
22
|
import { BASH_CHANNEL_MAX, MAX_REPLAY_REASON, testWords, truncate } from "./bundle.js";
|
|
23
23
|
import { coverageOf, modeFor, reachOf } from "./coverage.js";
|
|
24
|
-
import { deriveParameters, } from "./derive.js";
|
|
24
|
+
import { deriveParameters, localDay, } from "./derive.js";
|
|
25
25
|
import { buildHandoverNote, MAX_HANDOVER_NOTE, } from "./handover.js";
|
|
26
26
|
import { NO_PROXY, NoSessionProxyError, ProxyWorkQueue, QUEUE_CLOSED } from "./executor.js";
|
|
27
27
|
import { logicTimeoutMs, MAX_LOGIC_TIMEOUT_MS } from "./logic.js";
|
|
28
|
-
import { PREVIEW_BUDGET_MS, ScenarioReplayPlan, StepRunError, } from "./plan.js";
|
|
28
|
+
import { PREVIEW_BUDGET_MS, RecordedValueError, ScenarioReplayPlan, StepRunError, } from "./plan.js";
|
|
29
29
|
import { PRICING_VERSION } from "./pricing.js";
|
|
30
30
|
import { hasShellStep, sinkOf, sinkOfPlan, unsafeParameter } from "./safety.js";
|
|
31
31
|
import { SourceRunOutputs } from "./source-run.js";
|
|
32
32
|
import { clampToFrameStart, flattenChain, frameEdges, } from "./flatten.js";
|
|
33
|
-
import { blockingTargets } from "./targets.js";
|
|
33
|
+
import { blockingTargets, testedOnlyTargets } from "./targets.js";
|
|
34
34
|
import { isNoResult, toolResultError } from "./tool-error.js";
|
|
35
35
|
import { OUTCOME_RANK, hasTargets, isReadyScenario, } from "./types.js";
|
|
36
36
|
/** The first-party tool a `direct` plan is delivered through (§6.3). */
|
|
37
37
|
export const DIRECT_TOOL_NAME = "mcp__bir__run_scenario";
|
|
38
|
+
/**
|
|
39
|
+
* `bir`'s own tool for saying a replay's results do not answer the request
|
|
40
|
+
* (bin/bir-scenario.ts; the service's review of calcscenarioautocorrect.md,
|
|
41
|
+
* item 19): the one call a finished bundle lets the agent make, where the
|
|
42
|
+
* session has it ({@link ReplayState.reportTool}).
|
|
43
|
+
*/
|
|
44
|
+
export const REPORT_TOOL_NAME = "mcp__bir__report_wrong_result";
|
|
38
45
|
/** How long a `/proxy/poll` is held open before it answers empty. */
|
|
39
46
|
export const POLL_HOLD_MS = 25_000;
|
|
40
47
|
/**
|
|
@@ -113,6 +120,19 @@ const DIRECT_RUN_MARGIN_MS = 5_000;
|
|
|
113
120
|
* Each is bounded by `logicTimeoutMs()` (logic.ts).
|
|
114
121
|
*/
|
|
115
122
|
const LOGIC_BODIES_OUTSIDE_PLAN = 6;
|
|
123
|
+
/**
|
|
124
|
+
* The agent's day as a system prompt said it, and only then (issue 1212): a
|
|
125
|
+
* line that says a day, written out or in words. Claude Code's own date
|
|
126
|
+
* reminder is this machine's day, which the runner knows better itself.
|
|
127
|
+
*/
|
|
128
|
+
function systemDay(day) {
|
|
129
|
+
if (!day || day.source !== "system")
|
|
130
|
+
return undefined;
|
|
131
|
+
if (day.day)
|
|
132
|
+
return day;
|
|
133
|
+
const words = /\b(jan(uary)?|feb(ruary)?|mar(ch)?|apr(il)?|may|june?|july?|aug(ust)?|sep(t(ember)?)?|oct(ober)?|nov(ember)?|dec(ember)?)\b/i;
|
|
134
|
+
return words.test(day.line) && /\b\d{4}\b/.test(day.line) ? day : undefined;
|
|
135
|
+
}
|
|
116
136
|
/** A derivation wait longer than this is not a budget a direct run can keep. */
|
|
117
137
|
const MAX_DIRECT_DERIVE_MS = 60_000;
|
|
118
138
|
/** However a direct run is squeezed, its plan keeps at least this. */
|
|
@@ -506,7 +526,7 @@ export class ReplayController {
|
|
|
506
526
|
// command nobody asked for.
|
|
507
527
|
let deriveCtx = ctx;
|
|
508
528
|
if (ctx.recentResults?.length && sinkOfPlan(planned, host?.sinks) === "command") {
|
|
509
|
-
deriveCtx = { liveCall: ctx.liveCall };
|
|
529
|
+
deriveCtx = { liveCall: ctx.liveCall, agentDay: ctx.agentDay };
|
|
510
530
|
logLine("replay.derive_context", {
|
|
511
531
|
scenario: scenario.id,
|
|
512
532
|
shell: hasShellStep(planned, host?.sinks) || undefined,
|
|
@@ -515,11 +535,27 @@ export class ReplayController {
|
|
|
515
535
|
});
|
|
516
536
|
}
|
|
517
537
|
const derivation = this.startDerivation(scenario, prompt, state, deriveCtx);
|
|
538
|
+
// The agent's own day shows in the session only after the prompt hook
|
|
539
|
+
// (issue 1212): the plan's start looks again, and reads the values once
|
|
540
|
+
// more when the day is another one.
|
|
541
|
+
state.agentDayNow = deriveCtx.agentDay;
|
|
542
|
+
state.rederive = (day) => this.startDerivation(scenario, prompt, state, { ...deriveCtx, agentDay: () => day });
|
|
518
543
|
// Whether the derivation has answered yet — read, never waited on, when the
|
|
519
544
|
// directive is written (below).
|
|
520
545
|
let deriveAnswered = false;
|
|
521
546
|
derivation.then(() => (deriveAnswered = true), () => (deriveAnswered = true));
|
|
522
|
-
|
|
547
|
+
// The targets only one half of this plan reads (the service's review of
|
|
548
|
+
// calcscenarioautocorrect.md, item 11; targets.ts, `testedOnlyTargets`):
|
|
549
|
+
// the plan holds each as a mark when the request does not give it. A
|
|
550
|
+
// reading that did not answer carries every target at its recorded
|
|
551
|
+
// sample (derive.ts), and one of these must be the mark there too — never
|
|
552
|
+
// last week's task name under a step that would create the task.
|
|
553
|
+
const oneHalf = hasTargets(scenario.paramsObject)
|
|
554
|
+
? testedOnlyTargets(targetKeys(scenario.paramsObject), scenario.paramsObject, planned, scenario.paramsLogic)
|
|
555
|
+
: [];
|
|
556
|
+
const params = derivation.then((r) => r.derived || oneHalf.length === 0
|
|
557
|
+
? r.params
|
|
558
|
+
: { ...r.params, ...Object.fromEntries(oneHalf.map((key) => [key, null])) });
|
|
523
559
|
// `params` is awaited by the plan, and by gate 7 below when there is a
|
|
524
560
|
// target. Without this, the losing race in gate 7 leaves `derivation`
|
|
525
561
|
// rejected and unhandled, which takes the process down on an unhandled
|
|
@@ -578,11 +614,22 @@ export class ReplayController {
|
|
|
578
614
|
// Worth a line of its own: this is the difference between a scenario
|
|
579
615
|
// that never runs and one that does, and it is the first thing to look
|
|
580
616
|
// at when a replay acts on the wrong thing.
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
617
|
+
const forOneHalf = result.missing.filter((key) => oneHalf.includes(key));
|
|
618
|
+
const byChain = result.missing.filter((key) => !oneHalf.includes(key));
|
|
619
|
+
if (byChain.length > 0) {
|
|
620
|
+
logLine("replay.targets_found_by_chain", {
|
|
621
|
+
scenario: scenario.id,
|
|
622
|
+
unnamed: byChain.join(","),
|
|
623
|
+
why: "the chain computes these from its own steps; none is read from the caller",
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
if (forOneHalf.length > 0) {
|
|
627
|
+
logLine("replay.targets_for_one_half", {
|
|
628
|
+
scenario: scenario.id,
|
|
629
|
+
unnamed: forOneHalf.join(","),
|
|
630
|
+
why: "only steps that run under a test read these: the plan runs, and a step that needs one stops in front of its call for the agent",
|
|
631
|
+
});
|
|
632
|
+
}
|
|
586
633
|
}
|
|
587
634
|
// The values are in hand: one this plan must not template into its
|
|
588
635
|
// command (safety.ts) declines here, before any directive is injected,
|
|
@@ -1058,10 +1105,12 @@ export class ReplayController {
|
|
|
1058
1105
|
// a note, delivered in place of this call.
|
|
1059
1106
|
const step = plan.currentStep();
|
|
1060
1107
|
if (step) {
|
|
1108
|
+
// A value only the recording holds (issue 1212) is no fault of the step.
|
|
1109
|
+
const recorded = err instanceof RecordedValueError;
|
|
1061
1110
|
this.recordStep(state, {
|
|
1062
1111
|
step,
|
|
1063
1112
|
entry: plan.currentEntry(),
|
|
1064
|
-
outcome: "failed",
|
|
1113
|
+
outcome: recorded ? "skipped" : "failed",
|
|
1065
1114
|
stage: "tool_input_logic",
|
|
1066
1115
|
error: errText(err),
|
|
1067
1116
|
});
|
|
@@ -1071,6 +1120,7 @@ export class ReplayController {
|
|
|
1071
1120
|
position: plan.currentStepIndex,
|
|
1072
1121
|
error: errText(err),
|
|
1073
1122
|
delivery: "above",
|
|
1123
|
+
...(recorded ? { stopReason: "not_run" } : {}),
|
|
1074
1124
|
});
|
|
1075
1125
|
const note = this.takeNote(state);
|
|
1076
1126
|
if (note)
|
|
@@ -1772,7 +1822,7 @@ export class ReplayController {
|
|
|
1772
1822
|
const deadline = Date.now() + this.budgets.planMs;
|
|
1773
1823
|
let result;
|
|
1774
1824
|
try {
|
|
1775
|
-
result = await plan.runToCompletion(this.executeStep(state, { deadline }), this.recordedSource(state), this.observeStep(state), deadline, MAX_REPLAY_REASON, { stopOnFailure: true, recordedFallback: this.recordedFallback, signal });
|
|
1825
|
+
result = await plan.runToCompletion(this.executeStep(state, { deadline }), this.recordedSource(state), this.observeStep(state), deadline, MAX_REPLAY_REASON, { stopOnFailure: true, recordedFallback: this.recordedFallback, signal, reportTool: this.reportToolFor(state) });
|
|
1776
1826
|
}
|
|
1777
1827
|
catch (err) {
|
|
1778
1828
|
// The scenario's own logic failed. Retire and let the model do the work.
|
|
@@ -2233,8 +2283,18 @@ export class ReplayController {
|
|
|
2233
2283
|
const service = this.deriveService(scenario.id);
|
|
2234
2284
|
const hasSchema = Object.keys(scenario.paramsObject ?? {}).length > 0;
|
|
2235
2285
|
state.deriveOnService = !apiKey && service !== undefined && hasSchema;
|
|
2286
|
+
// The day a system prompt told the agent it is — a benchmark's keeps its
|
|
2287
|
+
// agent on 2023-11-30 for ever — and else this machine's (issue 1212).
|
|
2288
|
+
// Never Claude Code's own date reminder: that is this machine's day, and
|
|
2289
|
+
// on a new day's first prompt still yesterday's.
|
|
2290
|
+
const agent = systemDay(ctx.agentDay?.());
|
|
2291
|
+
const today = agent?.day ?? localDay();
|
|
2292
|
+
state.deriveDay = today;
|
|
2293
|
+
state.deriveLine = agent?.line;
|
|
2236
2294
|
return derive({
|
|
2237
2295
|
prompt,
|
|
2296
|
+
today,
|
|
2297
|
+
...(agent?.line ? { todaySaid: agent.line } : {}),
|
|
2238
2298
|
intent: scenario.intent ?? "",
|
|
2239
2299
|
paramsObject: scenario.paramsObject,
|
|
2240
2300
|
apiKey,
|
|
@@ -2252,6 +2312,9 @@ export class ReplayController {
|
|
|
2252
2312
|
})
|
|
2253
2313
|
.then((r) => {
|
|
2254
2314
|
state.deriveCostUsd += r.costUsd;
|
|
2315
|
+
// The day the service read from: a plan on a fixed date reads its own.
|
|
2316
|
+
if (r.dayUsed)
|
|
2317
|
+
state.deriveDay = r.dayUsed;
|
|
2255
2318
|
logLine("replay.derived", {
|
|
2256
2319
|
scenario: scenario.id,
|
|
2257
2320
|
params: Object.keys(r.params).length,
|
|
@@ -2333,6 +2396,7 @@ export class ReplayController {
|
|
|
2333
2396
|
recordedFallback: this.recordedFallback,
|
|
2334
2397
|
deadline,
|
|
2335
2398
|
signal,
|
|
2399
|
+
reportTool: this.reportToolFor(state),
|
|
2336
2400
|
});
|
|
2337
2401
|
}
|
|
2338
2402
|
catch (err) {
|
|
@@ -2768,6 +2832,21 @@ export class ReplayController {
|
|
|
2768
2832
|
}
|
|
2769
2833
|
return serializeCapped(redact(result));
|
|
2770
2834
|
}
|
|
2835
|
+
/**
|
|
2836
|
+
* The report tool a bundle may name, when this plan's session has it
|
|
2837
|
+
* ({@link ReplayState.reportTool}); undefined leaves the bundle's words as
|
|
2838
|
+
* they always were. Never for another host: its adapter reads no bundle.
|
|
2839
|
+
*/
|
|
2840
|
+
reportToolFor(state) {
|
|
2841
|
+
if (state.host || !state.reportTool)
|
|
2842
|
+
return undefined;
|
|
2843
|
+
try {
|
|
2844
|
+
return state.reportTool() ? REPORT_TOOL_NAME : undefined;
|
|
2845
|
+
}
|
|
2846
|
+
catch {
|
|
2847
|
+
return undefined;
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2771
2850
|
/** Where recorded outputs come from, when they may stand in at all. */
|
|
2772
2851
|
recordedSource(state, force = false) {
|
|
2773
2852
|
if (!force && !this.recordedFallback)
|
|
@@ -2801,6 +2880,37 @@ export class ReplayController {
|
|
|
2801
2880
|
// carries the verdict, so the recording page says why it never runs.
|
|
2802
2881
|
blame: true,
|
|
2803
2882
|
});
|
|
2883
|
+
// The agent's own day may show only now (issue 1212): its host writes a
|
|
2884
|
+
// system prompt's "Today's date is …" just after the prompt hook. Values
|
|
2885
|
+
// read for another day are read again, before the first step runs.
|
|
2886
|
+
if (!opts.adHoc && state.rederive && state.agentDayNow && plan.currentStepIndex === 0) {
|
|
2887
|
+
const now = systemDay(state.agentDayNow());
|
|
2888
|
+
// A new line, unless it says the very day the values were read for. A
|
|
2889
|
+
// line with the day in words is read by the service.
|
|
2890
|
+
if (now && now.line !== state.deriveLine && (now.day === undefined || now.day !== state.deriveDay)) {
|
|
2891
|
+
logLine("replay.rederive", {
|
|
2892
|
+
scenario: state.scenarioId ?? undefined,
|
|
2893
|
+
from: state.deriveDay,
|
|
2894
|
+
to: now.day ?? "said in words",
|
|
2895
|
+
});
|
|
2896
|
+
state.deriveLine = now.line;
|
|
2897
|
+
if (now.day)
|
|
2898
|
+
state.deriveDay = now.day;
|
|
2899
|
+
const targets = targetKeys(plan.paramsSchema);
|
|
2900
|
+
// A reading that did not answer names no target, as at the prompt
|
|
2901
|
+
// (gate 7): never the recorded person or date in its place.
|
|
2902
|
+
const again = state.rederive(now).then((r) => {
|
|
2903
|
+
if (r.derived)
|
|
2904
|
+
return r;
|
|
2905
|
+
const params = { ...r.params };
|
|
2906
|
+
for (const key of targets)
|
|
2907
|
+
params[key] = null;
|
|
2908
|
+
return { ...r, params, missing: [...targets] };
|
|
2909
|
+
});
|
|
2910
|
+
again.then((r) => (state.rederivedMissing = r.missing), () => (state.rederivedMissing = [...targets]));
|
|
2911
|
+
plan.resetParams(again.then((r) => r.params));
|
|
2912
|
+
}
|
|
2913
|
+
}
|
|
2804
2914
|
if (!plan.parametersSettled) {
|
|
2805
2915
|
let failure;
|
|
2806
2916
|
const settled = plan.ready().then(() => true, (err) => {
|
|
@@ -2839,6 +2949,21 @@ export class ReplayController {
|
|
|
2839
2949
|
}
|
|
2840
2950
|
}
|
|
2841
2951
|
}
|
|
2952
|
+
// The second reading left a value unnamed that this plan would act on.
|
|
2953
|
+
const missingAgain = state.rederivedMissing;
|
|
2954
|
+
state.rederivedMissing = undefined;
|
|
2955
|
+
if (missingAgain && !opts.adHoc) {
|
|
2956
|
+
const planned = plan.allEntries().slice(0, plan.stepCount);
|
|
2957
|
+
const blocked = blockingTargets(missingAgain, plan.paramsSchema, planned, plan.paramsLogic);
|
|
2958
|
+
if (blocked.length > 0) {
|
|
2959
|
+
return {
|
|
2960
|
+
ok: false,
|
|
2961
|
+
error: `the value of ${blocked[0]} could not be read from this request for ${state.deriveDay}`,
|
|
2962
|
+
stage: "derive_params",
|
|
2963
|
+
blame: false,
|
|
2964
|
+
};
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2842
2967
|
const sink = opts.adHoc
|
|
2843
2968
|
? undefined
|
|
2844
2969
|
: sinkOfPlan(plan.allEntries().slice(0, plan.stepCount), state.host?.sinks);
|
package/dist/replay/derive.d.ts
CHANGED
|
@@ -38,10 +38,21 @@ export interface LiveCall {
|
|
|
38
38
|
/** Redacted and capped, exactly as the probe sent it. */
|
|
39
39
|
toolInput: string;
|
|
40
40
|
}
|
|
41
|
+
/** The day the agent was told it is (control/transcript.ts `agentDayOf`; issue 1212). */
|
|
42
|
+
export interface AgentDay {
|
|
43
|
+
line: string;
|
|
44
|
+
day?: string;
|
|
45
|
+
source: "system" | "host";
|
|
46
|
+
}
|
|
41
47
|
/** What a turn can tell derivation beyond its prompt (segmented.md R-PARAM-2). */
|
|
42
48
|
export interface DeriveContext {
|
|
43
49
|
liveCall?: LiveCall;
|
|
44
50
|
recentResults?: string[];
|
|
51
|
+
/**
|
|
52
|
+
* The agent's own day, read again each time it is asked: its host writes it
|
|
53
|
+
* into the session only after the prompt hook (issue 1212).
|
|
54
|
+
*/
|
|
55
|
+
agentDay?: () => AgentDay | undefined;
|
|
45
56
|
}
|
|
46
57
|
/**
|
|
47
58
|
* The service, which derives when this runner has no key of its own
|
|
@@ -62,6 +73,8 @@ export interface DeriveOptions extends DeriveContext {
|
|
|
62
73
|
paramsObject: ParamsSchema | null;
|
|
63
74
|
/** The day on this machine. Injected by tests; defaults to {@link localDay}. */
|
|
64
75
|
today?: string;
|
|
76
|
+
/** The words that told the agent its day, when its host showed it any (issue 1212). */
|
|
77
|
+
todaySaid?: string;
|
|
65
78
|
/** An override that keeps the reading on this machine. Absent → the service. */
|
|
66
79
|
apiKey?: string;
|
|
67
80
|
/** Used when there is no `apiKey`. Absent too → recorded samples. */
|
|
@@ -91,6 +104,8 @@ export interface DeriveResult {
|
|
|
91
104
|
missing: string[];
|
|
92
105
|
/** Settings filled from their recorded sample (R-PARAM-2). */
|
|
93
106
|
sampled: string[];
|
|
107
|
+
/** The day the service read the turn's dates from, when it said (issue 1212). */
|
|
108
|
+
dayUsed?: string;
|
|
94
109
|
}
|
|
95
110
|
/**
|
|
96
111
|
* The day on this machine, `YYYY-MM-DD`, in its own time zone.
|
package/dist/replay/derive.js
CHANGED
|
@@ -343,6 +343,10 @@ async function deriveViaService(opts, service, schema, keys) {
|
|
|
343
343
|
// What "tomorrow" is counted from. A service that does not know the
|
|
344
344
|
// field ignores it.
|
|
345
345
|
today: opts.today ?? localDay(),
|
|
346
|
+
// The words that told the agent its day ("Today's date is Thursday,
|
|
347
|
+
// 2023-11-30 …"), which the service turns into the day it reads from
|
|
348
|
+
// (issue 1212). Older services ignore it.
|
|
349
|
+
...(opts.todaySaid ? { todaySaid: opts.todaySaid } : {}),
|
|
346
350
|
}),
|
|
347
351
|
signal: opts.signal ?? timeoutSignal(),
|
|
348
352
|
});
|
|
@@ -402,6 +406,7 @@ async function deriveViaService(opts, service, schema, keys) {
|
|
|
402
406
|
model: body.model,
|
|
403
407
|
missing,
|
|
404
408
|
sampled,
|
|
409
|
+
...(typeof body.today === "string" ? { dayUsed: body.today } : {}),
|
|
405
410
|
};
|
|
406
411
|
}
|
|
407
412
|
//# sourceMappingURL=derive.js.map
|
package/dist/replay/plan.d.ts
CHANGED
|
@@ -24,6 +24,48 @@ import { type FlatEntry } from "./flatten.js";
|
|
|
24
24
|
import type { ReplayMode } from "./coverage.js";
|
|
25
25
|
import type { HandoverStopReason } from "./handover.js";
|
|
26
26
|
import type { ExecutionStage, FallbackKind, ParamsSchema, SerializedScenario, SerializedScenarioStep } from "./types.js";
|
|
27
|
+
/**
|
|
28
|
+
* A value a step of the recording worked out — an address the directory
|
|
29
|
+
* returned, the id a search found; the service labels it `from: "step"` —
|
|
30
|
+
* is never replayed from the recording (issue 1212). The plan holds this mark
|
|
31
|
+
* in its place. A step whose input still holds it, because its earlier steps
|
|
32
|
+
* did not return the value and its code fell back on the parameter, stops the
|
|
33
|
+
* plan in front of it, for the agent; a summary that holds it is left out.
|
|
34
|
+
* Never the recorded e-mail address, never the recorded lead.
|
|
35
|
+
*/
|
|
36
|
+
export declare const FROM_STEP_MARK = "\u2063bir-from-step:";
|
|
37
|
+
/**
|
|
38
|
+
* A value the request did not give, which only the steps of one half of an
|
|
39
|
+
* "if \u2026 otherwise" read (the service's review of calcscenarioautocorrect.md,
|
|
40
|
+
* item 11; targets.ts, `testedOnlyTargets`). The plan arms without it \u2014 the
|
|
41
|
+
* other half needs nothing it lacks \u2014 and holds this mark in its place, never
|
|
42
|
+
* `null` and never the recorded value. A step whose input reads or holds it
|
|
43
|
+
* stops in front of its call, and the agent does that half; a test that reads
|
|
44
|
+
* it decides nothing; a summary that reads it is left out.
|
|
45
|
+
*/
|
|
46
|
+
export declare const MISSING_VALUE_MARK = "\u2063bir-missing:";
|
|
47
|
+
/**
|
|
48
|
+
* A step's code read a value a step works out, which here only the recording
|
|
49
|
+
* holds (issue 1212). Not a fault of the step: its earlier steps did not
|
|
50
|
+
* return the value this time. The plan stops in front of it, the step counts
|
|
51
|
+
* as not run, and the agent does the rest.
|
|
52
|
+
*/
|
|
53
|
+
export declare class RecordedValueError extends Error {
|
|
54
|
+
readonly key: string;
|
|
55
|
+
constructor(key: string, message?: string);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A step's code read a value the request did not give ({@link
|
|
59
|
+
* MISSING_VALUE_MARK}). The same stop as {@link RecordedValueError} \u2014 not a
|
|
60
|
+
* fault of the step: it counts as not run, nothing is parked or repaired, and
|
|
61
|
+
* the agent does the rest \u2014 so it is one, and every place that tells that
|
|
62
|
+
* stop apart tells this one apart too. Its words name the value.
|
|
63
|
+
*/
|
|
64
|
+
export declare class MissingValueError extends RecordedValueError {
|
|
65
|
+
constructor(key: string);
|
|
66
|
+
}
|
|
67
|
+
/** The value a mark stands for, when `value` holds one anywhere \u2014 either kind. */
|
|
68
|
+
export declare function markedKey(value: unknown): string | undefined;
|
|
27
69
|
/**
|
|
28
70
|
* Runs one step's tool and returns its output as a string.
|
|
29
71
|
*
|
|
@@ -76,6 +118,14 @@ export interface DriveOptions {
|
|
|
76
118
|
* so what the run reports about it is the truth.
|
|
77
119
|
*/
|
|
78
120
|
signal?: AbortSignal;
|
|
121
|
+
/**
|
|
122
|
+
* The tool the model may call although the bundle says to call none: `bir`'s
|
|
123
|
+
* own `mcp__bir__report_wrong_result`, when the session has it (the service's
|
|
124
|
+
* review of calcscenarioautocorrect.md, item 19). Set by the caller only
|
|
125
|
+
* where the `bir` server is connected; absent, the bundle's words are as
|
|
126
|
+
* they always were (bundle.ts, `AssembleOptions.reportTool`).
|
|
127
|
+
*/
|
|
128
|
+
reportTool?: string;
|
|
79
129
|
}
|
|
80
130
|
/**
|
|
81
131
|
* Supplies a step's recorded output when its tool cannot run here (§8.1).
|
|
@@ -289,7 +339,17 @@ export declare class ScenarioReplayPlan {
|
|
|
289
339
|
private readonly scenario;
|
|
290
340
|
/** The flat list this plan walks. One entry per step that will really run. */
|
|
291
341
|
private readonly entries;
|
|
292
|
-
private
|
|
342
|
+
private paramsPromise;
|
|
343
|
+
/** The values a step worked out in the recording ({@link FROM_STEP_MARK}). */
|
|
344
|
+
private readonly fromStep;
|
|
345
|
+
/**
|
|
346
|
+
* The targets only the steps of one half read (targets.ts,
|
|
347
|
+
* `testedOnlyTargets`): each held as {@link MISSING_VALUE_MARK} when the
|
|
348
|
+
* request does not give it.
|
|
349
|
+
*/
|
|
350
|
+
private readonly oneHalf;
|
|
351
|
+
/** Of {@link oneHalf}, the ones the request did not give: held as the mark now. */
|
|
352
|
+
private missingMarked;
|
|
293
353
|
private params;
|
|
294
354
|
/** The derivation's own answer, before `paramsLogic`. What safety.ts judges. */
|
|
295
355
|
private derivedParams;
|
|
@@ -385,6 +445,12 @@ export declare class ScenarioReplayPlan {
|
|
|
385
445
|
* throws.
|
|
386
446
|
*/
|
|
387
447
|
useFallbackParams(): void;
|
|
448
|
+
/**
|
|
449
|
+
* The values read again, before any step ran (issue 1212): the agent's own
|
|
450
|
+
* day showed in the session only after the first reading. False once a step
|
|
451
|
+
* has run, when the values the steps ran on are the ones that stand.
|
|
452
|
+
*/
|
|
453
|
+
resetParams(params: Promise<Record<string, unknown>>): boolean;
|
|
388
454
|
/** Whether the parameters are final. */
|
|
389
455
|
get parametersSettled(): boolean;
|
|
390
456
|
/** The derivation's own values, before `paramsLogic`. Empty until settled. */
|
|
@@ -409,6 +475,21 @@ export declare class ScenarioReplayPlan {
|
|
|
409
475
|
currentEntry(): FlatEntry | undefined;
|
|
410
476
|
/** The parameters in force. Empty until {@link ready} resolves. */
|
|
411
477
|
get parameters(): Readonly<Record<string, unknown>>;
|
|
478
|
+
/**
|
|
479
|
+
* The values a body may not use: a value a step works out ({@link
|
|
480
|
+
* FROM_STEP_MARK}) and a value the request did not give ({@link
|
|
481
|
+
* MISSING_VALUE_MARK}). A read of one is the stop {@link valueError} names.
|
|
482
|
+
*/
|
|
483
|
+
private watchedKeys;
|
|
484
|
+
/** The stop a read of `key` means: a value the request did not give, or one only the recording had. */
|
|
485
|
+
private valueError;
|
|
486
|
+
/**
|
|
487
|
+
* `parameters` for one body, with every read of a value a step works out
|
|
488
|
+
* noted (issue 1212): a read is the recorded value used, however the code
|
|
489
|
+
* changes it afterwards — upper-cased, encoded, sliced or counted. A value
|
|
490
|
+
* the request did not give is watched the same way (review item 11).
|
|
491
|
+
*/
|
|
492
|
+
private watched;
|
|
412
493
|
/** Everything the steps have accumulated so far. */
|
|
413
494
|
get accumulated(): Readonly<Record<string, unknown>>;
|
|
414
495
|
/** The scenario's parameter schema — what the target and safety checks judge. */
|
|
@@ -439,6 +520,14 @@ export declare class ScenarioReplayPlan {
|
|
|
439
520
|
* a throw as divergence.
|
|
440
521
|
*/
|
|
441
522
|
toolInputForCurrentStep(): Record<string, unknown>;
|
|
523
|
+
/**
|
|
524
|
+
* A step's input, refused when it holds a value only the recording had: its
|
|
525
|
+
* code fell back on a parameter a step works out, and the earlier steps did
|
|
526
|
+
* not return it (issue 1212). The caller stops the plan in front of it. So
|
|
527
|
+
* is one that reads, or holds, a value the request did not give (review
|
|
528
|
+
* item 11): {@link MissingValueError}.
|
|
529
|
+
*/
|
|
530
|
+
private inputOf;
|
|
442
531
|
/** Whether the plan's cursor rests in front of the step it is parked before. */
|
|
443
532
|
atStop(): boolean;
|
|
444
533
|
/**
|