@coreplane/switchboard 1.223.0 → 1.224.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/package-lock.json +3 -3
- package/dist/assets/package.json +1 -1
- package/dist/assets/source.json +3 -3
- package/dist/assets/web/dist/.vite/manifest.json +19 -19
- package/dist/assets/web/dist/assets/{ResidentDetailPage-BTg4oFcn.js → ResidentDetailPage-BXwWQRJt.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentsIndexPage-Dr2qkjKI.js → ResidentsIndexPage-CwVN-3tl.js} +1 -1
- package/dist/assets/web/dist/assets/RunRoutePage-C0-RUb8o.js +12 -0
- package/dist/assets/web/dist/assets/{RunsIndexPage-DEkZXNnw.js → RunsIndexPage-Tx5P767G.js} +1 -1
- package/dist/assets/web/dist/assets/{ScheduledPage-wA7HE6UW.js → ScheduledPage-C80zFu3G.js} +1 -1
- package/dist/assets/web/dist/assets/{StatusDot-7ojvQlTS.js → StatusDot-BaGkjYs1.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-Cx88lWUW.js → Tooltip-BL-Cwe59.js} +1 -1
- package/dist/assets/web/dist/assets/{dist-B85zXO-d.js → dist-DZgVjemt.js} +1 -1
- package/dist/assets/web/dist/assets/main-43n8Y5qO.css +1 -0
- package/dist/assets/web/dist/assets/{main-BdoqEBpN.js → main-BB6FMkeU.js} +2 -2
- package/dist/cli.js +91 -34
- package/package.json +1 -1
- package/dist/assets/web/dist/assets/RunRoutePage-CTbnfyBQ.js +0 -12
- package/dist/assets/web/dist/assets/main-C1tNx19B.css +0 -1
package/dist/cli.js
CHANGED
|
@@ -31681,7 +31681,7 @@ var init_bridge2 = __esm({
|
|
|
31681
31681
|
return this.answerText ?? this.heldAnswer;
|
|
31682
31682
|
}
|
|
31683
31683
|
observe(event) {
|
|
31684
|
-
const out = { replies: [], settled: false
|
|
31684
|
+
const out = { replies: [], settled: false };
|
|
31685
31685
|
const disposition = PI_EVENT_DISPOSITION[event.type];
|
|
31686
31686
|
if (disposition === void 0) {
|
|
31687
31687
|
this.note("harness_error", `pi emitted an event kind this build does not know: ${redactAndCap(event.type, 80)}`);
|
|
@@ -31698,9 +31698,6 @@ var init_bridge2 = __esm({
|
|
|
31698
31698
|
case "agent_settled":
|
|
31699
31699
|
out.settled = true;
|
|
31700
31700
|
break;
|
|
31701
|
-
case "turn_end":
|
|
31702
|
-
out.turnEnded = true;
|
|
31703
|
-
break;
|
|
31704
31701
|
case "message_start":
|
|
31705
31702
|
if (isRecord3(event.message) && event.message.role === "assistant") this.assistantStartedAt = this.deps.clock();
|
|
31706
31703
|
break;
|
|
@@ -31893,6 +31890,7 @@ var init_bridge2 = __esm({
|
|
|
31893
31890
|
});
|
|
31894
31891
|
|
|
31895
31892
|
// ../../src/core/harness/pi/mirror.ts
|
|
31893
|
+
import { isDeepStrictEqual } from "node:util";
|
|
31896
31894
|
function partsOf2(content) {
|
|
31897
31895
|
if (typeof content === "string") return [{ type: "text", text: content }];
|
|
31898
31896
|
if (!Array.isArray(content)) return [];
|
|
@@ -32042,11 +32040,14 @@ var init_mirror = __esm({
|
|
|
32042
32040
|
constructor(deps) {
|
|
32043
32041
|
this.deps = deps;
|
|
32044
32042
|
this.idx = deps.seedLength;
|
|
32043
|
+
this.mirroredTail = deps.mirroredTail;
|
|
32045
32044
|
}
|
|
32046
32045
|
deps;
|
|
32047
32046
|
idx;
|
|
32048
32047
|
pendingUser = [];
|
|
32049
|
-
|
|
32048
|
+
/** pi is about to echo the seed's prompt as a user message (see `expectSeedEcho`). */
|
|
32049
|
+
seedEchoPending = false;
|
|
32050
|
+
mirroredTail;
|
|
32050
32051
|
iteration = 0;
|
|
32051
32052
|
/** The highest ledger inbox seq folded in so far (run-history item 40). */
|
|
32052
32053
|
inboxConsumedSeq = 0;
|
|
@@ -32054,19 +32055,43 @@ var init_mirror = __esm({
|
|
|
32054
32055
|
get wired() {
|
|
32055
32056
|
return this.deps.onStep !== void 0;
|
|
32056
32057
|
}
|
|
32058
|
+
/** pi answered the seed's prompt: the first user message without results
|
|
32059
|
+
* that follows is its echo — the seed, on the ledger already — and is not
|
|
32060
|
+
* written twice. A continue prompt (harness-pi item 8) expects none: its
|
|
32061
|
+
* echo is a turn the model was told, folded in like a steer's text. */
|
|
32062
|
+
expectSeedEcho() {
|
|
32063
|
+
this.seedEchoPending = true;
|
|
32064
|
+
}
|
|
32065
|
+
/** The row about to be written, against the transcript's tail — compared
|
|
32066
|
+
* once, with the first row the mirror meets: equal means the ledger holds
|
|
32067
|
+
* it already (read again, harness-pi item 8), together with the results
|
|
32068
|
+
* pending before it, which were its step's user turn. */
|
|
32069
|
+
alreadyHeld(row) {
|
|
32070
|
+
const tail = this.mirroredTail;
|
|
32071
|
+
if (tail === void 0) return false;
|
|
32072
|
+
this.mirroredTail = void 0;
|
|
32073
|
+
if (!isDeepStrictEqual(row, tail)) return false;
|
|
32074
|
+
this.pendingUser = [];
|
|
32075
|
+
return true;
|
|
32076
|
+
}
|
|
32077
|
+
/** Feeds one finished message; answers whether the ledger now holds
|
|
32078
|
+
* everything up to it — a step written, or an assistant turn found already
|
|
32079
|
+
* there — so the harness can move the row's offset past it. A result or a
|
|
32080
|
+
* steer's text waits in memory for the next step, and the answer is no. */
|
|
32057
32081
|
async onMessage(message3, turn) {
|
|
32058
|
-
if (!this.deps.onStep) return;
|
|
32082
|
+
if (!this.deps.onStep) return false;
|
|
32059
32083
|
const chat = chatMessageOf(message3);
|
|
32060
|
-
if (!chat) return;
|
|
32061
|
-
if (chat.content.length === 0) return;
|
|
32084
|
+
if (!chat) return false;
|
|
32085
|
+
if (chat.content.length === 0) return false;
|
|
32062
32086
|
if (chat.role === "user") {
|
|
32063
|
-
if (
|
|
32064
|
-
this.
|
|
32065
|
-
return;
|
|
32087
|
+
if (this.seedEchoPending && !chat.content.some((p) => p.type === "tool_result")) {
|
|
32088
|
+
this.seedEchoPending = false;
|
|
32089
|
+
return false;
|
|
32066
32090
|
}
|
|
32067
32091
|
this.pendingUser.push(...chat.content);
|
|
32068
|
-
return;
|
|
32092
|
+
return false;
|
|
32069
32093
|
}
|
|
32094
|
+
if (this.alreadyHeld({ turn: chat })) return true;
|
|
32070
32095
|
const turns = [];
|
|
32071
32096
|
if (this.pendingUser.length > 0) turns.push({ role: "user", content: this.pendingUser });
|
|
32072
32097
|
this.pendingUser = [];
|
|
@@ -32083,13 +32108,16 @@ var init_mirror = __esm({
|
|
|
32083
32108
|
};
|
|
32084
32109
|
this.idx += turns.length;
|
|
32085
32110
|
await this.deps.onStep(report2);
|
|
32111
|
+
return true;
|
|
32086
32112
|
}
|
|
32087
32113
|
/** pi compacted (session-log item 6): the results pending since the last
|
|
32088
32114
|
* assistant turn go as the user turn they would have been, the entry as the
|
|
32089
32115
|
* row after them — its own step with nothing in flight, so the log holds
|
|
32090
|
-
* the summary where pi wrote it and the index moves past it.
|
|
32116
|
+
* the summary where pi wrote it and the index moves past it. Answers as
|
|
32117
|
+
* `onMessage` does: the ledger holds everything up to the entry. */
|
|
32091
32118
|
async onCompaction(entry, turn) {
|
|
32092
|
-
if (!this.deps.onStep) return;
|
|
32119
|
+
if (!this.deps.onStep) return false;
|
|
32120
|
+
if (this.alreadyHeld({ compaction: entry })) return true;
|
|
32093
32121
|
const turns = [];
|
|
32094
32122
|
if (this.pendingUser.length > 0) turns.push({ role: "user", content: this.pendingUser });
|
|
32095
32123
|
this.pendingUser = [];
|
|
@@ -32105,6 +32133,7 @@ var init_mirror = __esm({
|
|
|
32105
32133
|
};
|
|
32106
32134
|
this.idx += turns.length + 1;
|
|
32107
32135
|
await this.deps.onStep(report2);
|
|
32136
|
+
return true;
|
|
32108
32137
|
}
|
|
32109
32138
|
};
|
|
32110
32139
|
}
|
|
@@ -32121,11 +32150,16 @@ var init_transport = __esm({
|
|
|
32121
32150
|
constructor(deps) {
|
|
32122
32151
|
this.deps = deps;
|
|
32123
32152
|
this.offset = deps.offset ?? 0;
|
|
32153
|
+
this.consumedOffset = this.offset;
|
|
32124
32154
|
this.lines = this.read();
|
|
32125
32155
|
}
|
|
32126
32156
|
deps;
|
|
32127
|
-
/** The byte the next read starts at
|
|
32157
|
+
/** The byte the next read starts at: the read position, moved by whole chunks. */
|
|
32128
32158
|
offset;
|
|
32159
|
+
/** The boundary after the record last handed out, moved by records: where a
|
|
32160
|
+
* reader that has seen everything so far continues from — the harness's
|
|
32161
|
+
* re-attach fact, taken when nothing handed out is left unwritten. */
|
|
32162
|
+
consumedOffset;
|
|
32129
32163
|
/** pi was found dead while the harness still listened. */
|
|
32130
32164
|
exited = false;
|
|
32131
32165
|
closed = false;
|
|
@@ -32178,11 +32212,15 @@ var init_transport = __esm({
|
|
|
32178
32212
|
/** Complete lines out of the buffered bytes; the partial tail waits for more. */
|
|
32179
32213
|
*split(chunk) {
|
|
32180
32214
|
this.buffer = Buffer.concat([this.buffer, Buffer.from(chunk)]);
|
|
32215
|
+
const base = this.offset - this.buffer.length;
|
|
32181
32216
|
let start3 = 0;
|
|
32182
32217
|
for (let i = this.buffer.indexOf(NEWLINE, start3); i >= 0; i = this.buffer.indexOf(NEWLINE, start3)) {
|
|
32183
32218
|
let line3 = this.buffer.subarray(start3, i).toString("utf8");
|
|
32184
32219
|
if (line3.endsWith("\r")) line3 = line3.slice(0, -1);
|
|
32185
|
-
if (line3.length > 0)
|
|
32220
|
+
if (line3.length > 0) {
|
|
32221
|
+
this.consumedOffset = base + i + 1;
|
|
32222
|
+
yield line3;
|
|
32223
|
+
}
|
|
32186
32224
|
start3 = i + 1;
|
|
32187
32225
|
}
|
|
32188
32226
|
this.buffer = this.buffer.subarray(start3);
|
|
@@ -32192,6 +32230,7 @@ var init_transport = __esm({
|
|
|
32192
32230
|
});
|
|
32193
32231
|
|
|
32194
32232
|
// ../../src/core/harness/pi/harness.ts
|
|
32233
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
32195
32234
|
function piHarnessFactsOf(value) {
|
|
32196
32235
|
if (typeof value !== "object" || value === null) return void 0;
|
|
32197
32236
|
const v = value;
|
|
@@ -32252,6 +32291,13 @@ function settlementResults(settlements) {
|
|
|
32252
32291
|
}))
|
|
32253
32292
|
};
|
|
32254
32293
|
}
|
|
32294
|
+
function ledgerTailOf(resume) {
|
|
32295
|
+
if (!resume) return void 0;
|
|
32296
|
+
const closing = resume.compactions?.filter((c) => c.before === resume.messages.length).at(-1);
|
|
32297
|
+
if (closing) return { compaction: closing.entry };
|
|
32298
|
+
const last = resume.messages.at(-1);
|
|
32299
|
+
return last?.role === "assistant" ? { turn: last } : void 0;
|
|
32300
|
+
}
|
|
32255
32301
|
function settlementAnswer(s) {
|
|
32256
32302
|
return { content: [{ type: "text", text: settlementText(s) }], isError: true };
|
|
32257
32303
|
}
|
|
@@ -32296,10 +32342,12 @@ async function runPiHarness(deps, run2) {
|
|
|
32296
32342
|
};
|
|
32297
32343
|
}
|
|
32298
32344
|
bridge.turns = run2.resume?.turn ?? 0;
|
|
32345
|
+
const tail = ledgerTailOf(run2.resume);
|
|
32299
32346
|
const mirror = new PiMirror({
|
|
32300
32347
|
onStep: run2.onStep,
|
|
32301
|
-
seedLength: run2.resume
|
|
32302
|
-
remainingMs: () => deadline - now()
|
|
32348
|
+
seedLength: run2.resume ? run2.resume.messages.length + (run2.resume.compactions?.length ?? 0) : run2.messages.length,
|
|
32349
|
+
remainingMs: () => deadline - now(),
|
|
32350
|
+
...tail ? { mirroredTail: tail } : {}
|
|
32303
32351
|
});
|
|
32304
32352
|
mirror.inboxConsumedSeq = run2.resume?.inboxConsumedSeq ?? 0;
|
|
32305
32353
|
let writeUp;
|
|
@@ -32336,12 +32384,17 @@ async function runPiHarness(deps, run2) {
|
|
|
32336
32384
|
let pid;
|
|
32337
32385
|
let transport;
|
|
32338
32386
|
let facts2;
|
|
32387
|
+
let mirrored = 0;
|
|
32339
32388
|
const save = () => {
|
|
32340
32389
|
if (facts2) {
|
|
32341
|
-
|
|
32390
|
+
facts2 = { ...facts2, logOffset: mirrored };
|
|
32342
32391
|
run2.saveFacts?.(facts2);
|
|
32343
32392
|
}
|
|
32344
32393
|
};
|
|
32394
|
+
const held = () => {
|
|
32395
|
+
if (transport) mirrored = transport.consumedOffset;
|
|
32396
|
+
save();
|
|
32397
|
+
};
|
|
32345
32398
|
let catchingUp = false;
|
|
32346
32399
|
try {
|
|
32347
32400
|
const recorded = run2.resume?.facts;
|
|
@@ -32368,13 +32421,14 @@ async function runPiHarness(deps, run2) {
|
|
|
32368
32421
|
if (reattached && recorded && paths !== void 0) {
|
|
32369
32422
|
pid = recorded.pid;
|
|
32370
32423
|
facts2 = { ...recorded, ...recorded.container === void 0 && here !== void 0 ? { container: here } : {} };
|
|
32424
|
+
mirrored = recorded.logOffset;
|
|
32371
32425
|
transport = new PiRpcTransport({
|
|
32372
32426
|
container,
|
|
32373
32427
|
paths,
|
|
32374
32428
|
pid,
|
|
32375
32429
|
pollMs: deps.pollMs ?? 750,
|
|
32376
32430
|
sleep: deps.sleep,
|
|
32377
|
-
offset:
|
|
32431
|
+
offset: mirrored
|
|
32378
32432
|
});
|
|
32379
32433
|
catchingUp = true;
|
|
32380
32434
|
const inFlight = run2.resume?.settlements.length ?? 0;
|
|
@@ -32452,12 +32506,15 @@ async function runPiHarness(deps, run2) {
|
|
|
32452
32506
|
save();
|
|
32453
32507
|
transport = new PiRpcTransport({ container, paths, pid, pollMs: deps.pollMs ?? 750, sleep: deps.sleep });
|
|
32454
32508
|
}
|
|
32455
|
-
|
|
32456
|
-
|
|
32509
|
+
const stamp = `${now()}-${randomUUID2().slice(0, 8)}`;
|
|
32510
|
+
const ids = { retry: `retry:${stamp}`, state: `state:${stamp}`, prompt: `prompt:${stamp}` };
|
|
32511
|
+
const continuing = reattached || run2.resume !== void 0;
|
|
32512
|
+
transport.send({ id: ids.retry, type: "set_auto_retry", enabled: false });
|
|
32513
|
+
transport.send({ id: ids.state, type: "get_state" });
|
|
32457
32514
|
if (reattached)
|
|
32458
|
-
transport.send({ id:
|
|
32459
|
-
else if (run2.resume) transport.send({ id:
|
|
32460
|
-
else transport.send({ id:
|
|
32515
|
+
transport.send({ id: ids.prompt, type: "prompt", message: CONTINUE_PROMPT, streamingBehavior: "steer" });
|
|
32516
|
+
else if (run2.resume) transport.send({ id: ids.prompt, type: "prompt", message: CONTINUE_PROMPT });
|
|
32517
|
+
else transport.send({ id: ids.prompt, type: "prompt", ...promptOf(run2.messages) });
|
|
32461
32518
|
let warned = false;
|
|
32462
32519
|
let settled = false;
|
|
32463
32520
|
let stopMode;
|
|
@@ -32575,19 +32632,20 @@ ${stagedLine}` : prompt,
|
|
|
32575
32632
|
}
|
|
32576
32633
|
if (obs.response) {
|
|
32577
32634
|
const r = obs.response;
|
|
32578
|
-
if (r.id ===
|
|
32635
|
+
if (r.id === ids.state && r.success === true && typeof r.data?.sessionFile === "string") {
|
|
32579
32636
|
const data = r.data;
|
|
32580
32637
|
facts2 = { ...facts2 ?? { pid, logOffset: 0, root: paths.dir }, sessionFile: String(data.sessionFile) };
|
|
32581
32638
|
save();
|
|
32582
32639
|
}
|
|
32583
|
-
if (r.id ===
|
|
32640
|
+
if (r.id === ids.prompt) {
|
|
32584
32641
|
catchingUp = false;
|
|
32585
32642
|
if (r.success === false) throw new PromptRefused(String(r.error ?? "no reason"));
|
|
32643
|
+
if (!continuing) mirror.expectSeedEcho();
|
|
32586
32644
|
}
|
|
32587
32645
|
}
|
|
32588
|
-
if (obs.message
|
|
32646
|
+
if (obs.message && await mirror.onMessage(obs.message, bridge.turns)) held();
|
|
32589
32647
|
if (obs.compaction) {
|
|
32590
|
-
await mirror.onCompaction(obs.compaction, bridge.turns);
|
|
32648
|
+
if (await mirror.onCompaction(obs.compaction, bridge.turns)) held();
|
|
32591
32649
|
if (!writeUp && !hardStopped && !catchingUp) {
|
|
32592
32650
|
let notepad;
|
|
32593
32651
|
let unavailable = false;
|
|
@@ -32608,7 +32666,6 @@ ${stagedLine}` : prompt,
|
|
|
32608
32666
|
note("harness_error", `a model call failed while the bot was away (${obs.providerError}); continuing`);
|
|
32609
32667
|
else providerError = obs.providerError;
|
|
32610
32668
|
}
|
|
32611
|
-
if (obs.turnEnded) save();
|
|
32612
32669
|
if (obs.settled && !catchingUp) {
|
|
32613
32670
|
settled = true;
|
|
32614
32671
|
break;
|
|
@@ -32622,8 +32679,8 @@ ${stagedLine}` : prompt,
|
|
|
32622
32679
|
}
|
|
32623
32680
|
if (bypass) throw bypass;
|
|
32624
32681
|
if (!settled) {
|
|
32625
|
-
const
|
|
32626
|
-
throw new Error(`pi exited before the run settled${
|
|
32682
|
+
const tail2 = await container.tail(paths.errLog, 2e3);
|
|
32683
|
+
throw new Error(`pi exited before the run settled${tail2.trim() ? `: ${redactAndCap(tail2.trim(), 400)}` : ""}`);
|
|
32627
32684
|
}
|
|
32628
32685
|
if (providerError !== void 0) throw new Error(`the model call failed: ${providerError}`);
|
|
32629
32686
|
const text = bridge.answer() ?? "";
|
|
@@ -36787,8 +36844,8 @@ var init_types5 = __esm({
|
|
|
36787
36844
|
});
|
|
36788
36845
|
|
|
36789
36846
|
// ../../src/core/runLedger/writeThrough.ts
|
|
36790
|
-
import { randomUUID as
|
|
36791
|
-
function mintGeneration(now = Date.now, random =
|
|
36847
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
36848
|
+
function mintGeneration(now = Date.now, random = randomUUID3) {
|
|
36792
36849
|
const stamp = new Date(now()).toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
36793
36850
|
const gen = `${stamp}-${random().replace(/-/g, "").slice(0, 8)}`;
|
|
36794
36851
|
if (!GEN_PATTERN.test(gen)) throw new Error(`minted generation ${gen} does not match GEN_PATTERN`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coreplane/switchboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.224.0",
|
|
4
4
|
"description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://openswitchboard.dev",
|