@coreplane/switchboard 1.254.0 → 1.255.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/dist/assets/.dockerignore +3 -0
- package/dist/assets/Dockerfile +12 -1
- package/dist/assets/config/config.example.yaml +6 -1
- package/dist/assets/deploy/cloudflare/worker.ts +39 -23
- package/dist/assets/deploy/cloudflare-memory/worker.ts +552 -5
- package/dist/assets/deploy/cloudflare-memory/wrangler.template.jsonc +5 -0
- package/dist/assets/deploy/cloudflare-resident/Dockerfile +13 -1
- package/dist/assets/deploy/cloudflare-resident/levels.ts +84 -0
- package/dist/assets/deploy/cloudflare-resident/prepare-commit-msg +17 -0
- package/dist/assets/deploy/cloudflare-resident/worker.ts +202 -31
- package/dist/assets/deploy/cloudflare-sandbox/Dockerfile +11 -1
- package/dist/assets/deploy/cloudflare-sandbox/prepare-commit-msg +17 -0
- package/dist/assets/deploy/cloudflare-sandbox/worker.ts +21 -4
- package/dist/assets/deploy/hooks/prepare-commit-msg +17 -0
- package/dist/assets/deploy/secrets.manifest.json +12 -0
- package/dist/assets/package-lock.json +3 -3
- package/dist/assets/package.json +1 -1
- package/dist/assets/source.json +3 -3
- package/dist/assets/src/agents/registry.ts +21 -0
- package/dist/assets/src/core/budgets.ts +35 -2
- package/dist/assets/src/core/coordinator/contract.ts +6 -0
- package/dist/assets/src/core/coordinator/driver.ts +49 -6
- package/dist/assets/src/core/costs.ts +39 -16
- package/dist/assets/src/core/pipelineStanding.ts +5 -0
- package/dist/assets/src/core/plane/decide.ts +389 -22
- package/dist/assets/src/core/refusal.ts +3 -0
- package/dist/assets/src/core/reviewVerdict.ts +15 -2
- package/dist/assets/src/core/runEvents.ts +32 -13
- package/dist/assets/src/core/runLedger/sessionLog.ts +128 -0
- package/dist/assets/src/core/runLedger/types.ts +3 -0
- package/dist/assets/src/core/runRecord.ts +24 -7
- package/dist/assets/src/core/ship/coordinator.ts +327 -61
- package/dist/assets/src/core/trace/workerTrace.ts +3 -0
- package/dist/assets/src/execution/sandboxErrors.ts +77 -6
- package/dist/assets/web/dist/.vite/manifest.json +59 -58
- package/dist/assets/web/dist/assets/CostsPage-BaeWnm-o.js +1 -0
- package/dist/assets/web/dist/assets/{DeliveryPage-ngPsO2to.js → DeliveryPage-BBAyLwPq.js} +1 -1
- package/dist/assets/web/dist/assets/{HomePage-DvxTHzPx.js → HomePage-Be7jLLnU.js} +1 -1
- package/dist/assets/web/dist/assets/PendingTurnRow-DGINv9XT.js +1 -0
- package/dist/assets/web/dist/assets/{PlanePage-DpWfiX4C.js → PlanePage-JEj-lqgz.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentDetailPage-DG86v39Y.js → ResidentDetailPage-D_RD6wLo.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentsIndexPage-x6p689VH.js → ResidentsIndexPage-BLkSuCxo.js} +1 -1
- package/dist/assets/web/dist/assets/RunFoldRow-CfuZqf_O.js +1 -0
- package/dist/assets/web/dist/assets/{RunRoutePage-ysJBY8xQ.js → RunRoutePage-CmWYGR36.js} +4 -4
- package/dist/assets/web/dist/assets/{RunsIndexPage-CuzFchcn.js → RunsIndexPage-DW-HHuZa.js} +1 -1
- package/dist/assets/web/dist/assets/{ScheduledPage-BuLmfcbG.js → ScheduledPage-3aYsDf-q.js} +1 -1
- package/dist/assets/web/dist/assets/{SettingsPage-BujWkdU_.js → SettingsPage-DG-p5Xy1.js} +1 -1
- package/dist/assets/web/dist/assets/{StatusDot-C8Bc0pTX.js → StatusDot-CEnGlyAL.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-BWwJx27K.js → Tooltip-CiunVowT.js} +1 -1
- package/dist/assets/web/dist/assets/UnitRoutePage-iOYnmTcQ.js +1 -0
- package/dist/assets/web/dist/assets/budgets-c1eumrqD.js +1 -0
- package/dist/assets/web/dist/assets/{dist-CpnyQGOb.js → dist-luhv3YSo.js} +1 -1
- package/dist/assets/web/dist/assets/indexRow-DborJPFp.js +1 -0
- package/dist/assets/web/dist/assets/{main-Comxmwi4.js → main-mAKx_zo9.js} +2 -2
- package/dist/assets/web/dist/assets/{sseReplay-IzTdD4-3.js → sseReplay-DE6wv1Ua.js} +6 -6
- package/dist/cli.js +4154 -3061
- package/package.json +1 -1
- package/dist/assets/web/dist/assets/CostsPage-BuKjw3nv.js +0 -1
- package/dist/assets/web/dist/assets/PendingTurnRow-ZYIRCCZ2.js +0 -1
- package/dist/assets/web/dist/assets/RunFoldRow-DG29LOTs.js +0 -1
- package/dist/assets/web/dist/assets/UnitRoutePage-B9kjA1AT.js +0 -1
- package/dist/assets/web/dist/assets/budgets-CbIyPAER.js +0 -1
- package/dist/assets/web/dist/assets/indexRow-DABQtONT.js +0 -1
|
@@ -35,6 +35,134 @@ export function sessionKey(threadKey: string, agent: string | undefined): string
|
|
|
35
35
|
return `${threadKey}:${agent ?? "-"}`;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/** The thread session's key (record 0057; the one-door plan's memory unit,
|
|
39
|
+
* item 13): one log per thread, read and written by the operator — every
|
|
40
|
+
* connector event the intake gate admits, every child's report, every
|
|
41
|
+
* question and answer is a turn in it. The `@thread` half can never collide
|
|
42
|
+
* with `sessionKey`'s agent half: no agent id starts with `@`. */
|
|
43
|
+
export function threadSessionKey(threadKey: string): string {
|
|
44
|
+
return `${threadKey}:@thread`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** A working session's lane: a unit's coding rounds continue one log, its
|
|
48
|
+
* review rounds another (item 13). */
|
|
49
|
+
export type WorkingLane = "coding" | "review";
|
|
50
|
+
|
|
51
|
+
/** A working session's key `<instance>:<unit>:<lane>` (item 13). A re-issue of the
|
|
52
|
+
* same plan carries an attempt suffix on its instance id (`planInstanceId`:
|
|
53
|
+
* `plan-<id>-<attempt>`, attempt ≥ 2); the key strips it, so a re-issue
|
|
54
|
+
* continues the prior instance's lanes rather than starting cold. */
|
|
55
|
+
export function workingSessionKey(instance: { id: string; attempt?: number }, unit: string, lane: WorkingLane): string {
|
|
56
|
+
const suffix = instance.attempt !== undefined ? `-${instance.attempt}` : "";
|
|
57
|
+
const base =
|
|
58
|
+
suffix !== "" && instance.id.endsWith(suffix)
|
|
59
|
+
? instance.id.slice(0, instance.id.length - suffix.length)
|
|
60
|
+
: instance.id;
|
|
61
|
+
return `${base}:${unit}:${lane}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** A connector turn's row id (item 13): the message id, with its edit timestamp
|
|
65
|
+
* when the message was edited — an edited message appends a second row (the
|
|
66
|
+
* first said what the person first said), a re-delivered unedited one
|
|
67
|
+
* appends nothing. */
|
|
68
|
+
export function connectorRowId(messageId: string, editedAt?: string | number): string {
|
|
69
|
+
return editedAt === undefined ? messageId : `${messageId}:edit-${editedAt}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** The fold's row id for a hosted parent's `ship_unit` event (item 13): the
|
|
73
|
+
* event's own identity — its unit, its state and the registry seq it was
|
|
74
|
+
* published under — so the same event read twice folds one row. The seq is
|
|
75
|
+
* required (the registry stamps every published event with one): without it,
|
|
76
|
+
* a unit reopened at a second segment would repeat a state — two `started`
|
|
77
|
+
* events — and the second fold would be dropped as a duplicate. */
|
|
78
|
+
export function shipUnitRowId(event: { unit: string; state: string; seq: number }): string {
|
|
79
|
+
return `ship-unit:${event.unit}:${event.state}:${event.seq}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** One thread-session row as its JSON is stored (item 13): a text turn with
|
|
83
|
+
* its author when a person wrote it, `silent` when the intake gate withheld
|
|
84
|
+
* the reply (the person's words are context all the same), `folded` when the
|
|
85
|
+
* row is a child's report folded whole — what `operatorTail` keeps ahead of
|
|
86
|
+
* older turns. */
|
|
87
|
+
export function storedTurnRow(turn: {
|
|
88
|
+
role: "user" | "assistant";
|
|
89
|
+
text: string;
|
|
90
|
+
actor?: string;
|
|
91
|
+
silent?: boolean;
|
|
92
|
+
folded?: boolean;
|
|
93
|
+
}): string {
|
|
94
|
+
return JSON.stringify({
|
|
95
|
+
role: turn.role,
|
|
96
|
+
part: { type: "text", text: turn.text },
|
|
97
|
+
...(turn.actor !== undefined ? { actor: turn.actor } : {}),
|
|
98
|
+
...(turn.silent === true ? { silent: true } : {}),
|
|
99
|
+
...(turn.folded === true ? { folded: true } : {}),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Whether a stored row is a reply the intake gate withheld as silent (item 13). */
|
|
104
|
+
export function silentOfStoredRow(json: string): boolean {
|
|
105
|
+
const stored = parseStored(json);
|
|
106
|
+
return stored !== undefined && !("compaction" in stored) && (stored as { silent?: unknown }).silent === true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Whether a stored row is a folded report (item 13) — kept whole by the
|
|
110
|
+
* operator's cap ahead of older turns. */
|
|
111
|
+
export function foldedOfStoredRow(json: string): boolean {
|
|
112
|
+
const stored = parseStored(json);
|
|
113
|
+
return stored !== undefined && !("compaction" in stored) && (stored as { folded?: unknown }).folded === true;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** A run of an old `<thread>:<agent>` log, as the cutover migration reads it
|
|
117
|
+
* (item 13): its log's key, when it started and the row range its record closed. */
|
|
118
|
+
export interface MigrationRun {
|
|
119
|
+
key: string;
|
|
120
|
+
startedAt: number;
|
|
121
|
+
range: { from: number; to?: number };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** The order the cutover migration reads an old thread's per-agent logs into
|
|
125
|
+
* the thread session (item 13): the runs by their start times, each run's rows in
|
|
126
|
+
* its session range in index order, and rows outside any run's range after
|
|
127
|
+
* the runs that precede them in their own log (before every run of that log
|
|
128
|
+
* when none does). The read is once: each row lands under the row id
|
|
129
|
+
* `migrationRowId(key, idx)`, so a replay appends nothing twice, and the old
|
|
130
|
+
* keys stay read-only for recall. */
|
|
131
|
+
export function migrationOrder(
|
|
132
|
+
runs: readonly MigrationRun[],
|
|
133
|
+
logs: readonly { key: string; rows: readonly number[] }[],
|
|
134
|
+
): Array<{ key: string; idx: number }> {
|
|
135
|
+
const byStart = [...runs].sort((a, b) => a.startedAt - b.startedAt);
|
|
136
|
+
// A row's place: inside a run's range it rides at that run's start (phase 0);
|
|
137
|
+
// past a run's closed range it rides after that run's rows (phase 1); before
|
|
138
|
+
// every run of its log it comes first of all (start -Infinity).
|
|
139
|
+
const placed = logs.flatMap((log, logOrder) =>
|
|
140
|
+
log.rows.map((idx) => {
|
|
141
|
+
let at = Number.NEGATIVE_INFINITY;
|
|
142
|
+
let phase = 1;
|
|
143
|
+
for (const r of byStart) {
|
|
144
|
+
if (r.key !== log.key) continue;
|
|
145
|
+
const to = r.range.to;
|
|
146
|
+
if (idx >= r.range.from && (to === undefined || idx <= to)) {
|
|
147
|
+
at = r.startedAt;
|
|
148
|
+
phase = 0;
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
if (to !== undefined && to < idx && r.startedAt > at) at = r.startedAt;
|
|
152
|
+
}
|
|
153
|
+
return { key: log.key, idx, at, phase, logOrder };
|
|
154
|
+
}),
|
|
155
|
+
);
|
|
156
|
+
placed.sort((a, b) => a.at - b.at || a.phase - b.phase || a.logOrder - b.logOrder || a.idx - b.idx);
|
|
157
|
+
return placed.map(({ key, idx }) => ({ key, idx }));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** The row id a migrated row lands under (item 13): the old log's key and the
|
|
161
|
+
* row's index there — stable, so the read-once migration is idempotent. */
|
|
162
|
+
export function migrationRowId(key: string, idx: number): string {
|
|
163
|
+
return `migrated:${key}#${idx}`;
|
|
164
|
+
}
|
|
165
|
+
|
|
38
166
|
/** The request is the seed's last user turn (`splitSeed` reads the seed the
|
|
39
167
|
* same way); a seed with no user turn — or no turns — puts its first row there. */
|
|
40
168
|
export function requestIndex(seed: readonly ChatMessage[]): number {
|
|
@@ -287,6 +287,9 @@ export interface IntakeReceipt {
|
|
|
287
287
|
verdict: "addressed" | "silent";
|
|
288
288
|
reason: string;
|
|
289
289
|
source: "model" | "mode" | "error" | "timeout";
|
|
290
|
+
/** The structured seam's attempts (docs/decisions/0067): what each answer
|
|
291
|
+
* violated, or that it was accepted; absent when no model was asked. */
|
|
292
|
+
attempts?: ReadonlyArray<{ outcome: "accepted" | "violation"; violation?: string }>;
|
|
290
293
|
mode: "mention" | "classify";
|
|
291
294
|
/** The `<provider>/<model>` ref the verdict ran on. */
|
|
292
295
|
model: string;
|
|
@@ -392,9 +392,10 @@ export function callsInFlight(events: readonly RunEvent[], status: RunStatus): C
|
|
|
392
392
|
return [...calls.values()].filter((c) => c.state === "cut" || (c.state === "open" && !orderly)).map((c) => c.call);
|
|
393
393
|
}
|
|
394
394
|
|
|
395
|
-
/** The router's decision as a record carries it — the
|
|
396
|
-
*
|
|
397
|
-
*
|
|
395
|
+
/** The router's decision as a record carries it — the fields the `route`
|
|
396
|
+
* event and the ledger row's `meta.route` carry (routing-and-config item 21),
|
|
397
|
+
* minus the event's `attempts` (record 0067): the record keeps the decision,
|
|
398
|
+
* the re-asks stay on the event. */
|
|
398
399
|
export interface RunRouteDecision {
|
|
399
400
|
preset: string;
|
|
400
401
|
reason: string;
|
|
@@ -425,7 +426,7 @@ export function routeOfEvents(events: readonly RunEvent[]): RunRouteDecision | u
|
|
|
425
426
|
* fields less the stream bookkeeping (record 0057; run-history item 60). */
|
|
426
427
|
export interface RunOperatorDecision {
|
|
427
428
|
mode: "shadow" | "on";
|
|
428
|
-
outcome: "binds" | "question" | "refusal";
|
|
429
|
+
outcome: "binds" | "question" | "refusal" | "non_decision";
|
|
429
430
|
reason: string;
|
|
430
431
|
binds?: { line: string; reason: string }[];
|
|
431
432
|
question?: string;
|
|
@@ -433,6 +434,9 @@ export interface RunOperatorDecision {
|
|
|
433
434
|
proposal?: string;
|
|
434
435
|
refusalCause?: string;
|
|
435
436
|
refusalText?: string;
|
|
437
|
+
/** The structured seam's attempts (record 0067): what each answer violated,
|
|
438
|
+
* or that it was accepted. */
|
|
439
|
+
attempts?: { outcome: "accepted" | "violation"; violation?: string }[];
|
|
436
440
|
intake?: { verdict: string; reason: string };
|
|
437
441
|
latencyMs?: number;
|
|
438
442
|
outputTokens?: number;
|
|
@@ -454,6 +458,14 @@ export function operatorOfEvents(events: readonly RunEvent[]): RunOperatorDecisi
|
|
|
454
458
|
...(e.proposal !== undefined ? { proposal: e.proposal } : {}),
|
|
455
459
|
...(e.refusalCause !== undefined ? { refusalCause: e.refusalCause } : {}),
|
|
456
460
|
...(e.refusalText !== undefined ? { refusalText: e.refusalText } : {}),
|
|
461
|
+
...(e.attempts
|
|
462
|
+
? {
|
|
463
|
+
attempts: e.attempts.map((a) => ({
|
|
464
|
+
outcome: a.outcome,
|
|
465
|
+
...(a.violation !== undefined ? { violation: a.violation } : {}),
|
|
466
|
+
})),
|
|
467
|
+
}
|
|
468
|
+
: {}),
|
|
457
469
|
...(e.intake ? { intake: { verdict: e.intake.verdict, reason: e.intake.reason } } : {}),
|
|
458
470
|
...(e.latencyMs !== undefined ? { latencyMs: e.latencyMs } : {}),
|
|
459
471
|
...(e.outputTokens !== undefined ? { outputTokens: e.outputTokens } : {}),
|
|
@@ -497,9 +509,14 @@ function isRunPullRequestShape(v: unknown): v is RunPullRequest {
|
|
|
497
509
|
* (item 57). `policy_refusal`: the model provider refused the run's call
|
|
498
510
|
* under its usage policy — the stop reason its wire names, never the
|
|
499
511
|
* explanation's words — so the session's next seed leaves the refused
|
|
500
|
-
* request out of its tail (docs/reference/specs/session-log.md item 9).
|
|
501
|
-
*
|
|
502
|
-
|
|
512
|
+
* request out of its tail (docs/reference/specs/session-log.md item 9).
|
|
513
|
+
* `provider_transient`: the run's model call failed on a provider transient
|
|
514
|
+
* (a gateway 5xx, a cut stream, a gateway timeout) with the harness's retry
|
|
515
|
+
* ladder spent — the ship runner reads it off the child's record to re-run a
|
|
516
|
+
* round-0 child that pushed nothing instead of aborting the unit
|
|
517
|
+
* (docs/reference/specs/agent-ship.md item 9, issue 1932). A failure without
|
|
518
|
+
* a name here leaves the record without the field. */
|
|
519
|
+
export const RUN_FAILURE_KINDS = ["policy_refusal", "provider_transient"] as const;
|
|
503
520
|
export type RunFailureKind = (typeof RUN_FAILURE_KINDS)[number];
|
|
504
521
|
export interface RunFailure {
|
|
505
522
|
kind: RunFailureKind;
|