@coreplane/switchboard 1.222.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/config/config.example.yaml +14 -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/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 +147 -41
- 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
|
@@ -2858,8 +2858,24 @@ function validateConfig(cfg) {
|
|
|
2858
2858
|
if (cfg.routing !== void 0) validateRouting(cfg.routing, cfg.providers);
|
|
2859
2859
|
if (cfg.artifacts !== void 0) validateArtifacts(cfg.artifacts);
|
|
2860
2860
|
if (cfg.harness !== void 0) validateHarness(cfg.harness);
|
|
2861
|
+
if (cfg.pi !== void 0) validatePi(cfg.pi);
|
|
2861
2862
|
validateDashboardConfig(cfg.dashboard);
|
|
2862
2863
|
}
|
|
2864
|
+
function validatePi(pi) {
|
|
2865
|
+
if (typeof pi !== "object" || pi === null || Array.isArray(pi)) throw new Error("config.yaml: pi must be a mapping");
|
|
2866
|
+
for (const key of unknownKeys2(pi, PI_KEYS)) throw new Error(`config.yaml: pi.${key} is not a known key`);
|
|
2867
|
+
const { compaction } = pi;
|
|
2868
|
+
if (compaction === void 0) return;
|
|
2869
|
+
if (typeof compaction !== "object" || compaction === null || Array.isArray(compaction))
|
|
2870
|
+
throw new Error("config.yaml: pi.compaction must be a mapping");
|
|
2871
|
+
for (const key of unknownKeys2(compaction, PI_COMPACTION_KEYS))
|
|
2872
|
+
throw new Error(`config.yaml: pi.compaction.${key} is not a known key`);
|
|
2873
|
+
for (const key of Object.keys(PI_COMPACTION_KEYS)) {
|
|
2874
|
+
const value = compaction[key];
|
|
2875
|
+
if (value !== void 0 && (typeof value !== "number" || !Number.isInteger(value) || value <= 0))
|
|
2876
|
+
throw new Error(`config.yaml: pi.compaction.${key} must be a positive integer (tokens)`);
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2863
2879
|
function validateHarness(harness) {
|
|
2864
2880
|
if (typeof harness !== "object" || harness === null || Array.isArray(harness))
|
|
2865
2881
|
throw new Error("config.yaml: harness must be a mapping of preset to harness (native | pi)");
|
|
@@ -2977,7 +2993,7 @@ function validateRuntimeOverrides(ro) {
|
|
|
2977
2993
|
}
|
|
2978
2994
|
}
|
|
2979
2995
|
}
|
|
2980
|
-
var MAX_INSTRUCTIONS_LENGTH, CONFIG_KEYS, SELF_IMPROVEMENT_KEYS, BOUNDARY_KEYS, MIN_BOUNDARY_MINUTES, ROUTE_ANSWER_MODES, ROUTING_KEYS, SHIP_KEYS, SPAWN_KEYS;
|
|
2996
|
+
var MAX_INSTRUCTIONS_LENGTH, CONFIG_KEYS, SELF_IMPROVEMENT_KEYS, BOUNDARY_KEYS, MIN_BOUNDARY_MINUTES, PI_KEYS, PI_COMPACTION_KEYS, ROUTE_ANSWER_MODES, ROUTING_KEYS, SHIP_KEYS, SPAWN_KEYS;
|
|
2981
2997
|
var init_validate = __esm({
|
|
2982
2998
|
"../../src/config/validate.ts"() {
|
|
2983
2999
|
"use strict";
|
|
@@ -3012,6 +3028,7 @@ var init_validate = __esm({
|
|
|
3012
3028
|
spawn: true,
|
|
3013
3029
|
routing: true,
|
|
3014
3030
|
harness: true,
|
|
3031
|
+
pi: true,
|
|
3015
3032
|
slack: true,
|
|
3016
3033
|
runHistory: true,
|
|
3017
3034
|
runtimeOverrides: true,
|
|
@@ -3026,6 +3043,8 @@ var init_validate = __esm({
|
|
|
3026
3043
|
};
|
|
3027
3044
|
BOUNDARY_KEYS = { maxMinutes: true, maxIdentity: true, machines: true };
|
|
3028
3045
|
MIN_BOUNDARY_MINUTES = 2;
|
|
3046
|
+
PI_KEYS = { compaction: true };
|
|
3047
|
+
PI_COMPACTION_KEYS = { reserveTokens: true, keepRecentTokens: true };
|
|
3029
3048
|
ROUTE_ANSWER_MODES = ["tool", "text"];
|
|
3030
3049
|
ROUTING_KEYS = { auto: true, model: true, answer: true };
|
|
3031
3050
|
SHIP_KEYS = { maxRounds: true, maxMinutes: true };
|
|
@@ -12186,6 +12205,8 @@ var init_costs = __esm({
|
|
|
12186
12205
|
async fetchCostReport(range) {
|
|
12187
12206
|
const rows = [];
|
|
12188
12207
|
let closedThrough = null;
|
|
12208
|
+
const endExclusive = range.partialLastDay ? range.to : addDays2(range.to, 1);
|
|
12209
|
+
if (range.from >= endExclusive) return { rows, closedThrough };
|
|
12189
12210
|
let page2 = null;
|
|
12190
12211
|
for (let i = 0; ; i++) {
|
|
12191
12212
|
if (i >= MAX_COST_PAGES)
|
|
@@ -12194,7 +12215,7 @@ var init_costs = __esm({
|
|
|
12194
12215
|
);
|
|
12195
12216
|
const url = new URL(ANTHROPIC_COST_REPORT);
|
|
12196
12217
|
url.searchParams.set("starting_at", `${range.from}T00:00:00Z`);
|
|
12197
|
-
url.searchParams.set("ending_at", `${
|
|
12218
|
+
url.searchParams.set("ending_at", `${endExclusive}T00:00:00Z`);
|
|
12198
12219
|
url.searchParams.set("bucket_width", "1d");
|
|
12199
12220
|
url.searchParams.append("group_by[]", "workspace_id");
|
|
12200
12221
|
url.searchParams.set("limit", "31");
|
|
@@ -31092,12 +31113,18 @@ function piSystemPrompt(spec) {
|
|
|
31092
31113
|
${harnessPromptNote(spec.relayTools, spec.identity)}
|
|
31093
31114
|
`;
|
|
31094
31115
|
}
|
|
31095
|
-
function piSettingsJson() {
|
|
31096
|
-
|
|
31116
|
+
function piSettingsJson(compaction) {
|
|
31117
|
+
const settings = { defaultProjectTrust: "never", checkForUpdates: false };
|
|
31118
|
+
const thresholds = {
|
|
31119
|
+
...compaction?.reserveTokens !== void 0 ? { reserveTokens: compaction.reserveTokens } : {},
|
|
31120
|
+
...compaction?.keepRecentTokens !== void 0 ? { keepRecentTokens: compaction.keepRecentTokens } : {}
|
|
31121
|
+
};
|
|
31122
|
+
if (Object.keys(thresholds).length > 0) settings.compaction = thresholds;
|
|
31123
|
+
return JSON.stringify(settings, null, 2) + "\n";
|
|
31097
31124
|
}
|
|
31098
31125
|
function piLaunchFiles(spec) {
|
|
31099
31126
|
return [
|
|
31100
|
-
{ path: `${spec.paths.agentDir}/settings.json`, content: piSettingsJson() },
|
|
31127
|
+
{ path: `${spec.paths.agentDir}/settings.json`, content: piSettingsJson(spec.compaction) },
|
|
31101
31128
|
{ path: `${spec.paths.agentDir}/models.json`, content: piModelsJson(spec) },
|
|
31102
31129
|
{ path: `${spec.paths.agentDir}/SYSTEM.md`, content: piSystemPrompt(spec) },
|
|
31103
31130
|
{ path: spec.paths.extension, content: PI_EXTENSION_SOURCE }
|
|
@@ -31654,7 +31681,7 @@ var init_bridge2 = __esm({
|
|
|
31654
31681
|
return this.answerText ?? this.heldAnswer;
|
|
31655
31682
|
}
|
|
31656
31683
|
observe(event) {
|
|
31657
|
-
const out = { replies: [], settled: false
|
|
31684
|
+
const out = { replies: [], settled: false };
|
|
31658
31685
|
const disposition = PI_EVENT_DISPOSITION[event.type];
|
|
31659
31686
|
if (disposition === void 0) {
|
|
31660
31687
|
this.note("harness_error", `pi emitted an event kind this build does not know: ${redactAndCap(event.type, 80)}`);
|
|
@@ -31671,9 +31698,6 @@ var init_bridge2 = __esm({
|
|
|
31671
31698
|
case "agent_settled":
|
|
31672
31699
|
out.settled = true;
|
|
31673
31700
|
break;
|
|
31674
|
-
case "turn_end":
|
|
31675
|
-
out.turnEnded = true;
|
|
31676
|
-
break;
|
|
31677
31701
|
case "message_start":
|
|
31678
31702
|
if (isRecord3(event.message) && event.message.role === "assistant") this.assistantStartedAt = this.deps.clock();
|
|
31679
31703
|
break;
|
|
@@ -31866,6 +31890,7 @@ var init_bridge2 = __esm({
|
|
|
31866
31890
|
});
|
|
31867
31891
|
|
|
31868
31892
|
// ../../src/core/harness/pi/mirror.ts
|
|
31893
|
+
import { isDeepStrictEqual } from "node:util";
|
|
31869
31894
|
function partsOf2(content) {
|
|
31870
31895
|
if (typeof content === "string") return [{ type: "text", text: content }];
|
|
31871
31896
|
if (!Array.isArray(content)) return [];
|
|
@@ -32015,11 +32040,14 @@ var init_mirror = __esm({
|
|
|
32015
32040
|
constructor(deps) {
|
|
32016
32041
|
this.deps = deps;
|
|
32017
32042
|
this.idx = deps.seedLength;
|
|
32043
|
+
this.mirroredTail = deps.mirroredTail;
|
|
32018
32044
|
}
|
|
32019
32045
|
deps;
|
|
32020
32046
|
idx;
|
|
32021
32047
|
pendingUser = [];
|
|
32022
|
-
|
|
32048
|
+
/** pi is about to echo the seed's prompt as a user message (see `expectSeedEcho`). */
|
|
32049
|
+
seedEchoPending = false;
|
|
32050
|
+
mirroredTail;
|
|
32023
32051
|
iteration = 0;
|
|
32024
32052
|
/** The highest ledger inbox seq folded in so far (run-history item 40). */
|
|
32025
32053
|
inboxConsumedSeq = 0;
|
|
@@ -32027,19 +32055,43 @@ var init_mirror = __esm({
|
|
|
32027
32055
|
get wired() {
|
|
32028
32056
|
return this.deps.onStep !== void 0;
|
|
32029
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. */
|
|
32030
32081
|
async onMessage(message3, turn) {
|
|
32031
|
-
if (!this.deps.onStep) return;
|
|
32082
|
+
if (!this.deps.onStep) return false;
|
|
32032
32083
|
const chat = chatMessageOf(message3);
|
|
32033
|
-
if (!chat) return;
|
|
32034
|
-
if (chat.content.length === 0) return;
|
|
32084
|
+
if (!chat) return false;
|
|
32085
|
+
if (chat.content.length === 0) return false;
|
|
32035
32086
|
if (chat.role === "user") {
|
|
32036
|
-
if (
|
|
32037
|
-
this.
|
|
32038
|
-
return;
|
|
32087
|
+
if (this.seedEchoPending && !chat.content.some((p) => p.type === "tool_result")) {
|
|
32088
|
+
this.seedEchoPending = false;
|
|
32089
|
+
return false;
|
|
32039
32090
|
}
|
|
32040
32091
|
this.pendingUser.push(...chat.content);
|
|
32041
|
-
return;
|
|
32092
|
+
return false;
|
|
32042
32093
|
}
|
|
32094
|
+
if (this.alreadyHeld({ turn: chat })) return true;
|
|
32043
32095
|
const turns = [];
|
|
32044
32096
|
if (this.pendingUser.length > 0) turns.push({ role: "user", content: this.pendingUser });
|
|
32045
32097
|
this.pendingUser = [];
|
|
@@ -32056,13 +32108,16 @@ var init_mirror = __esm({
|
|
|
32056
32108
|
};
|
|
32057
32109
|
this.idx += turns.length;
|
|
32058
32110
|
await this.deps.onStep(report2);
|
|
32111
|
+
return true;
|
|
32059
32112
|
}
|
|
32060
32113
|
/** pi compacted (session-log item 6): the results pending since the last
|
|
32061
32114
|
* assistant turn go as the user turn they would have been, the entry as the
|
|
32062
32115
|
* row after them — its own step with nothing in flight, so the log holds
|
|
32063
|
-
* 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. */
|
|
32064
32118
|
async onCompaction(entry, turn) {
|
|
32065
|
-
if (!this.deps.onStep) return;
|
|
32119
|
+
if (!this.deps.onStep) return false;
|
|
32120
|
+
if (this.alreadyHeld({ compaction: entry })) return true;
|
|
32066
32121
|
const turns = [];
|
|
32067
32122
|
if (this.pendingUser.length > 0) turns.push({ role: "user", content: this.pendingUser });
|
|
32068
32123
|
this.pendingUser = [];
|
|
@@ -32078,6 +32133,7 @@ var init_mirror = __esm({
|
|
|
32078
32133
|
};
|
|
32079
32134
|
this.idx += turns.length + 1;
|
|
32080
32135
|
await this.deps.onStep(report2);
|
|
32136
|
+
return true;
|
|
32081
32137
|
}
|
|
32082
32138
|
};
|
|
32083
32139
|
}
|
|
@@ -32094,11 +32150,16 @@ var init_transport = __esm({
|
|
|
32094
32150
|
constructor(deps) {
|
|
32095
32151
|
this.deps = deps;
|
|
32096
32152
|
this.offset = deps.offset ?? 0;
|
|
32153
|
+
this.consumedOffset = this.offset;
|
|
32097
32154
|
this.lines = this.read();
|
|
32098
32155
|
}
|
|
32099
32156
|
deps;
|
|
32100
|
-
/** The byte the next read starts at
|
|
32157
|
+
/** The byte the next read starts at: the read position, moved by whole chunks. */
|
|
32101
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;
|
|
32102
32163
|
/** pi was found dead while the harness still listened. */
|
|
32103
32164
|
exited = false;
|
|
32104
32165
|
closed = false;
|
|
@@ -32151,11 +32212,15 @@ var init_transport = __esm({
|
|
|
32151
32212
|
/** Complete lines out of the buffered bytes; the partial tail waits for more. */
|
|
32152
32213
|
*split(chunk) {
|
|
32153
32214
|
this.buffer = Buffer.concat([this.buffer, Buffer.from(chunk)]);
|
|
32215
|
+
const base = this.offset - this.buffer.length;
|
|
32154
32216
|
let start3 = 0;
|
|
32155
32217
|
for (let i = this.buffer.indexOf(NEWLINE, start3); i >= 0; i = this.buffer.indexOf(NEWLINE, start3)) {
|
|
32156
32218
|
let line3 = this.buffer.subarray(start3, i).toString("utf8");
|
|
32157
32219
|
if (line3.endsWith("\r")) line3 = line3.slice(0, -1);
|
|
32158
|
-
if (line3.length > 0)
|
|
32220
|
+
if (line3.length > 0) {
|
|
32221
|
+
this.consumedOffset = base + i + 1;
|
|
32222
|
+
yield line3;
|
|
32223
|
+
}
|
|
32159
32224
|
start3 = i + 1;
|
|
32160
32225
|
}
|
|
32161
32226
|
this.buffer = this.buffer.subarray(start3);
|
|
@@ -32165,6 +32230,7 @@ var init_transport = __esm({
|
|
|
32165
32230
|
});
|
|
32166
32231
|
|
|
32167
32232
|
// ../../src/core/harness/pi/harness.ts
|
|
32233
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
32168
32234
|
function piHarnessFactsOf(value) {
|
|
32169
32235
|
if (typeof value !== "object" || value === null) return void 0;
|
|
32170
32236
|
const v = value;
|
|
@@ -32210,6 +32276,9 @@ function promptOf(seed) {
|
|
|
32210
32276
|
}
|
|
32211
32277
|
return { message: texts.join("\n\n"), ...images.length > 0 ? { images } : {} };
|
|
32212
32278
|
}
|
|
32279
|
+
function settlementText(s) {
|
|
32280
|
+
return s.action === "synthetic" ? s.text : `The bot restarted while this ${s.toolUse.name} call was in flight; its result was lost \u2014 re-check its effects before re-running it.`;
|
|
32281
|
+
}
|
|
32213
32282
|
function settlementResults(settlements) {
|
|
32214
32283
|
if (settlements.length === 0) return void 0;
|
|
32215
32284
|
return {
|
|
@@ -32217,11 +32286,21 @@ function settlementResults(settlements) {
|
|
|
32217
32286
|
content: settlements.map((s) => ({
|
|
32218
32287
|
type: "tool_result",
|
|
32219
32288
|
toolUseId: s.toolUse.id,
|
|
32220
|
-
content: s
|
|
32289
|
+
content: settlementText(s),
|
|
32221
32290
|
isError: true
|
|
32222
32291
|
}))
|
|
32223
32292
|
};
|
|
32224
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
|
+
}
|
|
32301
|
+
function settlementAnswer(s) {
|
|
32302
|
+
return { content: [{ type: "text", text: settlementText(s) }], isError: true };
|
|
32303
|
+
}
|
|
32225
32304
|
async function runPiHarness(deps, run2) {
|
|
32226
32305
|
const { container, clock: clock3 } = deps;
|
|
32227
32306
|
const now = () => clock3();
|
|
@@ -32263,10 +32342,12 @@ async function runPiHarness(deps, run2) {
|
|
|
32263
32342
|
};
|
|
32264
32343
|
}
|
|
32265
32344
|
bridge.turns = run2.resume?.turn ?? 0;
|
|
32345
|
+
const tail = ledgerTailOf(run2.resume);
|
|
32266
32346
|
const mirror = new PiMirror({
|
|
32267
32347
|
onStep: run2.onStep,
|
|
32268
|
-
seedLength: run2.resume
|
|
32269
|
-
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 } : {}
|
|
32270
32351
|
});
|
|
32271
32352
|
mirror.inboxConsumedSeq = run2.resume?.inboxConsumedSeq ?? 0;
|
|
32272
32353
|
let writeUp;
|
|
@@ -32298,15 +32379,22 @@ async function runPiHarness(deps, run2) {
|
|
|
32298
32379
|
}
|
|
32299
32380
|
};
|
|
32300
32381
|
const forget = deps.registry.register(live);
|
|
32382
|
+
const calls = deps.registry.calls(run2.runId);
|
|
32383
|
+
for (const s of run2.resume?.settlements ?? []) calls?.settle(s.toolUse.id, settlementAnswer(s));
|
|
32301
32384
|
let pid;
|
|
32302
32385
|
let transport;
|
|
32303
32386
|
let facts2;
|
|
32387
|
+
let mirrored = 0;
|
|
32304
32388
|
const save = () => {
|
|
32305
32389
|
if (facts2) {
|
|
32306
|
-
|
|
32390
|
+
facts2 = { ...facts2, logOffset: mirrored };
|
|
32307
32391
|
run2.saveFacts?.(facts2);
|
|
32308
32392
|
}
|
|
32309
32393
|
};
|
|
32394
|
+
const held = () => {
|
|
32395
|
+
if (transport) mirrored = transport.consumedOffset;
|
|
32396
|
+
save();
|
|
32397
|
+
};
|
|
32310
32398
|
let catchingUp = false;
|
|
32311
32399
|
try {
|
|
32312
32400
|
const recorded = run2.resume?.facts;
|
|
@@ -32333,18 +32421,20 @@ async function runPiHarness(deps, run2) {
|
|
|
32333
32421
|
if (reattached && recorded && paths !== void 0) {
|
|
32334
32422
|
pid = recorded.pid;
|
|
32335
32423
|
facts2 = { ...recorded, ...recorded.container === void 0 && here !== void 0 ? { container: here } : {} };
|
|
32424
|
+
mirrored = recorded.logOffset;
|
|
32336
32425
|
transport = new PiRpcTransport({
|
|
32337
32426
|
container,
|
|
32338
32427
|
paths,
|
|
32339
32428
|
pid,
|
|
32340
32429
|
pollMs: deps.pollMs ?? 750,
|
|
32341
32430
|
sleep: deps.sleep,
|
|
32342
|
-
offset:
|
|
32431
|
+
offset: mirrored
|
|
32343
32432
|
});
|
|
32344
32433
|
catchingUp = true;
|
|
32434
|
+
const inFlight = run2.resume?.settlements.length ?? 0;
|
|
32345
32435
|
note(
|
|
32346
32436
|
"resumed",
|
|
32347
|
-
`resumed after a restart: pi still runs in the container (pid ${pid}); continuing its session with ${Math.round(remainingMs / 6e4)} min of budget left`
|
|
32437
|
+
`resumed after a restart: pi still runs in the container (pid ${pid}); continuing its session with ${Math.round(remainingMs / 6e4)} min of budget left` + (inFlight > 0 ? ` \u2014 ${inFlight} call(s) were in flight, each answered with a restart note if pi asks for it again` : "")
|
|
32348
32438
|
);
|
|
32349
32439
|
} else {
|
|
32350
32440
|
paths = await container.makeRoot(run2.runId);
|
|
@@ -32359,7 +32449,8 @@ async function runPiHarness(deps, run2) {
|
|
|
32359
32449
|
...run2.effort ? { effort: run2.effort } : {},
|
|
32360
32450
|
identity: run2.agent.identity,
|
|
32361
32451
|
system: run2.system,
|
|
32362
|
-
relayTools: run2.tools.map((t) => t.name)
|
|
32452
|
+
relayTools: run2.tools.map((t) => t.name),
|
|
32453
|
+
...deps.compaction ? { compaction: deps.compaction } : {}
|
|
32363
32454
|
};
|
|
32364
32455
|
let session;
|
|
32365
32456
|
if (run2.resume) {
|
|
@@ -32415,10 +32506,15 @@ async function runPiHarness(deps, run2) {
|
|
|
32415
32506
|
save();
|
|
32416
32507
|
transport = new PiRpcTransport({ container, paths, pid, pollMs: deps.pollMs ?? 750, sleep: deps.sleep });
|
|
32417
32508
|
}
|
|
32418
|
-
|
|
32419
|
-
|
|
32420
|
-
|
|
32421
|
-
|
|
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" });
|
|
32514
|
+
if (reattached)
|
|
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) });
|
|
32422
32518
|
let warned = false;
|
|
32423
32519
|
let settled = false;
|
|
32424
32520
|
let stopMode;
|
|
@@ -32536,19 +32632,20 @@ ${stagedLine}` : prompt,
|
|
|
32536
32632
|
}
|
|
32537
32633
|
if (obs.response) {
|
|
32538
32634
|
const r = obs.response;
|
|
32539
|
-
if (r.id ===
|
|
32635
|
+
if (r.id === ids.state && r.success === true && typeof r.data?.sessionFile === "string") {
|
|
32540
32636
|
const data = r.data;
|
|
32541
32637
|
facts2 = { ...facts2 ?? { pid, logOffset: 0, root: paths.dir }, sessionFile: String(data.sessionFile) };
|
|
32542
32638
|
save();
|
|
32543
32639
|
}
|
|
32544
|
-
if (r.id ===
|
|
32640
|
+
if (r.id === ids.prompt) {
|
|
32545
32641
|
catchingUp = false;
|
|
32546
32642
|
if (r.success === false) throw new PromptRefused(String(r.error ?? "no reason"));
|
|
32643
|
+
if (!continuing) mirror.expectSeedEcho();
|
|
32547
32644
|
}
|
|
32548
32645
|
}
|
|
32549
|
-
if (obs.message
|
|
32646
|
+
if (obs.message && await mirror.onMessage(obs.message, bridge.turns)) held();
|
|
32550
32647
|
if (obs.compaction) {
|
|
32551
|
-
await mirror.onCompaction(obs.compaction, bridge.turns);
|
|
32648
|
+
if (await mirror.onCompaction(obs.compaction, bridge.turns)) held();
|
|
32552
32649
|
if (!writeUp && !hardStopped && !catchingUp) {
|
|
32553
32650
|
let notepad;
|
|
32554
32651
|
let unavailable = false;
|
|
@@ -32569,7 +32666,6 @@ ${stagedLine}` : prompt,
|
|
|
32569
32666
|
note("harness_error", `a model call failed while the bot was away (${obs.providerError}); continuing`);
|
|
32570
32667
|
else providerError = obs.providerError;
|
|
32571
32668
|
}
|
|
32572
|
-
if (obs.turnEnded) save();
|
|
32573
32669
|
if (obs.settled && !catchingUp) {
|
|
32574
32670
|
settled = true;
|
|
32575
32671
|
break;
|
|
@@ -32583,8 +32679,8 @@ ${stagedLine}` : prompt,
|
|
|
32583
32679
|
}
|
|
32584
32680
|
if (bypass) throw bypass;
|
|
32585
32681
|
if (!settled) {
|
|
32586
|
-
const
|
|
32587
|
-
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)}` : ""}`);
|
|
32588
32684
|
}
|
|
32589
32685
|
if (providerError !== void 0) throw new Error(`the model call failed: ${providerError}`);
|
|
32590
32686
|
const text = bridge.answer() ?? "";
|
|
@@ -33571,6 +33667,9 @@ async function runLoop2(deps, ctx) {
|
|
|
33571
33667
|
harnessUrl,
|
|
33572
33668
|
registry: deps.harness.registry,
|
|
33573
33669
|
...deps.runBearers ? { bearers: deps.runBearers } : {},
|
|
33670
|
+
// The deployment's compaction thresholds ride into pi's settings for
|
|
33671
|
+
// every run on pi (harness-pi item 4); absent, pi's defaults stand.
|
|
33672
|
+
...deps.config.config.pi?.compaction ? { compaction: deps.config.config.pi.compaction } : {},
|
|
33574
33673
|
clock: clock3,
|
|
33575
33674
|
sleep: (ms) => new Promise((r) => setTimeout(r, ms))
|
|
33576
33675
|
},
|
|
@@ -36745,8 +36844,8 @@ var init_types5 = __esm({
|
|
|
36745
36844
|
});
|
|
36746
36845
|
|
|
36747
36846
|
// ../../src/core/runLedger/writeThrough.ts
|
|
36748
|
-
import { randomUUID as
|
|
36749
|
-
function mintGeneration(now = Date.now, random =
|
|
36847
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
36848
|
+
function mintGeneration(now = Date.now, random = randomUUID3) {
|
|
36750
36849
|
const stamp = new Date(now()).toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
36751
36850
|
const gen = `${stamp}-${random().replace(/-/g, "").slice(0, 8)}`;
|
|
36752
36851
|
if (!GEN_PATTERN.test(gen)) throw new Error(`minted generation ${gen} does not match GEN_PATTERN`);
|
|
@@ -43082,6 +43181,13 @@ var init_relay = __esm({
|
|
|
43082
43181
|
}
|
|
43083
43182
|
return answer;
|
|
43084
43183
|
}
|
|
43184
|
+
/** The call's answer is known before it is asked (harness-pi item 8): the
|
|
43185
|
+
* record's settlement for a call in flight when the previous generation
|
|
43186
|
+
* died, whose extension asks again with the same id. Every ask reads it and
|
|
43187
|
+
* the tool never runs; a call already joined keeps the answer it has. */
|
|
43188
|
+
settle(callId, answer) {
|
|
43189
|
+
if (!this.calls.has(callId)) this.calls.set(callId, Promise.resolve(answer));
|
|
43190
|
+
}
|
|
43085
43191
|
end() {
|
|
43086
43192
|
this.ending.abort();
|
|
43087
43193
|
this.calls.clear();
|
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",
|