@basein/runner 0.3.17 → 0.3.19
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-hooks.d.ts +11 -8
- package/dist/bin/bir-hooks.js +11 -8
- package/dist/bin/bir-scenario.d.ts +5 -1
- package/dist/bin/bir-scenario.js +155 -5
- package/dist/bin/bir.js +22 -9
- package/dist/bin/investigate.d.ts +9 -0
- package/dist/bin/investigate.js +26 -12
- package/dist/bin/scenario-edit.d.ts +7 -0
- package/dist/bin/scenario-edit.js +19 -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/recorder-main.d.ts +15 -0
- package/dist/control/recorder-main.js +33 -8
- package/dist/control/server.d.ts +192 -13
- package/dist/control/server.js +819 -41
- 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 +156 -2
- 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/condition-words.d.ts +28 -0
- package/dist/replay/condition-words.js +59 -0
- package/dist/replay/controller.d.ts +78 -7
- package/dist/replay/controller.js +318 -62
- package/dist/replay/derive.d.ts +15 -0
- package/dist/replay/derive.js +5 -0
- package/dist/replay/handover.d.ts +7 -0
- package/dist/replay/handover.js +89 -51
- package/dist/replay/plan.d.ts +101 -5
- package/dist/replay/plan.js +260 -18
- 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 +25 -8
- package/docs/calculatedReplay.md +45 -5
- package/docs/calculatedReplayGuide.md +13 -4
- package/package.json +1 -1
- package/production.md +21 -7
|
@@ -49,9 +49,14 @@
|
|
|
49
49
|
* only with enough of the budget left.
|
|
50
50
|
*
|
|
51
51
|
* STDOUT IS CONTEXT. For SessionStart, Claude Code adds whatever a command hook
|
|
52
|
-
* prints on stdout to the model's context
|
|
53
|
-
*
|
|
54
|
-
* is the answer,
|
|
52
|
+
* prints on stdout to the model's context — unless it is one JSON object, which
|
|
53
|
+
* it reads as the hook's answer instead. So nothing is printed unless the
|
|
54
|
+
* control server answered with something, and then it is the answer, as one
|
|
55
|
+
* line of JSON and nothing else. The control server answers `{}`, or — when
|
|
56
|
+
* plans of the account wait for their owner (the service's review of
|
|
57
|
+
* calcscenarioautocorrect.md, item 8) — `{ "systemMessage": "bir: …" }`, a
|
|
58
|
+
* line Claude Code shows the person and never the model. Characters past ASCII
|
|
59
|
+
* are written as `\u` escapes, so a console code page cannot garble the line.
|
|
55
60
|
*/
|
|
56
61
|
import { type EnsureOptions } from "./daemon.js";
|
|
57
62
|
/**
|
|
@@ -93,6 +98,12 @@ export interface EnsureHookOptions extends EnsureOptions {
|
|
|
93
98
|
*/
|
|
94
99
|
overrideCheck?: ((projectCwd: string) => StaleOverrides) | false;
|
|
95
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* `value` as one line of JSON whose every character past ASCII is a `\u`
|
|
103
|
+
* escape: the same JSON to any reader, and nothing a console's code page can
|
|
104
|
+
* turn into something else on the way to Claude Code.
|
|
105
|
+
*/
|
|
106
|
+
export declare function asciiJson(value: unknown): string;
|
|
96
107
|
/**
|
|
97
108
|
* Run the hook for `cwd`. Resolves the exit code, which is always 0.
|
|
98
109
|
*/
|
|
@@ -49,9 +49,14 @@
|
|
|
49
49
|
* only with enough of the budget left.
|
|
50
50
|
*
|
|
51
51
|
* STDOUT IS CONTEXT. For SessionStart, Claude Code adds whatever a command hook
|
|
52
|
-
* prints on stdout to the model's context
|
|
53
|
-
*
|
|
54
|
-
* is the answer,
|
|
52
|
+
* prints on stdout to the model's context — unless it is one JSON object, which
|
|
53
|
+
* it reads as the hook's answer instead. So nothing is printed unless the
|
|
54
|
+
* control server answered with something, and then it is the answer, as one
|
|
55
|
+
* line of JSON and nothing else. The control server answers `{}`, or — when
|
|
56
|
+
* plans of the account wait for their owner (the service's review of
|
|
57
|
+
* calcscenarioautocorrect.md, item 8) — `{ "systemMessage": "bir: …" }`, a
|
|
58
|
+
* line Claude Code shows the person and never the model. Characters past ASCII
|
|
59
|
+
* are written as `\u` escapes, so a console code page cannot garble the line.
|
|
55
60
|
*/
|
|
56
61
|
import { appendFileSync } from "node:fs";
|
|
57
62
|
import { Console } from "node:console";
|
|
@@ -152,6 +157,14 @@ function reportStaleOverrides(projectCwd, logFile, msLeft, check) {
|
|
|
152
157
|
/* a check that failed leaves things as they were; `bir doctor` names what is stale */
|
|
153
158
|
}
|
|
154
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* `value` as one line of JSON whose every character past ASCII is a `\u`
|
|
162
|
+
* escape: the same JSON to any reader, and nothing a console's code page can
|
|
163
|
+
* turn into something else on the way to Claude Code.
|
|
164
|
+
*/
|
|
165
|
+
export function asciiJson(value) {
|
|
166
|
+
return JSON.stringify(value).replace(/[\u007f-]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
167
|
+
}
|
|
155
168
|
/** True when this process's own environment switches the runner off (`BIR_OFF=1` or `true`). */
|
|
156
169
|
function offInThisEnvironment() {
|
|
157
170
|
const value = (process.env.BIR_OFF ?? "").trim().toLowerCase();
|
|
@@ -228,8 +241,8 @@ export async function runEnsureHook(cwd, opts = {}) {
|
|
|
228
241
|
signal: timeoutSignal(Math.max(300, Math.min(RELAY_TIMEOUT_MS, left()))),
|
|
229
242
|
});
|
|
230
243
|
const answer = (await res.json().catch(() => ({})));
|
|
231
|
-
if (res.ok && answer && typeof answer === "object" && Object.keys(answer).length > 0) {
|
|
232
|
-
stdout.write(
|
|
244
|
+
if (res.ok && answer && typeof answer === "object" && !Array.isArray(answer) && Object.keys(answer).length > 0) {
|
|
245
|
+
stdout.write(asciiJson(answer));
|
|
233
246
|
}
|
|
234
247
|
}
|
|
235
248
|
catch (err) {
|
|
@@ -52,6 +52,21 @@ export declare function derivationKey(daemon?: boolean): {
|
|
|
52
52
|
apiKey?: string;
|
|
53
53
|
source?: string;
|
|
54
54
|
};
|
|
55
|
+
/**
|
|
56
|
+
* `BIR_SEGMENT_ARM`: whether a segment the service hands out may run mid-task.
|
|
57
|
+
* On unless it is `0`, from runner 0.3.19 (the service's segmentsbreakdown.md
|
|
58
|
+
* SB-21): segments found by repeated work, and the halves after a plan's
|
|
59
|
+
* decision. `0` is observe-only: what would have armed is logged, and nothing
|
|
60
|
+
* is replaced. While it is on, whole plans may start mid-task by intent too:
|
|
61
|
+
* `BIR_INTENT_ARM` follows it unless that is set.
|
|
62
|
+
*/
|
|
63
|
+
export declare function segmentArmFromEnv(env?: NodeJS.ProcessEnv): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* What the `replay.enabled` startup line says segments do. A segment starts
|
|
66
|
+
* only where the probe is waited on, so `BIR_INTENT_ARM=0` starts nothing
|
|
67
|
+
* mid-task, segments included — the rule `bir doctor` words from /health.
|
|
68
|
+
*/
|
|
69
|
+
export declare function segmentsAtStartup(segmentArm: boolean, env?: NodeJS.ProcessEnv): string;
|
|
55
70
|
/** Where the two replay switches came from, for `/health` and `bir doctor`. */
|
|
56
71
|
export type ReplaySource = "env" | "sidecar" | "default";
|
|
57
72
|
/** What a recorder still serves (K4, `ControlServer.activity()`). */
|
|
@@ -152,6 +152,27 @@ export function derivationKey(daemon = process.env[DAEMON_ENV] === "1") {
|
|
|
152
152
|
}
|
|
153
153
|
return {};
|
|
154
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* `BIR_SEGMENT_ARM`: whether a segment the service hands out may run mid-task.
|
|
157
|
+
* On unless it is `0`, from runner 0.3.19 (the service's segmentsbreakdown.md
|
|
158
|
+
* SB-21): segments found by repeated work, and the halves after a plan's
|
|
159
|
+
* decision. `0` is observe-only: what would have armed is logged, and nothing
|
|
160
|
+
* is replaced. While it is on, whole plans may start mid-task by intent too:
|
|
161
|
+
* `BIR_INTENT_ARM` follows it unless that is set.
|
|
162
|
+
*/
|
|
163
|
+
export function segmentArmFromEnv(env = process.env) {
|
|
164
|
+
return env.BIR_SEGMENT_ARM !== "0";
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* What the `replay.enabled` startup line says segments do. A segment starts
|
|
168
|
+
* only where the probe is waited on, so `BIR_INTENT_ARM=0` starts nothing
|
|
169
|
+
* mid-task, segments included — the rule `bir doctor` words from /health.
|
|
170
|
+
*/
|
|
171
|
+
export function segmentsAtStartup(segmentArm, env = process.env) {
|
|
172
|
+
if (!segmentArm)
|
|
173
|
+
return "observed only (BIR_SEGMENT_ARM=0)";
|
|
174
|
+
return env.BIR_INTENT_ARM === "0" ? "observed only (BIR_INTENT_ARM=0)" : "run mid-task";
|
|
175
|
+
}
|
|
155
176
|
/**
|
|
156
177
|
* Assemble the replay configuration (docs/calculatedReplay.md §5.3 of the guide).
|
|
157
178
|
*
|
|
@@ -204,19 +225,21 @@ function buildReplayOptions(keeper, policy, key) {
|
|
|
204
225
|
intentMatch: {
|
|
205
226
|
enabled: process.env.BIR_INTENT_MATCH !== "0",
|
|
206
227
|
// The probe's own ceiling, not a wait on the hook's path: `PreToolUse`
|
|
207
|
-
//
|
|
208
|
-
//
|
|
228
|
+
// waits for it only while arming is on — the default, unless
|
|
229
|
+
// BIR_SEGMENT_ARM=0 or BIR_INTENT_ARM=0 — and then at most
|
|
209
230
|
// BIR_INTENT_ARM_BUDGET_MS (500 ms), never while the service is failing
|
|
210
|
-
// (control/server.ts)
|
|
211
|
-
//
|
|
212
|
-
// 2 500 ms
|
|
231
|
+
// (control/server.ts); otherwise it answers without it (hit counting
|
|
232
|
+
// only). 4 000 leaves a request whose best segment lands in the
|
|
233
|
+
// not-clear band its one live question under the service's own 2 500 ms
|
|
234
|
+
// attempt (segmented.md R-HIT-11).
|
|
213
235
|
budgetMs: positiveInt(process.env.BIR_INTENT_MATCH_BUDGET_MS, 4_000),
|
|
214
236
|
maxPerTurn: positiveInt(process.env.BIR_INTENT_MATCHES_PER_TURN, 3),
|
|
215
237
|
maxRequestsPerTurn: positiveInt(process.env.BIR_INTENT_REQUESTS_PER_TURN, 40),
|
|
216
238
|
},
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
|
|
239
|
+
// On by default from 0.3.19 (the service's segmentsbreakdown.md SB-21): a
|
|
240
|
+
// plan that stops at its decision hands the rest to segments of each half,
|
|
241
|
+
// and they run only mid-task. BIR_SEGMENT_ARM=0 brings back observe-only.
|
|
242
|
+
segmentArm: segmentArmFromEnv(),
|
|
220
243
|
// Both read live, never captured (C5). The recorder signs in after it
|
|
221
244
|
// listens, refreshes the token as the session outlives it, and may sign
|
|
222
245
|
// in or out while it runs; replay reads whatever holds *now*. The old
|
|
@@ -247,6 +270,8 @@ function buildReplayOptions(keeper, policy, key) {
|
|
|
247
270
|
? "the service"
|
|
248
271
|
: "recorded sample values — sign in, or a scenario with a target will not run"),
|
|
249
272
|
intentMatch: opts.intentMatch?.enabled ? "on" : "off",
|
|
273
|
+
// Whether a segment the service hands out runs, or is only logged.
|
|
274
|
+
segments: segmentsAtStartup(opts.segmentArm === true),
|
|
250
275
|
source,
|
|
251
276
|
why: "a prompt that matches a calculated scenario runs it: the scenario's own steps run without a " +
|
|
252
277
|
"permission prompt of their own (never in plan mode); every other tool call is asked about as " +
|
package/dist/control/server.d.ts
CHANGED
|
@@ -24,9 +24,26 @@
|
|
|
24
24
|
* accepts unauthenticated step reports is a local exfiltration channel.
|
|
25
25
|
*/
|
|
26
26
|
import { type IntentSource } from "./transcript.js";
|
|
27
|
-
import { type Recorder } from "../record/recorder.js";
|
|
27
|
+
import { type AttentionPlan, type Recorder } from "../record/recorder.js";
|
|
28
28
|
import { type ReplayOptions } from "../replay/controller.js";
|
|
29
29
|
import { type ServiceHealth } from "../util/service-health.js";
|
|
30
|
+
/**
|
|
31
|
+
* The project a run or a tool list belongs to (the service's review of
|
|
32
|
+
* calcscenarioautocorrect.md, item 16): the first 16 hex characters of the
|
|
33
|
+
* sha256 of its folder, made absolute and — on Windows — lower-cased with
|
|
34
|
+
* forward slashes, as the discovery file's key is (paths.ts, `controlKey`).
|
|
35
|
+
* The service only compares it, so a plan's recording finds its own
|
|
36
|
+
* project's tools and never another project's server of the same name.
|
|
37
|
+
*/
|
|
38
|
+
export declare function projectKey(dir: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* The one line a session start shows the person (review item 8): which plan
|
|
41
|
+
* waits, for how long, why, and where to look —
|
|
42
|
+
* `bir: a plan needs you — "Check engaged users and reassign leads" held for 3 days, a correction is waiting: <url>`
|
|
43
|
+
* — and with more than one, how many, and the first one's page. A plan that
|
|
44
|
+
* is not held, whose correction waits, says only that.
|
|
45
|
+
*/
|
|
46
|
+
export declare function attentionText(plans: readonly AttentionPlan[], now?: number): string | undefined;
|
|
30
47
|
/**
|
|
31
48
|
* The prompt match gate (see {@link ControlServer.armFromMatch}). A match that
|
|
32
49
|
* answered slower than `slowMs` (`BIR_MATCH_SLOW_MS`), or not inside its
|
|
@@ -259,12 +276,13 @@ export interface ControlServerOptions {
|
|
|
259
276
|
* (fallbk.md §Runner 4).
|
|
260
277
|
*
|
|
261
278
|
* Arming there means *waiting* there, on every unsteered tool call, for a
|
|
262
|
-
* service round trip
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
279
|
+
* service round trip. It waits (at most `BIR_INTENT_ARM_BUDGET_MS`, 500 ms,
|
|
280
|
+
* and never while the service is failing) when segment arming is on — the
|
|
281
|
+
* recorder's default from 0.3.19, `BIR_SEGMENT_ARM` unset or `1` — or when
|
|
282
|
+
* `BIR_INTENT_ARM=1` asks for whole-scenario intent arming. `BIR_INTENT_ARM=0`
|
|
283
|
+
* never waits. Otherwise, as in a server built with neither (a test, an
|
|
284
|
+
* embedder), the probe is sent without waiting, for hit counting only, and
|
|
285
|
+
* nothing arms mid-turn.
|
|
268
286
|
*/
|
|
269
287
|
intentArm?: boolean;
|
|
270
288
|
/**
|
|
@@ -311,6 +329,20 @@ export declare class ControlServer {
|
|
|
311
329
|
private readonly proxySessions;
|
|
312
330
|
/** `run_scenario` pres not yet consumed by a `/scenario/run`, oldest first. */
|
|
313
331
|
private directCalls;
|
|
332
|
+
/**
|
|
333
|
+
* `report_wrong_result` pres not yet consumed by a `/scenario/dispute`,
|
|
334
|
+
* oldest first (review item 19): how a report from `bir-scenario`, which is
|
|
335
|
+
* never told its session, finds the session — and so the plan — it is about.
|
|
336
|
+
*/
|
|
337
|
+
private reportCalls;
|
|
338
|
+
/** Plans the agent said were wrong, and the service's answer — on its way, or in. */
|
|
339
|
+
private readonly disputed;
|
|
340
|
+
/**
|
|
341
|
+
* The plans that need their owner, by account, as the service last listed
|
|
342
|
+
* them (`GET /scenarios/attention`, review item 8), and the ask still on its
|
|
343
|
+
* way. Null is "nothing can be said": no service, an older one, a failure.
|
|
344
|
+
*/
|
|
345
|
+
private readonly attention;
|
|
314
346
|
/** Plans a `/scenario/run` is executing right now: one run per plan. */
|
|
315
347
|
private readonly runningPlans;
|
|
316
348
|
/**
|
|
@@ -572,6 +604,16 @@ export declare class ControlServer {
|
|
|
572
604
|
*/
|
|
573
605
|
private ensureRun;
|
|
574
606
|
private runMetadata;
|
|
607
|
+
/**
|
|
608
|
+
* The project key of everything this recorder sends (review item 16): its
|
|
609
|
+
* runs and its tool lists. The folder this recorder serves — the one its
|
|
610
|
+
* discovery file is keyed by and its hooks are installed in — and not a
|
|
611
|
+
* session's `cwd`: that follows the agent's `cd` from turn to turn, and a
|
|
612
|
+
* tool list is sent when its proxy starts, before any of its calls ties it
|
|
613
|
+
* to a session. The service matches a plan's recording to its tools by
|
|
614
|
+
* equality, so both sides must hash the same folder.
|
|
615
|
+
*/
|
|
616
|
+
private projectKeyHere;
|
|
575
617
|
/**
|
|
576
618
|
* A similar-prompt hit means the service created no run, so every later step
|
|
577
619
|
* post would 404. Stop recording it — that half is v1 and is mandatory, and
|
|
@@ -668,6 +710,16 @@ export declare class ControlServer {
|
|
|
668
710
|
* is none, and a `bir-scenario` must have proved it serves the tool.
|
|
669
711
|
*/
|
|
670
712
|
private deliveryToolAvailable;
|
|
713
|
+
/**
|
|
714
|
+
* Whether a running `bir-scenario` here serves `report_wrong_result` right
|
|
715
|
+
* now (review item 19): one that is not off said so in its hello. What a
|
|
716
|
+
* bundle delivered beside a call of the agent's own (a divergence) is laid
|
|
717
|
+
* out by: such a bundle forbids every tool call but this one. A direct
|
|
718
|
+
* plan's bundle goes by its own `bir-scenario`'s word instead, which came
|
|
719
|
+
* with its `/scenario/run` (see {@link onScenarioRun}). Configured is not
|
|
720
|
+
* connected, as for the delivery tool.
|
|
721
|
+
*/
|
|
722
|
+
private reportToolServed;
|
|
671
723
|
/**
|
|
672
724
|
* Whether this project's configuration has the `bir` server, as far as
|
|
673
725
|
* anything here knows: a hook that named one of its tools, the caller's
|
|
@@ -681,6 +733,25 @@ export declare class ControlServer {
|
|
|
681
733
|
* only — no other I/O.
|
|
682
734
|
*/
|
|
683
735
|
private liveHellos;
|
|
736
|
+
/**
|
|
737
|
+
* The tool list of each wrapped server last sent to the service, by
|
|
738
|
+
* account, project and server (AC12; review item 16): its hash, when, and
|
|
739
|
+
* whether the service took it (null while the send is on its way).
|
|
740
|
+
*/
|
|
741
|
+
private readonly toolListsSent;
|
|
742
|
+
/**
|
|
743
|
+
* `POST /proxy/tools` — a proxy's server listed its tools (`tools/list`;
|
|
744
|
+
* the service's autocorrect.md AC12). Its names, descriptions, input
|
|
745
|
+
* schemas and what it says of each tool (`annotations`) go to the service —
|
|
746
|
+
* secret-shaped text taken out, and within what the service keeps — with
|
|
747
|
+
* the project they are of ({@link projectKeyHere}, the key every run here
|
|
748
|
+
* carries). Sent when the list changed since that server's last one for
|
|
749
|
+
* this account and project, when the last send failed ten minutes ago, or
|
|
750
|
+
* six hours after the last one the service took. `bir off`, and a session
|
|
751
|
+
* started with BIR_OFF=1, send nothing, as for a step. Always `{ ok: true }`;
|
|
752
|
+
* never slow.
|
|
753
|
+
*/
|
|
754
|
+
private onProxyTools;
|
|
684
755
|
/**
|
|
685
756
|
* `POST /scenario/hello` — a running `bir-scenario` saying what it serves
|
|
686
757
|
* (K3): on `initialize`, on `tools/list`, when its off state flips and every
|
|
@@ -689,6 +760,42 @@ export declare class ControlServer {
|
|
|
689
760
|
* and is not off still runs. Always `{ ok: true }`; never slow.
|
|
690
761
|
*/
|
|
691
762
|
private onScenarioHello;
|
|
763
|
+
/** Remember a `report_wrong_result` pre (see {@link reportCalls}): a few, and only for a while. */
|
|
764
|
+
private noteReportCall;
|
|
765
|
+
/**
|
|
766
|
+
* `POST /scenario/dispute` — the agent said, through `bir`'s
|
|
767
|
+
* `report_wrong_result`, that a replay's results do not answer its request
|
|
768
|
+
* (the service's review of calcscenarioautocorrect.md, item 19): the plan
|
|
769
|
+
* took the wrong half of an "if … otherwise", or acted on the wrong item. A
|
|
770
|
+
* wrong half is caught only when the agent says so, and until now there was
|
|
771
|
+
* no way to say it but in an answer nobody might read.
|
|
772
|
+
*
|
|
773
|
+
* WHOSE PLAN. The session is the one whose `PreToolUse` for the tool carried
|
|
774
|
+
* the request's `toolUseId` (`bir-scenario` forwards the host's id for the
|
|
775
|
+
* call, as for `run_scenario`); without one, the one session where such a
|
|
776
|
+
* call is waiting; without that either, the one session whose plan ran in
|
|
777
|
+
* the last half hour. Never a guess between two. The plan is the newest one
|
|
778
|
+
* that ran in that session's latest turn with a plan: this turn's, or the
|
|
779
|
+
* one before it.
|
|
780
|
+
*
|
|
781
|
+
* WHAT GOES. `POST /scenarios/:scenarioId/dispute` with the reason, `by:
|
|
782
|
+
* "agent"`, and the turn's execution ticket as `executionId` — the id its
|
|
783
|
+
* report books under when the turn ends, so the service may well have the
|
|
784
|
+
* ticket and not yet the row. Once per plan and turn: a second report of the
|
|
785
|
+
* same plan is answered from the first. Nothing here undoes anything.
|
|
786
|
+
*
|
|
787
|
+
* Answers `{ ok, held?, why? }` for `bir-scenario` to put in one sentence.
|
|
788
|
+
* Never throws, and is never slow beyond the service's own bound.
|
|
789
|
+
*/
|
|
790
|
+
private onScenarioDispute;
|
|
791
|
+
/** The session a `/scenario/dispute` is about (see {@link onScenarioDispute}), or undefined. */
|
|
792
|
+
private sessionForDispute;
|
|
793
|
+
/**
|
|
794
|
+
* The plan a report of a wrong replay is about: the newest that ran — a
|
|
795
|
+
* step of it did its work — in the session's latest turn with one, this
|
|
796
|
+
* turn or the one before it.
|
|
797
|
+
*/
|
|
798
|
+
private disputedPlan;
|
|
692
799
|
/**
|
|
693
800
|
* Re-read whether this project configures the `bir` server — only when
|
|
694
801
|
* ~/.claude.json or .mcp.json changed since the last read. A file the host is
|
|
@@ -713,6 +820,20 @@ export declare class ControlServer {
|
|
|
713
820
|
* not Claude Code, and undefined when it is.
|
|
714
821
|
*/
|
|
715
822
|
private hostContext;
|
|
823
|
+
/**
|
|
824
|
+
* The day this session's agent was told it is (issue 1212), read from its
|
|
825
|
+
* transcript each time it is asked. A session of another host has none.
|
|
826
|
+
*/
|
|
827
|
+
private agentDayFor;
|
|
828
|
+
/**
|
|
829
|
+
* What a run's finish says of its agent's day (the service's review of
|
|
830
|
+
* calcscenarioautocorrect.md, item 1): the line of the session's system
|
|
831
|
+
* prompt that gives the date — never Claude Code's own date reminder, which
|
|
832
|
+
* is only this machine's day — and this machine's day when the turn's prompt
|
|
833
|
+
* came. The service checks a corrected plan against this run, and reads its
|
|
834
|
+
* prompt with this day, as a replay would have. Undefined with neither.
|
|
835
|
+
*/
|
|
836
|
+
private runAgentDay;
|
|
716
837
|
/**
|
|
717
838
|
* The earlier tool results the reading of new values may look at: this
|
|
718
839
|
* prompt's own, from the transcript — and so none for a plan that is
|
|
@@ -801,6 +922,20 @@ export declare class ControlServer {
|
|
|
801
922
|
/** Transcript cost since `mark`; unmeasured (and zero) without one, or with a model that has no price. */
|
|
802
923
|
private costSince;
|
|
803
924
|
private reportExecution;
|
|
925
|
+
/**
|
|
926
|
+
* The plan's own calls of the turn, whole, as an answered turn's report
|
|
927
|
+
* carries them (the service's review of calcscenarioautocorrect.md, item
|
|
928
|
+
* 12): what each step sent and what came back, as they were kept for the
|
|
929
|
+
* turn (replay/controller.ts, `TurnCall`) — in a recording's own form,
|
|
930
|
+
* redacted and capped at 64 KiB apiece, as a redo's copies are (AC2) —
|
|
931
|
+
* where the report's own copies have 3,800 bytes. The calls of a called sub-task are
|
|
932
|
+
* left out: their step numbers are the sub-task's own, and would read as the
|
|
933
|
+
* plan's steps of the same number. `kept` is what the turn kept, taken while
|
|
934
|
+
* the seal still had it; this runs after the answer's wait, off the hook's
|
|
935
|
+
* path. The recorder cuts them to what one report may carry when it sends
|
|
936
|
+
* them.
|
|
937
|
+
*/
|
|
938
|
+
private answerCallsOf;
|
|
804
939
|
/**
|
|
805
940
|
* Seal the session's run now, and drain it to the service in the background.
|
|
806
941
|
*
|
|
@@ -831,6 +966,26 @@ export declare class ControlServer {
|
|
|
831
966
|
*/
|
|
832
967
|
private drainRun;
|
|
833
968
|
private onSessionStart;
|
|
969
|
+
/**
|
|
970
|
+
* The line a session start shows the person when plans of this account
|
|
971
|
+
* wait for their owner (`GET /scenarios/attention`; the service's review of
|
|
972
|
+
* calcscenarioautocorrect.md, item 8), or undefined. A `systemMessage`:
|
|
973
|
+
* Claude Code shows it to the person and adds nothing to the model's
|
|
974
|
+
* context. Asked at most once in {@link ATTENTION_CACHE_MS} per account (in
|
|
975
|
+
* {@link ATTENTION_RETRY_MS} when it could say nothing), waited for at most
|
|
976
|
+
* {@link ATTENTION_WAIT_MS}, and never while the service is failing; any
|
|
977
|
+
* failure says nothing. Not after a compaction — the
|
|
978
|
+
* session is mid-work, and was told at its start — and never in a session
|
|
979
|
+
* of another host, whose adapter shows a person nothing.
|
|
980
|
+
*/
|
|
981
|
+
private attentionLine;
|
|
982
|
+
/**
|
|
983
|
+
* This account's plans that need their owner: the cached answer while it is
|
|
984
|
+
* fresh, else the service's, waited for no longer than
|
|
985
|
+
* {@link ATTENTION_WAIT_MS}. An answer that comes later still fills the
|
|
986
|
+
* cache for the next session start. One ask at a time per account.
|
|
987
|
+
*/
|
|
988
|
+
private attentionFor;
|
|
834
989
|
private onPrompt;
|
|
835
990
|
/**
|
|
836
991
|
* `PreToolUse`. Two shapes of answer:
|
|
@@ -1000,14 +1155,19 @@ export declare class ControlServer {
|
|
|
1000
1155
|
*/
|
|
1001
1156
|
private excludeRunsFor;
|
|
1002
1157
|
/**
|
|
1003
|
-
* Per
|
|
1004
|
-
* (segmented.md R-OUT-6).
|
|
1158
|
+
* Per plan of this turn, its recording and how far the plan got in its own
|
|
1159
|
+
* chain (segmented.md R-OUT-6).
|
|
1005
1160
|
*
|
|
1006
1161
|
* The server uses it to refuse a segment that starts *before* where this turn
|
|
1007
1162
|
* already is: re-running steps the turn has just done is worse than not
|
|
1008
|
-
* replaying at all. The
|
|
1009
|
-
*
|
|
1010
|
-
*
|
|
1163
|
+
* replaying at all. The position is the plan's own: the step it handed over
|
|
1164
|
+
* at (its decision included), or its last step when it ran to its end. The
|
|
1165
|
+
* server maps it onto the recording — a segment's first position, a
|
|
1166
|
+
* decision's step before it — and takes the largest per recording (the
|
|
1167
|
+
* service's segmentsbreakdown.md D18). One entry per plan, so that two plans
|
|
1168
|
+
* of one recording, whose own positions are on different scales, never
|
|
1169
|
+
* hide each other. A plan declined for anything but a known-bad first step
|
|
1170
|
+
* reports nothing — it ran none of the recording, so it blocks none of it.
|
|
1011
1171
|
*
|
|
1012
1172
|
* Rebuilt on every probe rather than cached: a plan that hands over between
|
|
1013
1173
|
* two calls changes the answer.
|
|
@@ -1058,6 +1218,16 @@ export declare class ControlServer {
|
|
|
1058
1218
|
* whose intent-armed plan handed over is recording the model's work anyway.
|
|
1059
1219
|
*/
|
|
1060
1220
|
private noteHandover;
|
|
1221
|
+
/**
|
|
1222
|
+
* Drop a fragment scheduled at a decision (the service's
|
|
1223
|
+
* segmentsbreakdown.md SB-16) when a plan the intent check armed takes the
|
|
1224
|
+
* agent's next call: what follows is that plan's half, not the other one,
|
|
1225
|
+
* and recorded as the other half it would become a wrong segment C. Cleared
|
|
1226
|
+
* rather than ended, so a later hand-over of that plan schedules its own
|
|
1227
|
+
* fragment, as any plan's does in a turn with none. Any other fragment is
|
|
1228
|
+
* left as it is.
|
|
1229
|
+
*/
|
|
1230
|
+
private dropDecisionFragment;
|
|
1061
1231
|
/**
|
|
1062
1232
|
* Open the fragment run and record from this call on (fallbk.md D7).
|
|
1063
1233
|
*
|
|
@@ -1353,7 +1523,16 @@ export declare class ControlServer {
|
|
|
1353
1523
|
private soleCandidate;
|
|
1354
1524
|
/** Record the merged pair for a correlation and latch it against re-entry. */
|
|
1355
1525
|
private settle;
|
|
1356
|
-
/**
|
|
1526
|
+
/**
|
|
1527
|
+
* The one place a tool step pair is written. Redaction and caps live here.
|
|
1528
|
+
*
|
|
1529
|
+
* Both rows carry the call's id (`metadata.callId`, review item 7) — the
|
|
1530
|
+
* caller's, or one minted here for a call no hook named — and the answer
|
|
1531
|
+
* of a call that failed says so (`metadata.isError`). The service pairs a
|
|
1532
|
+
* call with its answer by that id, where it used to pair them by tool name
|
|
1533
|
+
* in the order they came: two calls of one tool at once, answered out of
|
|
1534
|
+
* order, took each other's answers.
|
|
1535
|
+
*/
|
|
1357
1536
|
private record;
|
|
1358
1537
|
}
|
|
1359
1538
|
/**
|