@coreplane/switchboard 1.220.1 → 1.221.1
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/deploy/cloudflare-resident/worker.ts +87 -22
- 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/execution/residentReuse.ts +98 -0
- package/dist/assets/src/execution/residentSteps.ts +1 -0
- package/dist/assets/web/dist/.vite/manifest.json +18 -18
- package/dist/assets/web/dist/assets/{ResidentDetailPage-DvCt96Dk.js → ResidentDetailPage-iqyj3Kpt.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentsIndexPage-BZaYja1-.js → ResidentsIndexPage-BiECMcX5.js} +1 -1
- package/dist/assets/web/dist/assets/{RunRoutePage-DI4vzCUu.js → RunRoutePage-YCWYYZkj.js} +4 -4
- package/dist/assets/web/dist/assets/{RunsIndexPage-Ch9uP4p4.js → RunsIndexPage-BX6231bA.js} +1 -1
- package/dist/assets/web/dist/assets/{ScheduledPage-DAkAHMCH.js → ScheduledPage-ibRdZaDS.js} +1 -1
- package/dist/assets/web/dist/assets/{StatusDot-CfBonGcV.js → StatusDot-W2x3d782.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-CBD36E3W.js → Tooltip-BLRVgG37.js} +1 -1
- package/dist/assets/web/dist/assets/{dist-DQ1U73LF.js → dist-C3C34ZMu.js} +1 -1
- package/dist/assets/web/dist/assets/{main-CdLnG-yl.js → main-B9dN-Wec.js} +2 -2
- package/dist/cli.js +875 -313
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -356,13 +356,14 @@ function amzDate(now) {
|
|
|
356
356
|
function encodeKey(key) {
|
|
357
357
|
return key.split("/").map(encodeURIComponent).join("/");
|
|
358
358
|
}
|
|
359
|
-
var PRESIGN_TTL_SECONDS, R2ArtifactStore;
|
|
359
|
+
var PRESIGN_TTL_SECONDS, IDENTITY, R2ArtifactStore;
|
|
360
360
|
var init_store = __esm({
|
|
361
361
|
"../../src/artifacts/store.ts"() {
|
|
362
362
|
"use strict";
|
|
363
363
|
init_clock();
|
|
364
364
|
init_config();
|
|
365
365
|
PRESIGN_TTL_SECONDS = ARTIFACT_DEFAULTS.presignTtlSeconds;
|
|
366
|
+
IDENTITY = { "accept-encoding": "identity" };
|
|
366
367
|
R2ArtifactStore = class {
|
|
367
368
|
bucket;
|
|
368
369
|
client;
|
|
@@ -402,7 +403,7 @@ var init_store = __esm({
|
|
|
402
403
|
return this.presign(key, "GET");
|
|
403
404
|
}
|
|
404
405
|
async head(key) {
|
|
405
|
-
const signed = await this.client.sign(new Request(this.objectUrl(key), { method: "HEAD" }), {
|
|
406
|
+
const signed = await this.client.sign(new Request(this.objectUrl(key), { method: "HEAD", headers: IDENTITY }), {
|
|
406
407
|
aws: { datetime: amzDate(this.clock()) }
|
|
407
408
|
});
|
|
408
409
|
const res = await this.fetchImpl(signed);
|
|
@@ -416,7 +417,7 @@ var init_store = __esm({
|
|
|
416
417
|
return { size, contentType: res.headers.get("content-type") ?? "application/octet-stream" };
|
|
417
418
|
}
|
|
418
419
|
async get(key) {
|
|
419
|
-
const signed = await this.client.sign(new Request(this.objectUrl(key), { method: "GET" }), {
|
|
420
|
+
const signed = await this.client.sign(new Request(this.objectUrl(key), { method: "GET", headers: IDENTITY }), {
|
|
420
421
|
aws: { datetime: amzDate(this.clock()) }
|
|
421
422
|
});
|
|
422
423
|
const res = await this.fetchImpl(signed);
|
|
@@ -4139,6 +4140,7 @@ var init_residentSteps = __esm({
|
|
|
4139
4140
|
"ops-dir": "preparing a directory",
|
|
4140
4141
|
"stage-dir": "preparing a directory",
|
|
4141
4142
|
stat: "checking a file",
|
|
4143
|
+
"boot-id": "reading the container's identity",
|
|
4142
4144
|
touch: "touching a marker",
|
|
4143
4145
|
nproc: "counting CPUs",
|
|
4144
4146
|
mutex_wait: "waiting for the workspace",
|
|
@@ -9419,7 +9421,7 @@ async function parseResidentBody(res) {
|
|
|
9419
9421
|
}
|
|
9420
9422
|
return sanitizeResidentBody(data);
|
|
9421
9423
|
}
|
|
9422
|
-
var DETACH_TIMEOUT_MS, ResidentNeedsRefError, ResidentOperations, ResidentExecutor;
|
|
9424
|
+
var DETACH_TIMEOUT_MS, ResidentNeedsRefError, ResidentReuseRefusedError, ResidentOperations, ResidentExecutor;
|
|
9423
9425
|
var init_resident = __esm({
|
|
9424
9426
|
"../../src/execution/resident.ts"() {
|
|
9425
9427
|
"use strict";
|
|
@@ -9451,6 +9453,16 @@ var init_resident = __esm({
|
|
|
9451
9453
|
defaultRef;
|
|
9452
9454
|
needs = "ref";
|
|
9453
9455
|
};
|
|
9456
|
+
ResidentReuseRefusedError = class extends Error {
|
|
9457
|
+
constructor(resource, why) {
|
|
9458
|
+
super(`resident attach: ${resource} cannot reuse this thread's worktree (${why})`);
|
|
9459
|
+
this.resource = resource;
|
|
9460
|
+
this.why = why;
|
|
9461
|
+
this.name = "ResidentReuseRefusedError";
|
|
9462
|
+
}
|
|
9463
|
+
resource;
|
|
9464
|
+
why;
|
|
9465
|
+
};
|
|
9454
9466
|
ResidentOperations = class {
|
|
9455
9467
|
constructor(opts) {
|
|
9456
9468
|
this.opts = opts;
|
|
@@ -9608,6 +9620,7 @@ var init_resident = __esm({
|
|
|
9608
9620
|
if (this.opts.refHint) body.refHint = this.opts.refHint;
|
|
9609
9621
|
if (this.opts.readonly) body.readonly = true;
|
|
9610
9622
|
if (this.opts.sha) body.sha = this.opts.sha;
|
|
9623
|
+
if (this.opts.reuse) body.reuse = true;
|
|
9611
9624
|
const answered = await this.call("/attach", body, timeoutMs, void 0, span);
|
|
9612
9625
|
const data = answered.data;
|
|
9613
9626
|
const status3 = answered.status === 200 && typeof data.error === "string" && typeof data.status === "number" ? data.status : answered.status;
|
|
@@ -9621,6 +9634,7 @@ var init_resident = __esm({
|
|
|
9621
9634
|
sha: data.sha,
|
|
9622
9635
|
...typeof data.workspace === "string" && data.workspace ? { workspace: data.workspace } : {},
|
|
9623
9636
|
...typeof data.user === "string" && data.user ? { user: data.user } : {},
|
|
9637
|
+
...typeof data.container === "string" && data.container ? { container: data.container } : {},
|
|
9624
9638
|
...trace.length > 0 ? { trace } : {},
|
|
9625
9639
|
...typeof data.attachMs === "number" && Number.isFinite(data.attachMs) ? { attachMs: data.attachMs } : {}
|
|
9626
9640
|
};
|
|
@@ -9640,6 +9654,8 @@ var init_resident = __esm({
|
|
|
9640
9654
|
const defaultRef = typeof data.defaultRef === "string" && data.defaultRef ? data.defaultRef : void 0;
|
|
9641
9655
|
return traced(new ResidentNeedsRefError(this.opts.resource, defaultRef));
|
|
9642
9656
|
}
|
|
9657
|
+
if (status3 === 409 && data.needs === "recreate")
|
|
9658
|
+
return traced(new ResidentReuseRefusedError(this.opts.resource, err2));
|
|
9643
9659
|
if (status3 === 404) return traced(new Error(`resident attach: ${this.opts.resource} is not onboarded (${err2})`));
|
|
9644
9660
|
return traced(new Error(`resident attach failed for ${this.opts.resource}: ${err2}`));
|
|
9645
9661
|
}
|
|
@@ -9994,11 +10010,33 @@ var init_githubApp = __esm({
|
|
|
9994
10010
|
// ../../src/execution/factory.ts
|
|
9995
10011
|
import { resolve as resolve7 } from "node:path";
|
|
9996
10012
|
import { mkdirSync as mkdirSync7 } from "node:fs";
|
|
10013
|
+
function workspaceBindingOf(value) {
|
|
10014
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
10015
|
+
const v = value;
|
|
10016
|
+
if (typeof v.backend !== "string" || !BACKENDS.includes(v.backend)) return void 0;
|
|
10017
|
+
return {
|
|
10018
|
+
backend: v.backend,
|
|
10019
|
+
...typeof v.workspace === "string" && v.workspace ? { workspace: v.workspace } : {},
|
|
10020
|
+
...typeof v.user === "string" && v.user ? { user: v.user } : {},
|
|
10021
|
+
...typeof v.container === "string" && v.container ? { container: v.container } : {}
|
|
10022
|
+
};
|
|
10023
|
+
}
|
|
10024
|
+
function workspaceBindingFor(selection, machine = "repo-resident") {
|
|
10025
|
+
if (machine === "none" || selection.backend === void 0) return void 0;
|
|
10026
|
+
const b = selection.binding;
|
|
10027
|
+
return {
|
|
10028
|
+
backend: selection.backend,
|
|
10029
|
+
...b?.workspace !== void 0 ? { workspace: b.workspace } : {},
|
|
10030
|
+
...b?.user !== void 0 ? { user: b.user } : {},
|
|
10031
|
+
...b?.container !== void 0 ? { container: b.container } : {}
|
|
10032
|
+
};
|
|
10033
|
+
}
|
|
9997
10034
|
async function makeExecutor(opts, ctx, span) {
|
|
9998
10035
|
const machine = ctx.profile.machine;
|
|
9999
10036
|
if (machine === "none") {
|
|
10000
10037
|
return { executor: new NullExecutor(ctx.agent.name), backend: "local" };
|
|
10001
10038
|
}
|
|
10039
|
+
if (ctx.reattach !== void 0) return reattachWorkspace(opts, ctx, ctx.reattach, span);
|
|
10002
10040
|
if (machine === "blank") {
|
|
10003
10041
|
return {
|
|
10004
10042
|
executor: await makePerThreadExecutor(opts, { threadKey: ctx.threadKey, resolveEnvs: async () => ({}) }),
|
|
@@ -10056,6 +10094,58 @@ async function makeExecutor(opts, ctx, span) {
|
|
|
10056
10094
|
...failedAttach ? { trace: failedAttach.steps } : {}
|
|
10057
10095
|
};
|
|
10058
10096
|
}
|
|
10097
|
+
async function reattachWorkspace(opts, ctx, recorded, span) {
|
|
10098
|
+
const refuse3 = (why) => new WorkspaceReattachRefusedError(recorded, oneLine(why));
|
|
10099
|
+
if (recorded.backend !== "resident") {
|
|
10100
|
+
const input = ctx.profile.machine === "blank" ? { threadKey: ctx.threadKey, resolveEnvs: async () => ({}) } : perThreadCheckout(ctx);
|
|
10101
|
+
return { executor: await makePerThreadExecutor(opts, input), backend: perThreadBackend(opts) };
|
|
10102
|
+
}
|
|
10103
|
+
const resident = opts.execution?.resident;
|
|
10104
|
+
if (!resident) throw refuse3("no resident backend is configured in this process");
|
|
10105
|
+
if (!ctx.repo) throw refuse3("the run's row names no repository to re-attach on");
|
|
10106
|
+
const tokenEnv = resident.tokenEnv ?? "RESIDENT_OPERATOR_TOKEN";
|
|
10107
|
+
const token2 = processSecrets.named(tokenEnv);
|
|
10108
|
+
if (!token2) throw new Error(`execution.resident is configured but ${tokenEnv} is not set`);
|
|
10109
|
+
const resource = repoResourceId(ctx.repo);
|
|
10110
|
+
const probe = await probeResident(resident, token2, resource, span);
|
|
10111
|
+
if (probe.kind === "unreachable") throw refuse3(`resident unreachable (${probe.error})`);
|
|
10112
|
+
if (!isServiceable(probe.state, probe.reason))
|
|
10113
|
+
throw refuse3(`resident ${probe.state}${probe.reason ? ` (${probe.reason})` : ""}`);
|
|
10114
|
+
const nonWarm = probe.state === "warm" ? void 0 : oneLine(`${probe.state}${probe.reason ? ` (${probe.reason})` : ""}`);
|
|
10115
|
+
const executor = new ResidentExecutor({
|
|
10116
|
+
baseUrl: resident.baseUrl,
|
|
10117
|
+
token: token2.reveal(),
|
|
10118
|
+
resource,
|
|
10119
|
+
threadKey: ctx.threadKey,
|
|
10120
|
+
refHint: ctx.ref,
|
|
10121
|
+
readonly: ctx.profile.identity === "read" ? true : void 0,
|
|
10122
|
+
sha: ctx.headSha,
|
|
10123
|
+
reuse: true
|
|
10124
|
+
});
|
|
10125
|
+
let binding;
|
|
10126
|
+
try {
|
|
10127
|
+
binding = await executor.attach(span);
|
|
10128
|
+
} catch (err2) {
|
|
10129
|
+
throw refuse3(err2 instanceof Error ? err2.message : String(err2));
|
|
10130
|
+
}
|
|
10131
|
+
const same = (recordedValue, answered) => recordedValue === void 0 || answered === void 0 || recordedValue === answered;
|
|
10132
|
+
if (!same(recorded.workspace, binding.workspace) || !same(recorded.user, binding.user)) {
|
|
10133
|
+
const name = (workspace, user) => `${workspace ?? "(unnamed)"} as ${user ?? "(unnamed)"}`;
|
|
10134
|
+
throw refuse3(
|
|
10135
|
+
`the resident's worktree for this thread is ${name(binding.workspace, binding.user)}, not the run's recorded ${name(recorded.workspace, recorded.user)}`
|
|
10136
|
+
);
|
|
10137
|
+
}
|
|
10138
|
+
const where = `${resource.replace(/^repo:/, "")} \xB7 ${binding.ref}@${binding.sha.slice(0, 7)}`;
|
|
10139
|
+
return {
|
|
10140
|
+
executor,
|
|
10141
|
+
resident: true,
|
|
10142
|
+
backend: "resident",
|
|
10143
|
+
...binding.trace ? { trace: binding.trace } : {},
|
|
10144
|
+
...binding.attachMs !== void 0 ? { attachMs: binding.attachMs } : {},
|
|
10145
|
+
binding,
|
|
10146
|
+
note: nonWarm ? `resident ${nonWarm} \xB7 ${where} \xB7 re-attached to the run's worktree` : `resident \xB7 ${where} \xB7 re-attached to the run's worktree`
|
|
10147
|
+
};
|
|
10148
|
+
}
|
|
10059
10149
|
async function openResident(opts, nonWarm, span) {
|
|
10060
10150
|
let executor = new ResidentExecutor(opts);
|
|
10061
10151
|
let binding;
|
|
@@ -10206,7 +10296,7 @@ function perThreadBackend(opts) {
|
|
|
10206
10296
|
const type = opts.execution?.type ?? "local";
|
|
10207
10297
|
return type === "e2b" ? "e2b" : type === "cloudflare" ? "sandbox" : "local";
|
|
10208
10298
|
}
|
|
10209
|
-
var PROBE_OUTAGE_WINDOW_MS, probeOutage, NullExecutor;
|
|
10299
|
+
var BACKENDS, WorkspaceReattachRefusedError, PROBE_OUTAGE_WINDOW_MS, probeOutage, NullExecutor;
|
|
10210
10300
|
var init_factory = __esm({
|
|
10211
10301
|
"../../src/execution/factory.ts"() {
|
|
10212
10302
|
"use strict";
|
|
@@ -10221,6 +10311,17 @@ var init_factory = __esm({
|
|
|
10221
10311
|
init_residentState();
|
|
10222
10312
|
init_clock();
|
|
10223
10313
|
init_secrets2();
|
|
10314
|
+
BACKENDS = ["local", "resident", "sandbox", "e2b"];
|
|
10315
|
+
WorkspaceReattachRefusedError = class extends Error {
|
|
10316
|
+
constructor(recorded, why) {
|
|
10317
|
+
super(`the run's workspace on the ${recorded.backend} backend could not be re-attached: ${why}`);
|
|
10318
|
+
this.recorded = recorded;
|
|
10319
|
+
this.why = why;
|
|
10320
|
+
this.name = "WorkspaceReattachRefusedError";
|
|
10321
|
+
}
|
|
10322
|
+
recorded;
|
|
10323
|
+
why;
|
|
10324
|
+
};
|
|
10224
10325
|
PROBE_OUTAGE_WINDOW_MS = 3e4;
|
|
10225
10326
|
NullExecutor = class {
|
|
10226
10327
|
constructor(agentName) {
|
|
@@ -20508,7 +20609,7 @@ function createRunsService(deps) {
|
|
|
20508
20609
|
const analyze = deps.analyze ?? ((events, opts) => analyzeRunFriction(events, opts));
|
|
20509
20610
|
const clock3 = deps.clock ?? systemClock;
|
|
20510
20611
|
const warn = deps.warn ?? ((m) => console.warn(m));
|
|
20511
|
-
const
|
|
20612
|
+
const describe12 = (err2) => err2 instanceof Error ? err2.message : String(err2);
|
|
20512
20613
|
let listing;
|
|
20513
20614
|
const liveRows = () => {
|
|
20514
20615
|
if (!ledger) return null;
|
|
@@ -20528,7 +20629,7 @@ function createRunsService(deps) {
|
|
|
20528
20629
|
try {
|
|
20529
20630
|
rows = await pending2;
|
|
20530
20631
|
} catch (err2) {
|
|
20531
|
-
warn(`[runs] run ledger list failed \u2014 showing this process's runs only: ${
|
|
20632
|
+
warn(`[runs] run ledger list failed \u2014 showing this process's runs only: ${describe12(err2)}`);
|
|
20532
20633
|
return [];
|
|
20533
20634
|
}
|
|
20534
20635
|
const foreign = rows.filter((row) => !registry.getById(row.runId));
|
|
@@ -20538,7 +20639,7 @@ function createRunsService(deps) {
|
|
|
20538
20639
|
try {
|
|
20539
20640
|
events = await ledger.readEvents(row.runId);
|
|
20540
20641
|
} catch (err2) {
|
|
20541
|
-
warn(`[runs] run ledger events read failed for ${row.runId}: ${
|
|
20642
|
+
warn(`[runs] run ledger events read failed for ${row.runId}: ${describe12(err2)}`);
|
|
20542
20643
|
}
|
|
20543
20644
|
return ledgerView(row, events);
|
|
20544
20645
|
})
|
|
@@ -20552,7 +20653,7 @@ function createRunsService(deps) {
|
|
|
20552
20653
|
if (!row) return null;
|
|
20553
20654
|
return { row, events: await ledger.readEvents(id) };
|
|
20554
20655
|
} catch (err2) {
|
|
20555
|
-
warn(`[runs] run ledger read failed for ${id}: ${
|
|
20656
|
+
warn(`[runs] run ledger read failed for ${id}: ${describe12(err2)}`);
|
|
20556
20657
|
return null;
|
|
20557
20658
|
}
|
|
20558
20659
|
};
|
|
@@ -20570,7 +20671,7 @@ function createRunsService(deps) {
|
|
|
20570
20671
|
row = await storeSummary(id);
|
|
20571
20672
|
} catch (err2) {
|
|
20572
20673
|
warn(
|
|
20573
|
-
`[runs] history store read failed for ${id} \u2014 serving the registry row without its record: ${
|
|
20674
|
+
`[runs] history store read failed for ${id} \u2014 serving the registry row without its record: ${describe12(err2)}`
|
|
20574
20675
|
);
|
|
20575
20676
|
return {};
|
|
20576
20677
|
}
|
|
@@ -20741,7 +20842,7 @@ function createRunsService(deps) {
|
|
|
20741
20842
|
const r = await ledger.requestStop(id, mode);
|
|
20742
20843
|
if (r.ok) return { ok: true, value: { id, mode, state: "stopping" } };
|
|
20743
20844
|
} catch (err2) {
|
|
20744
|
-
warn(`[runs] run ledger stop failed for ${id}: ${
|
|
20845
|
+
warn(`[runs] run ledger stop failed for ${id}: ${describe12(err2)}`);
|
|
20745
20846
|
}
|
|
20746
20847
|
}
|
|
20747
20848
|
return await storeSummary(id) ? conflict : notFound;
|
|
@@ -26605,9 +26706,10 @@ var init_runs2 = __esm({
|
|
|
26605
26706
|
request.budget = budget;
|
|
26606
26707
|
}
|
|
26607
26708
|
const spawn7 = ctx.spawn ?? nullSpawnCapability;
|
|
26709
|
+
const conversation = ctx.conversation ? await ctx.conversation() : void 0;
|
|
26608
26710
|
const out = await spawn7.spawn(request, {
|
|
26609
26711
|
remainingMs: ctx.remainingMs?.() ?? Number.POSITIVE_INFINITY,
|
|
26610
|
-
...
|
|
26712
|
+
...conversation ? { conversation } : {}
|
|
26611
26713
|
});
|
|
26612
26714
|
if (out.kind === "refused") return `spawn refused (${out.reason}): ${out.message}`;
|
|
26613
26715
|
return `spawned a ${preset} run: ${out.runId} in thread ${out.threadKey}${out.url ? ` (${out.url})` : ""} \u2014 it runs on its own; await_runs waits for it and returns its reply; get_run_status ${out.runId} answers its progress meanwhile.`;
|
|
@@ -26786,6 +26888,252 @@ var init_runs2 = __esm({
|
|
|
26786
26888
|
}
|
|
26787
26889
|
});
|
|
26788
26890
|
|
|
26891
|
+
// ../../src/core/dispatch/staging.ts
|
|
26892
|
+
function stagedBasename(index, name) {
|
|
26893
|
+
return `${index}-${safeBasename(name)}`;
|
|
26894
|
+
}
|
|
26895
|
+
function pullCommandFor(url, basename4) {
|
|
26896
|
+
return `mkdir -p ${ATTACHMENTS_DIR} && curl -fsS -o ${shellQuote(`${ATTACHMENTS_DIR}/${basename4}`)} ${shellQuote(url)}`;
|
|
26897
|
+
}
|
|
26898
|
+
function excludeCommand() {
|
|
26899
|
+
const entry = shellQuote(`${ATTACHMENTS_DIR}/`);
|
|
26900
|
+
return `mkdir -p .git/info && { grep -qxF ${entry} .git/info/exclude 2>/dev/null || echo ${entry} >> .git/info/exclude; }`;
|
|
26901
|
+
}
|
|
26902
|
+
function formatSize(bytes) {
|
|
26903
|
+
if (bytes >= 1e9) return `${(bytes / 1e9).toFixed(1)} GB`;
|
|
26904
|
+
if (bytes >= 1e6) return `${Math.round(bytes / 1e6)} MB`;
|
|
26905
|
+
if (bytes >= 1e3) return `${Math.round(bytes / 1e3)} KB`;
|
|
26906
|
+
return `${bytes} B`;
|
|
26907
|
+
}
|
|
26908
|
+
function attachmentsLine(outcomes) {
|
|
26909
|
+
const landed = outcomes.filter((o) => o.error === void 0);
|
|
26910
|
+
const failed = outcomes.filter((o) => o.error !== void 0);
|
|
26911
|
+
const parts = [];
|
|
26912
|
+
if (landed.length > 0) {
|
|
26913
|
+
parts.push(
|
|
26914
|
+
`Attached files are in ./${ATTACHMENTS_DIR}/: ${landed.map(
|
|
26915
|
+
(o) => `${o.basename} (${formatSize(o.file.size)}, ${o.file.type}${o.earlier ? ", from earlier in the thread" : ""})`
|
|
26916
|
+
).join(", ")}`
|
|
26917
|
+
);
|
|
26918
|
+
}
|
|
26919
|
+
for (const o of failed) parts.push(`${o.file.name} could not be staged: ${o.error}`);
|
|
26920
|
+
return parts.join(". ");
|
|
26921
|
+
}
|
|
26922
|
+
function noWorkspaceLine(files) {
|
|
26923
|
+
return files.map(
|
|
26924
|
+
(f) => `this agent has no workspace for ${f.name} (${formatSize(f.size)}, ${f.type}); ask \`agent:coding\` to work with it`
|
|
26925
|
+
).join(". ");
|
|
26926
|
+
}
|
|
26927
|
+
function stagingIndex() {
|
|
26928
|
+
let n2 = 0;
|
|
26929
|
+
return () => ++n2;
|
|
26930
|
+
}
|
|
26931
|
+
async function copyStaged(files, deps) {
|
|
26932
|
+
return Promise.all(
|
|
26933
|
+
files.map(async (file) => {
|
|
26934
|
+
const index = deps.nextIndex();
|
|
26935
|
+
const basename4 = stagedBasename(index, file.name);
|
|
26936
|
+
const key = inboundKey(deps.threadKey, file.messageId, index, file.name);
|
|
26937
|
+
try {
|
|
26938
|
+
await deps.store.copyFromUrl({ url: file.url, size: file.size, key });
|
|
26939
|
+
deps.publish?.({
|
|
26940
|
+
type: "artifact",
|
|
26941
|
+
direction: "in",
|
|
26942
|
+
key,
|
|
26943
|
+
name: file.name,
|
|
26944
|
+
size: file.size,
|
|
26945
|
+
contentType: file.type
|
|
26946
|
+
});
|
|
26947
|
+
return { file, basename: basename4, key };
|
|
26948
|
+
} catch (err2) {
|
|
26949
|
+
return { file, basename: basename4, key, error: `the copy into the store failed: ${describe4(err2)}` };
|
|
26950
|
+
}
|
|
26951
|
+
})
|
|
26952
|
+
);
|
|
26953
|
+
}
|
|
26954
|
+
async function pullStaged(outcomes, deps) {
|
|
26955
|
+
const landed = outcomes.filter((o) => o.error === void 0);
|
|
26956
|
+
if (landed.length === 0) return [...outcomes];
|
|
26957
|
+
const timeoutMs = deps.timeoutMs ?? BASH_TIMEOUT_MAX_MS;
|
|
26958
|
+
const opts = { timeoutMs, ...deps.signal ? { signal: deps.signal } : {} };
|
|
26959
|
+
if (deps.resident) await deps.executor.exec(excludeCommand(), opts);
|
|
26960
|
+
const pulled = /* @__PURE__ */ new Map();
|
|
26961
|
+
for (const o of landed) {
|
|
26962
|
+
const url = await deps.store.presignGet(o.key);
|
|
26963
|
+
const out = await deps.executor.exec(pullCommandFor(url, o.basename), opts);
|
|
26964
|
+
pulled.set(o.key, parseExitPrefix(out).failed ? `the pull into the workspace failed: ${out.trim()}` : void 0);
|
|
26965
|
+
}
|
|
26966
|
+
return outcomes.map((o) => {
|
|
26967
|
+
const error = o.error ?? pulled.get(o.key);
|
|
26968
|
+
if (error !== void 0) return { ...o, error };
|
|
26969
|
+
const { error: _dropped, ...landedOutcome } = o;
|
|
26970
|
+
return landedOutcome;
|
|
26971
|
+
});
|
|
26972
|
+
}
|
|
26973
|
+
function stageThreadArtifacts(artifacts, deps) {
|
|
26974
|
+
const outcomes = [];
|
|
26975
|
+
for (const a of artifacts) {
|
|
26976
|
+
const file = { name: a.name, size: a.size, type: a.contentType };
|
|
26977
|
+
if (a.held === void 0) {
|
|
26978
|
+
outcomes.push({
|
|
26979
|
+
file,
|
|
26980
|
+
basename: safeBasename(a.name),
|
|
26981
|
+
key: a.key,
|
|
26982
|
+
earlier: true,
|
|
26983
|
+
error: "the store could not be asked whether it still holds it"
|
|
26984
|
+
});
|
|
26985
|
+
continue;
|
|
26986
|
+
}
|
|
26987
|
+
if (!a.held) {
|
|
26988
|
+
outcomes.push({
|
|
26989
|
+
file,
|
|
26990
|
+
basename: safeBasename(a.name),
|
|
26991
|
+
key: a.key,
|
|
26992
|
+
earlier: true,
|
|
26993
|
+
error: "the store no longer holds it (its retention passed)"
|
|
26994
|
+
});
|
|
26995
|
+
continue;
|
|
26996
|
+
}
|
|
26997
|
+
const basename4 = stagedBasename(deps.nextIndex(), a.name);
|
|
26998
|
+
deps.publish?.({
|
|
26999
|
+
type: "artifact",
|
|
27000
|
+
direction: "in",
|
|
27001
|
+
key: a.key,
|
|
27002
|
+
name: a.name,
|
|
27003
|
+
size: a.size,
|
|
27004
|
+
contentType: a.contentType
|
|
27005
|
+
});
|
|
27006
|
+
outcomes.push({ file, basename: basename4, key: a.key, earlier: true });
|
|
27007
|
+
}
|
|
27008
|
+
return outcomes;
|
|
27009
|
+
}
|
|
27010
|
+
async function stageIntoWorkspace(files, deps) {
|
|
27011
|
+
const outcomes = await pullStaged(await copyStaged(files, deps), deps);
|
|
27012
|
+
return { line: attachmentsLine(outcomes), outcomes };
|
|
27013
|
+
}
|
|
27014
|
+
var ATTACHMENTS_DIR, WorkspaceFiles, describe4;
|
|
27015
|
+
var init_staging = __esm({
|
|
27016
|
+
"../../src/core/dispatch/staging.ts"() {
|
|
27017
|
+
"use strict";
|
|
27018
|
+
init_keys();
|
|
27019
|
+
init_bashTimeout();
|
|
27020
|
+
init_shellQuote();
|
|
27021
|
+
init_runEvents();
|
|
27022
|
+
ATTACHMENTS_DIR = "attachments";
|
|
27023
|
+
WorkspaceFiles = class {
|
|
27024
|
+
paths = /* @__PURE__ */ new Map();
|
|
27025
|
+
/** Every outcome that landed: its key now names a workspace path. */
|
|
27026
|
+
record(outcomes) {
|
|
27027
|
+
for (const o of outcomes) if (o.error === void 0) this.paths.set(o.key, `${ATTACHMENTS_DIR}/${o.basename}`);
|
|
27028
|
+
}
|
|
27029
|
+
pathOf(key) {
|
|
27030
|
+
return this.paths.get(key);
|
|
27031
|
+
}
|
|
27032
|
+
};
|
|
27033
|
+
describe4 = (err2) => err2 instanceof Error ? err2.message : String(err2);
|
|
27034
|
+
}
|
|
27035
|
+
});
|
|
27036
|
+
|
|
27037
|
+
// ../../src/core/dispatch/threadAssets.ts
|
|
27038
|
+
function threadAssetsOf(runsOldestFirst) {
|
|
27039
|
+
const seen = /* @__PURE__ */ new Set();
|
|
27040
|
+
const out = [];
|
|
27041
|
+
for (const run2 of runsOldestFirst) {
|
|
27042
|
+
for (const e of run2.events) {
|
|
27043
|
+
if (e.type !== "artifact" || seen.has(e.key)) continue;
|
|
27044
|
+
seen.add(e.key);
|
|
27045
|
+
out.push({
|
|
27046
|
+
key: e.key,
|
|
27047
|
+
name: e.name,
|
|
27048
|
+
size: e.size,
|
|
27049
|
+
contentType: e.contentType,
|
|
27050
|
+
direction: e.direction,
|
|
27051
|
+
runId: run2.id,
|
|
27052
|
+
...e.seq !== void 0 ? { seq: e.seq } : {}
|
|
27053
|
+
});
|
|
27054
|
+
}
|
|
27055
|
+
}
|
|
27056
|
+
return out;
|
|
27057
|
+
}
|
|
27058
|
+
async function readThreadAssets(deps, threadKey, warn = (line3) => console.warn(line3)) {
|
|
27059
|
+
const runs = [];
|
|
27060
|
+
let before;
|
|
27061
|
+
try {
|
|
27062
|
+
for (; ; ) {
|
|
27063
|
+
const page2 = await deps.runs.listRuns({
|
|
27064
|
+
status: "all",
|
|
27065
|
+
visibleTo: { kind: "all" },
|
|
27066
|
+
threadKey,
|
|
27067
|
+
limit: THREAD_ASSETS_PAGE,
|
|
27068
|
+
...before !== void 0 ? { before: before.finishedAt, beforeId: before.id } : {}
|
|
27069
|
+
});
|
|
27070
|
+
runs.push(...page2.runs);
|
|
27071
|
+
if (page2.storeUnavailable) {
|
|
27072
|
+
warn(
|
|
27073
|
+
`[thread] ${threadKey}: listing its runs for their files answered live rows only after ${runs.length} run(s) \u2014 the run store was unavailable`
|
|
27074
|
+
);
|
|
27075
|
+
break;
|
|
27076
|
+
}
|
|
27077
|
+
if (page2.nextBefore === void 0) break;
|
|
27078
|
+
before = page2.nextBefore;
|
|
27079
|
+
}
|
|
27080
|
+
} catch (err2) {
|
|
27081
|
+
warn(
|
|
27082
|
+
`[thread] ${threadKey}: listing its runs for their files stopped after ${runs.length} run(s) \u2014 ${describe5(err2)}`
|
|
27083
|
+
);
|
|
27084
|
+
}
|
|
27085
|
+
const perRun = [];
|
|
27086
|
+
for (const run2 of runs.reverse()) {
|
|
27087
|
+
const events = [];
|
|
27088
|
+
let afterSeq;
|
|
27089
|
+
try {
|
|
27090
|
+
for (; ; ) {
|
|
27091
|
+
const r = await deps.runs.getRunEvents(run2.id, afterSeq === void 0 ? {} : { afterSeq });
|
|
27092
|
+
if (!r.ok) {
|
|
27093
|
+
warn(`[thread] ${run2.id}: reading its files stopped after ${events.length} event(s) \u2014 ${r.error}`);
|
|
27094
|
+
break;
|
|
27095
|
+
}
|
|
27096
|
+
events.push(...r.value.events);
|
|
27097
|
+
if (r.value.nextAfterSeq === void 0) break;
|
|
27098
|
+
afterSeq = r.value.nextAfterSeq;
|
|
27099
|
+
}
|
|
27100
|
+
} catch (err2) {
|
|
27101
|
+
warn(`[thread] ${run2.id}: reading its files failed after ${events.length} event(s) \u2014 ${describe5(err2)}`);
|
|
27102
|
+
}
|
|
27103
|
+
perRun.push({ id: run2.id, events });
|
|
27104
|
+
}
|
|
27105
|
+
return Promise.all(
|
|
27106
|
+
threadAssetsOf(perRun).map(async (asset) => {
|
|
27107
|
+
try {
|
|
27108
|
+
return { ...asset, held: await deps.store.head(asset.key) !== null };
|
|
27109
|
+
} catch (err2) {
|
|
27110
|
+
warn(`[thread] ${asset.key}: the store could not be asked whether it holds it \u2014 ${describe5(err2)}`);
|
|
27111
|
+
return asset;
|
|
27112
|
+
}
|
|
27113
|
+
})
|
|
27114
|
+
);
|
|
27115
|
+
}
|
|
27116
|
+
function describeAsset(asset, path) {
|
|
27117
|
+
const what = `${asset.name} (${formatSize(asset.size)}, ${asset.contentType})`;
|
|
27118
|
+
const origin = asset.direction === "in" ? "received on this thread" : `produced by run ${asset.runId}`;
|
|
27119
|
+
return `${what} \u2014 ${origin}; ${whereIs(asset, path)}`;
|
|
27120
|
+
}
|
|
27121
|
+
function whereIs(asset, path) {
|
|
27122
|
+
if (path !== void 0) return `in this workspace at ./${path}`;
|
|
27123
|
+
if (asset.held === false) return "no longer in the store (its retention passed)";
|
|
27124
|
+
if (asset.held === void 0) return "the store could not be asked whether it still holds it";
|
|
27125
|
+
return asset.direction === "out" ? "on that run's page, not in this workspace" : "in the store, not in this workspace";
|
|
27126
|
+
}
|
|
27127
|
+
var THREAD_ASSETS_PAGE, describe5;
|
|
27128
|
+
var init_threadAssets = __esm({
|
|
27129
|
+
"../../src/core/dispatch/threadAssets.ts"() {
|
|
27130
|
+
"use strict";
|
|
27131
|
+
init_staging();
|
|
27132
|
+
THREAD_ASSETS_PAGE = 50;
|
|
27133
|
+
describe5 = (err2) => err2 instanceof Error ? err2.message : String(err2);
|
|
27134
|
+
}
|
|
27135
|
+
});
|
|
27136
|
+
|
|
26789
27137
|
// ../../src/core/runLedger/sessionLog.ts
|
|
26790
27138
|
function sessionKey(threadKey, agent) {
|
|
26791
27139
|
return `${threadKey}:${agent ?? "-"}`;
|
|
@@ -26807,31 +27155,50 @@ var init_sessionLog = __esm({
|
|
|
26807
27155
|
});
|
|
26808
27156
|
|
|
26809
27157
|
// ../../src/tools/session.ts
|
|
26810
|
-
function sessionCapabilityFor(run2, ledger) {
|
|
27158
|
+
function sessionCapabilityFor(run2, ledger, assets) {
|
|
26811
27159
|
const session = run2?.session;
|
|
26812
27160
|
if (!session) return void 0;
|
|
26813
27161
|
return {
|
|
26814
27162
|
session,
|
|
26815
27163
|
search: (query, limit) => ledger.searchSession(session.key, query, limit),
|
|
26816
27164
|
readTurn: async (idx) => (await ledger.readSession(session.key, idx, idx)).messages[0],
|
|
27165
|
+
readConversation: async () => (await ledger.readSession(session.key, session.seedFrom)).messages,
|
|
26817
27166
|
readNotepad: () => ledger.readNotepad(session.key),
|
|
26818
|
-
writeNotepad: (text) => ledger.writeNotepad(session.key, text)
|
|
27167
|
+
writeNotepad: (text) => ledger.writeNotepad(session.key, text),
|
|
27168
|
+
...assets ? { assets: assets.read, workspacePathOf: assets.pathOf } : {}
|
|
26819
27169
|
};
|
|
26820
27170
|
}
|
|
27171
|
+
function assetView(asset, path) {
|
|
27172
|
+
return {
|
|
27173
|
+
name: asset.name,
|
|
27174
|
+
size: asset.size,
|
|
27175
|
+
type: asset.contentType,
|
|
27176
|
+
[asset.direction === "in" ? "received" : "produced"]: `run ${asset.runId}`,
|
|
27177
|
+
key: asset.key,
|
|
27178
|
+
where: whereIs(asset, path)
|
|
27179
|
+
};
|
|
27180
|
+
}
|
|
27181
|
+
function filesNamedIn(text, catalogue) {
|
|
27182
|
+
return catalogue.filter((a) => [a.name, safeBasename(a.name)].some((n2) => nameAt2(n2).test(text)));
|
|
27183
|
+
}
|
|
26821
27184
|
async function mayRead(ctx) {
|
|
26822
27185
|
if (!ctx.runs?.runId) return false;
|
|
26823
27186
|
const res = await ctx.runs.service.getRun(ctx.runs.runId);
|
|
26824
27187
|
return res.ok && authorize(ctx.runs.actor, "runs:read", runResource(res.value)).allow;
|
|
26825
27188
|
}
|
|
26826
|
-
var UNAVAILABLE3, DEFAULT_HITS, MAX_HITS, SNIPPET_CHARS, snippetOf, recallTool, notesTool, SESSION_TOOLS;
|
|
27189
|
+
var FILE_BEARING, nameAt2, UNAVAILABLE3, DEFAULT_HITS, MAX_HITS, SNIPPET_CHARS, snippetOf, recallTool, notesTool, SESSION_TOOLS;
|
|
26827
27190
|
var init_session = __esm({
|
|
26828
27191
|
"../../src/tools/session.ts"() {
|
|
26829
27192
|
"use strict";
|
|
27193
|
+
init_keys();
|
|
26830
27194
|
init_authorize();
|
|
27195
|
+
init_threadAssets();
|
|
26831
27196
|
init_runEvents();
|
|
26832
27197
|
init_sessionLog();
|
|
26833
27198
|
init_runRecord();
|
|
26834
27199
|
init_runsService();
|
|
27200
|
+
FILE_BEARING = /attachments\/|attach_file|attached files/i;
|
|
27201
|
+
nameAt2 = (name) => new RegExp(`(?<![A-Za-z0-9._])${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![A-Za-z0-9._-])`);
|
|
26835
27202
|
UNAVAILABLE3 = "the session tools are not available in this context: this run has no session log.";
|
|
26836
27203
|
DEFAULT_HITS = 5;
|
|
26837
27204
|
MAX_HITS = 50;
|
|
@@ -26842,7 +27209,7 @@ var init_session = __esm({
|
|
|
26842
27209
|
};
|
|
26843
27210
|
recallTool = {
|
|
26844
27211
|
name: "recall",
|
|
26845
|
-
description: "Search this conversation's whole log \u2014 every turn of this thread on this agent, earlier runs' included and everything a compaction removed from your window \u2014 for words, and get the matching turns in relevance order with their turn numbers and a snippet; or pass `turn` to read one turn whole (a tool result, a command, a message). Use it when you need something said or seen earlier that is not in front of you: a failing test's name, a command's output, a decision. `limit` defaults to 5 (at most 50).",
|
|
27212
|
+
description: "Search this conversation's whole log \u2014 every turn of this thread on this agent, earlier runs' included and everything a compaction removed from your window \u2014 for words, and get the matching turns in relevance order with their turn numbers and a snippet; or pass `turn` to read one turn whole (a tool result, a command, a message). Use it when you need something said or seen earlier that is not in front of you: a failing test's name, a command's output, a decision. `limit` defaults to 5 (at most 50). A hit that names a file of this thread carries the file's key and where it is for this run; `assets: true` lists every file the thread received or its runs produced instead of searching.",
|
|
26846
27213
|
inputSchema: {
|
|
26847
27214
|
type: "object",
|
|
26848
27215
|
properties: {
|
|
@@ -26851,6 +27218,10 @@ var init_session = __esm({
|
|
|
26851
27218
|
turn: {
|
|
26852
27219
|
type: "integer",
|
|
26853
27220
|
description: "A turn number from an earlier recall: returns that turn whole instead of searching"
|
|
27221
|
+
},
|
|
27222
|
+
assets: {
|
|
27223
|
+
type: "boolean",
|
|
27224
|
+
description: "List the thread's files \u2014 received on its messages or produced by its runs \u2014 with their keys and where each is for this run, instead of searching"
|
|
26854
27225
|
}
|
|
26855
27226
|
}
|
|
26856
27227
|
},
|
|
@@ -26859,13 +27230,30 @@ var init_session = __esm({
|
|
|
26859
27230
|
if (!ctx.session) return UNAVAILABLE3;
|
|
26860
27231
|
const turn = typeof input.turn === "number" ? Math.trunc(input.turn) : void 0;
|
|
26861
27232
|
const query = typeof input.query === "string" ? input.query.trim() : "";
|
|
26862
|
-
|
|
26863
|
-
if (
|
|
27233
|
+
const listAssets = input.assets === true;
|
|
27234
|
+
if (turn === void 0 && query.length === 0 && !listAssets)
|
|
27235
|
+
return "recall needs a query, a turn number or assets: true.";
|
|
27236
|
+
if (!await mayRead(ctx)) {
|
|
27237
|
+
return JSON.stringify(turn !== void 0 ? { turn, content: null } : listAssets ? { assets: [] } : { hits: [] });
|
|
27238
|
+
}
|
|
26864
27239
|
if (turn !== void 0) {
|
|
26865
27240
|
const message3 = turn >= 0 ? await ctx.session.readTurn(turn) : void 0;
|
|
26866
27241
|
if (!message3) return `no turn ${turn} in this session's log.`;
|
|
26867
27242
|
return JSON.stringify({ turn, role: message3.role, content: message3.content });
|
|
26868
27243
|
}
|
|
27244
|
+
if (listAssets) {
|
|
27245
|
+
if (!ctx.session.assets) {
|
|
27246
|
+
return JSON.stringify({
|
|
27247
|
+
assets: [],
|
|
27248
|
+
note: "this deployment has no artifact store: the thread's files are not catalogued"
|
|
27249
|
+
});
|
|
27250
|
+
}
|
|
27251
|
+
const assets = await ctx.session.assets();
|
|
27252
|
+
return JSON.stringify({
|
|
27253
|
+
assets: assets.map((a) => assetView(a, ctx.session.workspacePathOf?.(a.key))),
|
|
27254
|
+
...assets.length === 0 ? { note: "no run of this thread has received or produced a file" } : {}
|
|
27255
|
+
});
|
|
27256
|
+
}
|
|
26869
27257
|
const limit = Math.min(
|
|
26870
27258
|
MAX_HITS,
|
|
26871
27259
|
Math.max(1, typeof input.limit === "number" ? Math.trunc(input.limit) : DEFAULT_HITS)
|
|
@@ -26875,12 +27263,17 @@ var init_session = __esm({
|
|
|
26875
27263
|
if (hits.length === 0)
|
|
26876
27264
|
notes.push("no turn of this session's log matches; your notes (notes {}) may hold what you look for");
|
|
26877
27265
|
if (ctx.session.session.seedFrom === 0) notes.push("this is the first run of its session: the log begins with it");
|
|
27266
|
+
const catalogue = ctx.session.assets && hits.some((h) => FILE_BEARING.test(h.text)) ? await ctx.session.assets() : [];
|
|
26878
27267
|
return JSON.stringify({
|
|
26879
|
-
hits: hits.map((h) =>
|
|
26880
|
-
|
|
26881
|
-
|
|
26882
|
-
|
|
26883
|
-
|
|
27268
|
+
hits: hits.map((h) => {
|
|
27269
|
+
const files = filesNamedIn(h.text, catalogue);
|
|
27270
|
+
return {
|
|
27271
|
+
turn: h.idx,
|
|
27272
|
+
...h.role !== void 0 ? { role: h.role } : {},
|
|
27273
|
+
snippet: snippetOf(h.text),
|
|
27274
|
+
...files.length > 0 ? { files: files.map((a) => assetView(a, ctx.session.workspacePathOf?.(a.key))) } : {}
|
|
27275
|
+
};
|
|
27276
|
+
}),
|
|
26884
27277
|
...gaps.length ? {
|
|
26885
27278
|
gaps: `the log has a gap at ${gaps.map((g) => `turn ${g}`).join(", ")}: a run before it detached from the ledger, so turns it saw after that point are not here`
|
|
26886
27279
|
} : {},
|
|
@@ -27545,7 +27938,11 @@ function imperativeRule(writers) {
|
|
|
27545
27938
|
}
|
|
27546
27939
|
function attachRule(attachers) {
|
|
27547
27940
|
const names = attachers.map((a) => `\`${a}\``).join(" or ");
|
|
27548
|
-
return
|
|
27941
|
+
return [
|
|
27942
|
+
`Only ${names} can attach or post a file into the thread (the \`attach_file\` tool).`,
|
|
27943
|
+
`A request that names attach_file routes to ${names}, whatever it asks the tool to do \u2014 a probe, a test or a diagnostic of the tool is still a call to it.`,
|
|
27944
|
+
"A request that asks for a file, a screenshot, a recording or an attachment to be posted, attached or sent back routes there too, however read-only the rest of it sounds; a read-only preset can describe a file but never post one."
|
|
27945
|
+
].join(" ");
|
|
27549
27946
|
}
|
|
27550
27947
|
function tidyReason(reason) {
|
|
27551
27948
|
const line3 = oneLine(redactAndCap(reason, ROUTE_REASON_CAP));
|
|
@@ -28613,7 +29010,8 @@ async function attachRoundWorkspace(input) {
|
|
|
28613
29010
|
profile,
|
|
28614
29011
|
repo: input.round.repo,
|
|
28615
29012
|
ref: input.round.ref,
|
|
28616
|
-
headSha: input.round.headSha
|
|
29013
|
+
headSha: input.round.headSha,
|
|
29014
|
+
...input.round.reattach !== void 0 ? { reattach: input.round.reattach } : {}
|
|
28617
29015
|
},
|
|
28618
29016
|
input.span
|
|
28619
29017
|
);
|
|
@@ -29240,157 +29638,6 @@ var init_messages = __esm({
|
|
|
29240
29638
|
}
|
|
29241
29639
|
});
|
|
29242
29640
|
|
|
29243
|
-
// ../../src/core/dispatch/staging.ts
|
|
29244
|
-
function stagedBasename(index, name) {
|
|
29245
|
-
return `${index}-${safeBasename(name)}`;
|
|
29246
|
-
}
|
|
29247
|
-
function pullCommandFor(url, basename4) {
|
|
29248
|
-
return `mkdir -p ${ATTACHMENTS_DIR} && curl -fsS -o ${shellQuote(`${ATTACHMENTS_DIR}/${basename4}`)} ${shellQuote(url)}`;
|
|
29249
|
-
}
|
|
29250
|
-
function excludeCommand() {
|
|
29251
|
-
const entry = shellQuote(`${ATTACHMENTS_DIR}/`);
|
|
29252
|
-
return `mkdir -p .git/info && { grep -qxF ${entry} .git/info/exclude 2>/dev/null || echo ${entry} >> .git/info/exclude; }`;
|
|
29253
|
-
}
|
|
29254
|
-
function formatSize(bytes) {
|
|
29255
|
-
if (bytes >= 1e9) return `${(bytes / 1e9).toFixed(1)} GB`;
|
|
29256
|
-
if (bytes >= 1e6) return `${Math.round(bytes / 1e6)} MB`;
|
|
29257
|
-
if (bytes >= 1e3) return `${Math.round(bytes / 1e3)} KB`;
|
|
29258
|
-
return `${bytes} B`;
|
|
29259
|
-
}
|
|
29260
|
-
function attachmentsLine(outcomes) {
|
|
29261
|
-
const landed = outcomes.filter((o) => o.error === void 0);
|
|
29262
|
-
const failed = outcomes.filter((o) => o.error !== void 0);
|
|
29263
|
-
const parts = [];
|
|
29264
|
-
if (landed.length > 0) {
|
|
29265
|
-
parts.push(
|
|
29266
|
-
`Attached files are in ./${ATTACHMENTS_DIR}/: ${landed.map(
|
|
29267
|
-
(o) => `${o.basename} (${formatSize(o.file.size)}, ${o.file.type}${o.earlier ? ", from earlier in the thread" : ""})`
|
|
29268
|
-
).join(", ")}`
|
|
29269
|
-
);
|
|
29270
|
-
}
|
|
29271
|
-
for (const o of failed) parts.push(`${o.file.name} could not be staged: ${o.error}`);
|
|
29272
|
-
return parts.join(". ");
|
|
29273
|
-
}
|
|
29274
|
-
function noWorkspaceLine(files) {
|
|
29275
|
-
return files.map(
|
|
29276
|
-
(f) => `this agent has no workspace for ${f.name} (${formatSize(f.size)}, ${f.type}); ask \`agent:coding\` to work with it`
|
|
29277
|
-
).join(". ");
|
|
29278
|
-
}
|
|
29279
|
-
function stagingIndex() {
|
|
29280
|
-
let n2 = 0;
|
|
29281
|
-
return () => ++n2;
|
|
29282
|
-
}
|
|
29283
|
-
async function copyStaged(files, deps) {
|
|
29284
|
-
return Promise.all(
|
|
29285
|
-
files.map(async (file) => {
|
|
29286
|
-
const index = deps.nextIndex();
|
|
29287
|
-
const basename4 = stagedBasename(index, file.name);
|
|
29288
|
-
const key = inboundKey(deps.threadKey, file.messageId, index, file.name);
|
|
29289
|
-
try {
|
|
29290
|
-
await deps.store.copyFromUrl({ url: file.url, size: file.size, key });
|
|
29291
|
-
deps.publish?.({
|
|
29292
|
-
type: "artifact",
|
|
29293
|
-
direction: "in",
|
|
29294
|
-
key,
|
|
29295
|
-
name: file.name,
|
|
29296
|
-
size: file.size,
|
|
29297
|
-
contentType: file.type
|
|
29298
|
-
});
|
|
29299
|
-
return { file, basename: basename4, key };
|
|
29300
|
-
} catch (err2) {
|
|
29301
|
-
return { file, basename: basename4, key, error: `the copy into the store failed: ${describe4(err2)}` };
|
|
29302
|
-
}
|
|
29303
|
-
})
|
|
29304
|
-
);
|
|
29305
|
-
}
|
|
29306
|
-
async function pullStaged(outcomes, deps) {
|
|
29307
|
-
const landed = outcomes.filter((o) => o.error === void 0);
|
|
29308
|
-
if (landed.length === 0) return [...outcomes];
|
|
29309
|
-
const timeoutMs = deps.timeoutMs ?? BASH_TIMEOUT_MAX_MS;
|
|
29310
|
-
const opts = { timeoutMs, ...deps.signal ? { signal: deps.signal } : {} };
|
|
29311
|
-
if (deps.resident) await deps.executor.exec(excludeCommand(), opts);
|
|
29312
|
-
const pulled = /* @__PURE__ */ new Map();
|
|
29313
|
-
for (const o of landed) {
|
|
29314
|
-
const url = await deps.store.presignGet(o.key);
|
|
29315
|
-
const out = await deps.executor.exec(pullCommandFor(url, o.basename), opts);
|
|
29316
|
-
pulled.set(o.key, parseExitPrefix(out).failed ? `the pull into the workspace failed: ${out.trim()}` : void 0);
|
|
29317
|
-
}
|
|
29318
|
-
return outcomes.map((o) => {
|
|
29319
|
-
const error = o.error ?? pulled.get(o.key);
|
|
29320
|
-
if (error !== void 0) return { ...o, error };
|
|
29321
|
-
const { error: _dropped, ...landedOutcome } = o;
|
|
29322
|
-
return landedOutcome;
|
|
29323
|
-
});
|
|
29324
|
-
}
|
|
29325
|
-
function threadInboundArtifacts(runsOldestFirst) {
|
|
29326
|
-
const seen = /* @__PURE__ */ new Set();
|
|
29327
|
-
const out = [];
|
|
29328
|
-
for (const events of runsOldestFirst) {
|
|
29329
|
-
for (const e of events) {
|
|
29330
|
-
if (e.type !== "artifact" || e.direction !== "in" || seen.has(e.key)) continue;
|
|
29331
|
-
seen.add(e.key);
|
|
29332
|
-
out.push({ key: e.key, name: e.name, size: e.size, contentType: e.contentType });
|
|
29333
|
-
}
|
|
29334
|
-
}
|
|
29335
|
-
return out;
|
|
29336
|
-
}
|
|
29337
|
-
async function stageThreadArtifacts(artifacts, deps) {
|
|
29338
|
-
const outcomes = [];
|
|
29339
|
-
for (const a of artifacts) {
|
|
29340
|
-
const file = { name: a.name, size: a.size, type: a.contentType };
|
|
29341
|
-
let held;
|
|
29342
|
-
try {
|
|
29343
|
-
held = await deps.store.head(a.key) !== null;
|
|
29344
|
-
} catch (err2) {
|
|
29345
|
-
outcomes.push({
|
|
29346
|
-
file,
|
|
29347
|
-
basename: safeBasename(a.name),
|
|
29348
|
-
key: a.key,
|
|
29349
|
-
earlier: true,
|
|
29350
|
-
error: `the store could not be asked: ${describe4(err2)}`
|
|
29351
|
-
});
|
|
29352
|
-
continue;
|
|
29353
|
-
}
|
|
29354
|
-
if (!held) {
|
|
29355
|
-
outcomes.push({
|
|
29356
|
-
file,
|
|
29357
|
-
basename: safeBasename(a.name),
|
|
29358
|
-
key: a.key,
|
|
29359
|
-
earlier: true,
|
|
29360
|
-
error: "the store no longer holds it (its retention passed)"
|
|
29361
|
-
});
|
|
29362
|
-
continue;
|
|
29363
|
-
}
|
|
29364
|
-
const basename4 = stagedBasename(deps.nextIndex(), a.name);
|
|
29365
|
-
deps.publish?.({
|
|
29366
|
-
type: "artifact",
|
|
29367
|
-
direction: "in",
|
|
29368
|
-
key: a.key,
|
|
29369
|
-
name: a.name,
|
|
29370
|
-
size: a.size,
|
|
29371
|
-
contentType: a.contentType
|
|
29372
|
-
});
|
|
29373
|
-
outcomes.push({ file, basename: basename4, key: a.key, earlier: true });
|
|
29374
|
-
}
|
|
29375
|
-
return outcomes;
|
|
29376
|
-
}
|
|
29377
|
-
async function stageIntoWorkspace(files, deps) {
|
|
29378
|
-
const outcomes = await pullStaged(await copyStaged(files, deps), deps);
|
|
29379
|
-
return { line: attachmentsLine(outcomes), outcomes };
|
|
29380
|
-
}
|
|
29381
|
-
var ATTACHMENTS_DIR, describe4;
|
|
29382
|
-
var init_staging = __esm({
|
|
29383
|
-
"../../src/core/dispatch/staging.ts"() {
|
|
29384
|
-
"use strict";
|
|
29385
|
-
init_keys();
|
|
29386
|
-
init_bashTimeout();
|
|
29387
|
-
init_shellQuote();
|
|
29388
|
-
init_runEvents();
|
|
29389
|
-
ATTACHMENTS_DIR = "attachments";
|
|
29390
|
-
describe4 = (err2) => err2 instanceof Error ? err2.message : String(err2);
|
|
29391
|
-
}
|
|
29392
|
-
});
|
|
29393
|
-
|
|
29394
29641
|
// ../../src/core/modelProxy/runBearers.ts
|
|
29395
29642
|
import { createHash as createHash4, randomBytes as randomBytes4, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
29396
29643
|
function token(runId3, secret2) {
|
|
@@ -30093,7 +30340,7 @@ async function reserveRun(deps, ctx) {
|
|
|
30093
30340
|
return void 0;
|
|
30094
30341
|
}
|
|
30095
30342
|
async function attachWorkspace(deps, ctx) {
|
|
30096
|
-
const { msg, io, refuse: refuse3, card, shell, closeLines, clock: clock3, agent, profile, repoCtx, root } = ctx;
|
|
30343
|
+
const { msg, io, refuse: refuse3, card, shell, closeLines, clock: clock3, agent, profile, repoCtx, root, reattach } = ctx;
|
|
30097
30344
|
let round2;
|
|
30098
30345
|
try {
|
|
30099
30346
|
round2 = await root.span("dispatch.workspace.attach", async (span) => {
|
|
@@ -30118,7 +30365,8 @@ async function attachWorkspace(deps, ctx) {
|
|
|
30118
30365
|
profile,
|
|
30119
30366
|
repo: repoCtx.repo,
|
|
30120
30367
|
ref: repoCtx.ref,
|
|
30121
|
-
headSha: repoCtx.headSha
|
|
30368
|
+
headSha: repoCtx.headSha,
|
|
30369
|
+
...reattach !== void 0 ? { reattach } : {}
|
|
30122
30370
|
},
|
|
30123
30371
|
logKey: msg.threadKey,
|
|
30124
30372
|
span
|
|
@@ -30145,6 +30393,7 @@ async function attachWorkspace(deps, ctx) {
|
|
|
30145
30393
|
});
|
|
30146
30394
|
return { kind: "refused", reason: "which_branch" };
|
|
30147
30395
|
}
|
|
30396
|
+
if (err2 instanceof WorkspaceReattachRefusedError) return { kind: "reattach_refused", why: err2.why };
|
|
30148
30397
|
throw err2;
|
|
30149
30398
|
}
|
|
30150
30399
|
return { kind: "attached", round: round2 };
|
|
@@ -30181,6 +30430,10 @@ function sessionNotesBlock(session) {
|
|
|
30181
30430
|
parts.push(
|
|
30182
30431
|
"SUMMARY OF THE EARLIER CONVERSATION (written when the context was compacted; every earlier turn is still reachable with `recall`):\n" + summary
|
|
30183
30432
|
);
|
|
30433
|
+
if (session.files && session.files.length > 0)
|
|
30434
|
+
parts.push(
|
|
30435
|
+
"FILES OF THIS THREAD (received on its messages or produced by its runs, as their records name them; `recall {assets: true}` lists them with their keys):\n" + session.files.map((line3) => `- ${line3}`).join("\n")
|
|
30436
|
+
);
|
|
30184
30437
|
return parts.length ? parts.join("\n\n") : void 0;
|
|
30185
30438
|
}
|
|
30186
30439
|
async function composePrompt(deps, ctx) {
|
|
@@ -30280,6 +30533,7 @@ var init_provision = __esm({
|
|
|
30280
30533
|
init_contract3();
|
|
30281
30534
|
init_registry();
|
|
30282
30535
|
init_profile();
|
|
30536
|
+
init_factory();
|
|
30283
30537
|
init_residentTrace();
|
|
30284
30538
|
init_resident();
|
|
30285
30539
|
init_memory();
|
|
@@ -30333,6 +30587,7 @@ async function claimRun(deps, ctx) {
|
|
|
30333
30587
|
} = ctx;
|
|
30334
30588
|
const { resident, binding } = selection;
|
|
30335
30589
|
let ledgerRun = ctx.ledgerRun;
|
|
30590
|
+
const workspaceBinding = workspaceBindingFor(selection, profile.machine);
|
|
30336
30591
|
if (!resume && reserved) {
|
|
30337
30592
|
const ledger = deps.runLedger;
|
|
30338
30593
|
const opened = await root.span(
|
|
@@ -30366,6 +30621,7 @@ async function claimRun(deps, ctx) {
|
|
|
30366
30621
|
...requestRow !== void 0 ? { request: requestRow } : {}
|
|
30367
30622
|
},
|
|
30368
30623
|
card: card.handle ?? null,
|
|
30624
|
+
...workspaceBinding !== void 0 ? { state: { binding: workspaceBinding } } : {},
|
|
30369
30625
|
// The row reserved before the attach (item 42), promoted in place;
|
|
30370
30626
|
// its hooks (a stop, a fence) were wired at the reservation and stay.
|
|
30371
30627
|
reservation: reserved,
|
|
@@ -30422,6 +30678,7 @@ var init_run2 = __esm({
|
|
|
30422
30678
|
init_workspace();
|
|
30423
30679
|
init_web();
|
|
30424
30680
|
init_githubApi();
|
|
30681
|
+
init_factory();
|
|
30425
30682
|
init_runRegistry();
|
|
30426
30683
|
init_secrets2();
|
|
30427
30684
|
webCapability = () => sharedWeb ??= makeWebCapability(processSecrets);
|
|
@@ -30454,6 +30711,17 @@ const URL_ENV = "SWITCHBOARD_HARNESS_URL";
|
|
|
30454
30711
|
/** How long the tool_call hook keeps asking an unreachable bot before it blocks. */
|
|
30455
30712
|
const AUTHORIZE_WAIT_MS = 90_000;
|
|
30456
30713
|
const AUTHORIZE_RETRY_MS = 2_000;
|
|
30714
|
+
/** How long one request for a relayed tool's result may take before it is asked
|
|
30715
|
+
* again: over the bot's window (30 s, after which it answers that the call is
|
|
30716
|
+
* still running), under this runtime's own five-minute header timeout on a
|
|
30717
|
+
* fetch, so a hung connection costs a minute of the wait, not five. */
|
|
30718
|
+
const TOOL_REQUEST_TIMEOUT_MS = 60_000;
|
|
30719
|
+
/** How long a relayed call keeps asking a bot it cannot reach before it fails; the cadence is the hook's. */
|
|
30720
|
+
const TOOL_WAIT_MS = 90_000;
|
|
30721
|
+
/** A bot that says a call is still running is asked again after the window it
|
|
30722
|
+
* held the request for; one that answered sooner is asked again no sooner
|
|
30723
|
+
* than this, so a misbehaving bot is never asked in a hot loop. */
|
|
30724
|
+
const TOOL_REASK_FLOOR_MS = 1_000;
|
|
30457
30725
|
|
|
30458
30726
|
function settings() {
|
|
30459
30727
|
const url = process.env[URL_ENV];
|
|
@@ -30527,6 +30795,49 @@ async function authorize(event) {
|
|
|
30527
30795
|
}
|
|
30528
30796
|
}
|
|
30529
30797
|
|
|
30798
|
+
/** pi's abort signal for the call, with this request's own timeout beside it
|
|
30799
|
+
* where the runtime can combine the two; pi's alone where it cannot. */
|
|
30800
|
+
function requestSignal(signal) {
|
|
30801
|
+
const timeout = typeof AbortSignal.timeout === "function" ? AbortSignal.timeout(TOOL_REQUEST_TIMEOUT_MS) : undefined;
|
|
30802
|
+
if (!timeout) return signal;
|
|
30803
|
+
if (!signal) return timeout;
|
|
30804
|
+
return typeof AbortSignal.any === "function" ? AbortSignal.any([signal, timeout]) : signal;
|
|
30805
|
+
}
|
|
30806
|
+
|
|
30807
|
+
/** A relayed tool's result. The call is posted with its id; a bot that answers
|
|
30808
|
+
* that the call is still running (a wait on other runs can take minutes) is
|
|
30809
|
+
* asked again with the same id until it answers: the bot runs the call once
|
|
30810
|
+
* and every later ask joins it. A bot that cannot be reached or is failing (a
|
|
30811
|
+
* network error, a timed-out request, a 5xx) is asked again every two seconds
|
|
30812
|
+
* until the wait is up, then the call fails naming why; a refusal at the door
|
|
30813
|
+
* (a 4xx) fails it at once; an abort from pi ends the asking. */
|
|
30814
|
+
async function relay(toolCallId, tool, input, signal) {
|
|
30815
|
+
let lastAnswered = Date.now();
|
|
30816
|
+
let lastError = "";
|
|
30817
|
+
for (;;) {
|
|
30818
|
+
if (signal && signal.aborted) throw new Error("switchboard harness: " + tool + " was aborted before the bot answered");
|
|
30819
|
+
const asked = Date.now();
|
|
30820
|
+
let answer;
|
|
30821
|
+
try {
|
|
30822
|
+
answer = await call("POST", "/harness/tool", { toolCallId, tool, input }, requestSignal(signal));
|
|
30823
|
+
} catch (err) {
|
|
30824
|
+
if (signal && signal.aborted) throw err;
|
|
30825
|
+
const status = err instanceof HarnessAnswerError ? err.status : undefined;
|
|
30826
|
+
if (status !== undefined && status >= 400 && status < 500) throw err;
|
|
30827
|
+
lastError = err instanceof Error ? err.message : String(err);
|
|
30828
|
+
if (Date.now() - lastAnswered >= TOOL_WAIT_MS) {
|
|
30829
|
+
throw new Error("switchboard harness: the bot did not answer " + tool + " for 90 s (" + lastError + ")");
|
|
30830
|
+
}
|
|
30831
|
+
await sleep(AUTHORIZE_RETRY_MS);
|
|
30832
|
+
continue;
|
|
30833
|
+
}
|
|
30834
|
+
lastAnswered = Date.now();
|
|
30835
|
+
if (!answer.pending) return answer;
|
|
30836
|
+
const held = Date.now() - asked;
|
|
30837
|
+
if (held < TOOL_REASK_FLOOR_MS) await sleep(TOOL_REASK_FLOOR_MS - held);
|
|
30838
|
+
}
|
|
30839
|
+
}
|
|
30840
|
+
|
|
30530
30841
|
function relayTool(def) {
|
|
30531
30842
|
return {
|
|
30532
30843
|
name: def.name,
|
|
@@ -30534,7 +30845,7 @@ function relayTool(def) {
|
|
|
30534
30845
|
description: def.description,
|
|
30535
30846
|
parameters: def.inputSchema,
|
|
30536
30847
|
async execute(toolCallId, params, signal) {
|
|
30537
|
-
const answer = await
|
|
30848
|
+
const answer = await relay(toolCallId, def.name, params, signal);
|
|
30538
30849
|
if (answer.isError) throw new Error(answer.content.map((c) => (c.type === "text" ? c.text : "")).join("\\n"));
|
|
30539
30850
|
return { content: answer.content, details: {} };
|
|
30540
30851
|
},
|
|
@@ -30733,6 +31044,9 @@ function readLogScript(path, offset, maxBytes) {
|
|
|
30733
31044
|
function aliveScript(pid) {
|
|
30734
31045
|
return `kill -0 ${pid} 2>/dev/null && echo alive || echo dead`;
|
|
30735
31046
|
}
|
|
31047
|
+
function identityScript() {
|
|
31048
|
+
return "cat /proc/sys/kernel/random/boot_id 2>/dev/null || true";
|
|
31049
|
+
}
|
|
30736
31050
|
function killScript(pid) {
|
|
30737
31051
|
return `kill -TERM -- -${pid} 2>/dev/null; kill -TERM ${pid} 2>/dev/null; sleep 1; kill -KILL -- -${pid} 2>/dev/null; kill -KILL ${pid} 2>/dev/null; true`;
|
|
30738
31052
|
}
|
|
@@ -30749,7 +31063,7 @@ function stdoutOf(operation, out) {
|
|
|
30749
31063
|
const stdout = cut >= 0 ? out.slice(0, cut) : out;
|
|
30750
31064
|
return stdout === "(no output)" ? "" : stdout;
|
|
30751
31065
|
}
|
|
30752
|
-
var PiContainerError, WRITE_CHUNK_CHARS, INLINE_LINE_CHARS, LOG_READ_BYTES, MESSAGE_UPDATE_MARK, LOG_FILTER, STDERR_MARK, OP_TIMEOUT_MS, ExecPiContainer;
|
|
31066
|
+
var PiContainerError, WRITE_CHUNK_CHARS, INLINE_LINE_CHARS, LOG_READ_BYTES, MESSAGE_UPDATE_MARK, LOG_FILTER, IDENTITY_WORD, STDERR_MARK, OP_TIMEOUT_MS, ExecPiContainer;
|
|
30753
31067
|
var init_container = __esm({
|
|
30754
31068
|
"../../src/core/harness/pi/container.ts"() {
|
|
30755
31069
|
"use strict";
|
|
@@ -30769,6 +31083,7 @@ var init_container = __esm({
|
|
|
30769
31083
|
LOG_READ_BYTES = 48 * 1024;
|
|
30770
31084
|
MESSAGE_UPDATE_MARK = '"type":"message_update"';
|
|
30771
31085
|
LOG_FILTER = `grep --line-buffered -v ${shellQuote(MESSAGE_UPDATE_MARK)}`;
|
|
31086
|
+
IDENTITY_WORD = /^[A-Za-z0-9-]{1,64}$/;
|
|
30772
31087
|
STDERR_MARK = "\n--- stderr ---\n";
|
|
30773
31088
|
OP_TIMEOUT_MS = 6e4;
|
|
30774
31089
|
ExecPiContainer = class {
|
|
@@ -30782,6 +31097,12 @@ var init_container = __esm({
|
|
|
30782
31097
|
async makeRoot(runId3) {
|
|
30783
31098
|
return piRunPaths(runId3);
|
|
30784
31099
|
}
|
|
31100
|
+
/** The start script never changes directory, so pi runs where the executor
|
|
31101
|
+
* runs every command: the thread's checkout, which the harness names (a
|
|
31102
|
+
* resident's `/exec` runs in the thread's worktree). No command runs here. */
|
|
31103
|
+
cwd(_paths, checkout) {
|
|
31104
|
+
return checkout;
|
|
31105
|
+
}
|
|
30785
31106
|
async writeFile(path, content) {
|
|
30786
31107
|
for (const script of writeFileScripts(path, content)) stdoutOf("write", await this.exec(script));
|
|
30787
31108
|
}
|
|
@@ -30807,6 +31128,16 @@ var init_container = __esm({
|
|
|
30807
31128
|
async alive(pid) {
|
|
30808
31129
|
return stdoutOf("alive", await this.exec(aliveScript(pid))).trim() === "alive";
|
|
30809
31130
|
}
|
|
31131
|
+
/** One word or nothing: an empty answer, a malformed one or a command the
|
|
31132
|
+
* executor could not run is no identity: a judgement never rests on a guess. */
|
|
31133
|
+
async identity() {
|
|
31134
|
+
try {
|
|
31135
|
+
const word = stdoutOf("identity", await this.exec(identityScript())).trim();
|
|
31136
|
+
return IDENTITY_WORD.test(word) ? word : void 0;
|
|
31137
|
+
} catch {
|
|
31138
|
+
return void 0;
|
|
31139
|
+
}
|
|
31140
|
+
}
|
|
30810
31141
|
async kill(pid) {
|
|
30811
31142
|
stdoutOf("kill", await this.exec(killScript(pid)));
|
|
30812
31143
|
}
|
|
@@ -30938,6 +31269,14 @@ var init_botHostContainer = __esm({
|
|
|
30938
31269
|
throw new PiContainerError("root", message2(err2));
|
|
30939
31270
|
}
|
|
30940
31271
|
}
|
|
31272
|
+
/** The run's own root: `start` spawns pi in it, so that is the directory a
|
|
31273
|
+
* session written for this root names, present on this host in this
|
|
31274
|
+
* generation. The checkout the harness names is a container path this host
|
|
31275
|
+
* does not have (a `none` run has no workspace), and the previous
|
|
31276
|
+
* generation's root is gone with its pi: neither is where pi runs. */
|
|
31277
|
+
cwd(paths, _checkout) {
|
|
31278
|
+
return paths.dir;
|
|
31279
|
+
}
|
|
30941
31280
|
/** Parents at 700, the file at 600, exact bytes, created and never
|
|
30942
31281
|
* replaced: under a root this container made nothing is there before the
|
|
30943
31282
|
* harness writes it, so a path already present is a named failure, never
|
|
@@ -31058,6 +31397,12 @@ var init_botHostContainer = __esm({
|
|
|
31058
31397
|
const child = this.byPid.get(pid);
|
|
31059
31398
|
return child !== void 0 && !child.exited;
|
|
31060
31399
|
}
|
|
31400
|
+
/** The bot host names no container: its pi is a child of one bot generation
|
|
31401
|
+
* and never outlives it, so a resume judges it by its pid alone (`alive`
|
|
31402
|
+
* answers no for a pid this container did not start). */
|
|
31403
|
+
async identity() {
|
|
31404
|
+
return void 0;
|
|
31405
|
+
}
|
|
31061
31406
|
/** The group first (pi leads it), then pi itself: TERM, the grace, KILL;
|
|
31062
31407
|
* a pid this container never started, or one already ended, is nothing to end. */
|
|
31063
31408
|
async kill(pid) {
|
|
@@ -31220,8 +31565,13 @@ var init_bridge2 = __esm({
|
|
|
31220
31565
|
break;
|
|
31221
31566
|
case "message_end":
|
|
31222
31567
|
if (isRecord3(event.message)) {
|
|
31223
|
-
|
|
31224
|
-
|
|
31568
|
+
if (event.message.role === "assistant") {
|
|
31569
|
+
const assistant = event.message;
|
|
31570
|
+
this.onAssistant(assistant, out);
|
|
31571
|
+
if (assistant.stopReason !== "error") out.message = event.message;
|
|
31572
|
+
} else {
|
|
31573
|
+
out.message = event.message;
|
|
31574
|
+
}
|
|
31225
31575
|
}
|
|
31226
31576
|
break;
|
|
31227
31577
|
case "tool_execution_start":
|
|
@@ -31383,6 +31733,11 @@ var init_bridge2 = __esm({
|
|
|
31383
31733
|
openSpan(callId) {
|
|
31384
31734
|
return this.openTools.get(callId)?.span;
|
|
31385
31735
|
}
|
|
31736
|
+
/** Whether the bridge has read the call's start off the log and not yet its
|
|
31737
|
+
* end: what a relayed request that arrived ahead of the poll waits for. */
|
|
31738
|
+
callOpen(callId) {
|
|
31739
|
+
return this.openTools.has(callId);
|
|
31740
|
+
}
|
|
31386
31741
|
/** End whatever tool spans a stopped pi left open, so no span outlives the run. */
|
|
31387
31742
|
closeOpenSpans(reason) {
|
|
31388
31743
|
for (const [callId, open2] of this.openTools) {
|
|
@@ -31562,6 +31917,7 @@ var init_mirror = __esm({
|
|
|
31562
31917
|
if (!this.deps.onStep) return;
|
|
31563
31918
|
const chat = chatMessageOf(message3);
|
|
31564
31919
|
if (!chat) return;
|
|
31920
|
+
if (chat.content.length === 0) return;
|
|
31565
31921
|
if (chat.role === "user") {
|
|
31566
31922
|
if (!this.seedEchoed && !chat.content.some((p) => p.type === "tool_result")) {
|
|
31567
31923
|
this.seedEchoed = true;
|
|
@@ -31704,7 +32060,8 @@ function piHarnessFactsOf(value) {
|
|
|
31704
32060
|
logOffset: v.logOffset,
|
|
31705
32061
|
...typeof v.sessionFile === "string" ? { sessionFile: v.sessionFile } : {},
|
|
31706
32062
|
...typeof v.bearerHash === "string" ? { bearerHash: v.bearerHash } : {},
|
|
31707
|
-
...typeof v.root === "string" ? { root: v.root } : {}
|
|
32063
|
+
...typeof v.root === "string" ? { root: v.root } : {},
|
|
32064
|
+
...typeof v.container === "string" ? { container: v.container } : {}
|
|
31708
32065
|
};
|
|
31709
32066
|
}
|
|
31710
32067
|
function relayedTools(tools) {
|
|
@@ -31773,6 +32130,24 @@ async function runPiHarness(deps, run2) {
|
|
|
31773
32130
|
const deadline = now() + remainingMs;
|
|
31774
32131
|
const warnAt = deadline - Math.min(3 * 6e4, run2.agent.maxMinutes * 15e3);
|
|
31775
32132
|
run2.toolContext.remainingMs = () => deadline - now();
|
|
32133
|
+
if (run2.conversation) {
|
|
32134
|
+
const readConversation = run2.conversation;
|
|
32135
|
+
run2.toolContext.conversation = async () => {
|
|
32136
|
+
try {
|
|
32137
|
+
return await readConversation();
|
|
32138
|
+
} catch (err2) {
|
|
32139
|
+
emit({
|
|
32140
|
+
type: "run_note",
|
|
32141
|
+
kind: "seed",
|
|
32142
|
+
summary: redactAndCap(
|
|
32143
|
+
`the conversation could not be read from the session log for a child's seed (${err2 instanceof Error ? err2.message : String(err2)}); a child spawned now starts from its own thread`,
|
|
32144
|
+
300
|
|
32145
|
+
)
|
|
32146
|
+
});
|
|
32147
|
+
return void 0;
|
|
32148
|
+
}
|
|
32149
|
+
};
|
|
32150
|
+
}
|
|
31776
32151
|
bridge.turns = run2.resume?.turn ?? 0;
|
|
31777
32152
|
const mirror = new PiMirror({
|
|
31778
32153
|
onStep: run2.onStep,
|
|
@@ -31802,7 +32177,11 @@ async function runPiHarness(deps, run2) {
|
|
|
31802
32177
|
emit,
|
|
31803
32178
|
toolSpan: (callId) => bridge.openSpan(callId),
|
|
31804
32179
|
gateSaw: (callId) => bridge.gateSaw(callId),
|
|
31805
|
-
toolsBlocked
|
|
32180
|
+
toolsBlocked,
|
|
32181
|
+
callSeen: async (callId) => {
|
|
32182
|
+
for (let waited = 0; !bridge.callOpen(callId) && waited < CALL_SEEN_WAIT_MS; waited += CALL_SEEN_TICK_MS)
|
|
32183
|
+
await deps.sleep(CALL_SEEN_TICK_MS);
|
|
32184
|
+
}
|
|
31806
32185
|
};
|
|
31807
32186
|
const forget = deps.registry.register(live);
|
|
31808
32187
|
let pid;
|
|
@@ -31819,21 +32198,27 @@ async function runPiHarness(deps, run2) {
|
|
|
31819
32198
|
const recorded = run2.resume?.facts;
|
|
31820
32199
|
let reattached = false;
|
|
31821
32200
|
let ended;
|
|
32201
|
+
let elsewhere;
|
|
32202
|
+
const here = await container.identity();
|
|
31822
32203
|
const honoured = (hash) => hash !== void 0 && (deps.bearers === void 0 || deps.bearers.adopt(run2.runId, hash));
|
|
31823
32204
|
if (recorded !== void 0) {
|
|
31824
|
-
|
|
31825
|
-
|
|
31826
|
-
|
|
31827
|
-
|
|
31828
|
-
|
|
31829
|
-
|
|
31830
|
-
|
|
31831
|
-
})
|
|
32205
|
+
if (recorded.container !== void 0 && here !== void 0 && recorded.container !== here) {
|
|
32206
|
+
elsewhere = `pi is elsewhere: the row's pi (pid ${recorded.pid}) ran in container ${recorded.container}, not the one this run was handed (${here}), so it was neither probed nor ended here`;
|
|
32207
|
+
} else {
|
|
32208
|
+
const alive = await container.alive(recorded.pid);
|
|
32209
|
+
if (alive && recorded.root !== void 0 && honoured(recorded.bearerHash)) {
|
|
32210
|
+
reattached = true;
|
|
32211
|
+
paths = piRunPathsAt(recorded.root);
|
|
32212
|
+
} else if (alive) {
|
|
32213
|
+
ended = recorded.root === void 0 ? "named no directory for its pi" : "carried no bearer this generation could honour for its pi";
|
|
32214
|
+
await container.kill(recorded.pid).catch(() => {
|
|
32215
|
+
});
|
|
32216
|
+
}
|
|
31832
32217
|
}
|
|
31833
32218
|
}
|
|
31834
32219
|
if (reattached && recorded && paths !== void 0) {
|
|
31835
32220
|
pid = recorded.pid;
|
|
31836
|
-
facts2 = { ...recorded };
|
|
32221
|
+
facts2 = { ...recorded, ...recorded.container === void 0 && here !== void 0 ? { container: here } : {} };
|
|
31837
32222
|
transport = new PiRpcTransport({
|
|
31838
32223
|
container,
|
|
31839
32224
|
paths,
|
|
@@ -31849,7 +32234,7 @@ async function runPiHarness(deps, run2) {
|
|
|
31849
32234
|
);
|
|
31850
32235
|
} else {
|
|
31851
32236
|
paths = await container.makeRoot(run2.runId);
|
|
31852
|
-
if (recorded?.root !== void 0 && recorded.root !== paths.dir)
|
|
32237
|
+
if (recorded?.root !== void 0 && recorded.root !== paths.dir && elsewhere === void 0)
|
|
31853
32238
|
await container.remove(piRunPathsAt(recorded.root)).catch(() => {
|
|
31854
32239
|
});
|
|
31855
32240
|
const spec = {
|
|
@@ -31882,7 +32267,7 @@ async function runPiHarness(deps, run2) {
|
|
|
31882
32267
|
piSessionFile(
|
|
31883
32268
|
session.messages,
|
|
31884
32269
|
{
|
|
31885
|
-
cwd: run2.rules.checkout,
|
|
32270
|
+
cwd: container.cwd(paths, run2.rules.checkout),
|
|
31886
32271
|
model: {
|
|
31887
32272
|
provider: run2.model.provider,
|
|
31888
32273
|
id: run2.model.id,
|
|
@@ -31896,7 +32281,7 @@ async function runPiHarness(deps, run2) {
|
|
|
31896
32281
|
}
|
|
31897
32282
|
if (run2.resume) {
|
|
31898
32283
|
const lost = run2.resume.settlements.length;
|
|
31899
|
-
const how = ended !== void 0 && recorded !== void 0 ? `the row ${ended} (pid ${recorded.pid}), so it was ended and pi restarted` : "pi restarted";
|
|
32284
|
+
const how = elsewhere !== void 0 ? `${elsewhere}, and pi restarted` : ended !== void 0 && recorded !== void 0 ? `the row ${ended} (pid ${recorded.pid}), so it was ended and pi restarted` : "pi restarted";
|
|
31900
32285
|
note(
|
|
31901
32286
|
"resumed",
|
|
31902
32287
|
`resumed after a restart: ${how} on the mirrored transcript \u2014 ${lost} call(s) were in flight, each answered with a restart note; ${Math.round(remainingMs / 6e4)} min of budget left`
|
|
@@ -31906,7 +32291,13 @@ async function runPiHarness(deps, run2) {
|
|
|
31906
32291
|
for (const file of piLaunchFiles(launch)) await container.writeFile(file.path, file.content);
|
|
31907
32292
|
({ pid } = await container.start({ paths, args: piLaunchArgs(launch), env: piLaunchEnv(launch, deps.bearer) }));
|
|
31908
32293
|
const bearerHash = bearerHashOf(deps.bearer);
|
|
31909
|
-
facts2 = {
|
|
32294
|
+
facts2 = {
|
|
32295
|
+
pid,
|
|
32296
|
+
logOffset: 0,
|
|
32297
|
+
root: paths.dir,
|
|
32298
|
+
...bearerHash !== void 0 ? { bearerHash } : {},
|
|
32299
|
+
...here !== void 0 ? { container: here } : {}
|
|
32300
|
+
};
|
|
31910
32301
|
save();
|
|
31911
32302
|
transport = new PiRpcTransport({ container, paths, pid, pollMs: deps.pollMs ?? 750, sleep: deps.sleep });
|
|
31912
32303
|
}
|
|
@@ -32101,7 +32492,7 @@ ${stagedLine}` : prompt,
|
|
|
32101
32492
|
agentSpan?.end(hardStopped || bypass ? "error" : "ok");
|
|
32102
32493
|
}
|
|
32103
32494
|
}
|
|
32104
|
-
var NATIVE_WORKSPACE_TOOLS, FINALE_TIMEOUT_MS2, CONTINUE_PROMPT, PromptRefused, GateBypassed;
|
|
32495
|
+
var NATIVE_WORKSPACE_TOOLS, FINALE_TIMEOUT_MS2, CALL_SEEN_WAIT_MS, CALL_SEEN_TICK_MS, CONTINUE_PROMPT, PromptRefused, GateBypassed;
|
|
32105
32496
|
var init_harness = __esm({
|
|
32106
32497
|
"../../src/core/harness/pi/harness.ts"() {
|
|
32107
32498
|
"use strict";
|
|
@@ -32116,6 +32507,8 @@ var init_harness = __esm({
|
|
|
32116
32507
|
init_transport();
|
|
32117
32508
|
NATIVE_WORKSPACE_TOOLS = /* @__PURE__ */ new Set(["bash", "read_file", "write_file"]);
|
|
32118
32509
|
FINALE_TIMEOUT_MS2 = 3 * 6e4;
|
|
32510
|
+
CALL_SEEN_WAIT_MS = 3e3;
|
|
32511
|
+
CALL_SEEN_TICK_MS = 50;
|
|
32119
32512
|
CONTINUE_PROMPT = "Continue where you left off: the bot restarted mid-run, so re-check the effects of your last command before relying on them.";
|
|
32120
32513
|
PromptRefused = class extends Error {
|
|
32121
32514
|
constructor(reason) {
|
|
@@ -32970,6 +33363,7 @@ async function runLoop2(deps, ctx) {
|
|
|
32970
33363
|
executor,
|
|
32971
33364
|
resident: round2.selection.resident !== void 0
|
|
32972
33365
|
});
|
|
33366
|
+
ctx.workspaceFiles?.record(staged.outcomes);
|
|
32973
33367
|
return staged.line;
|
|
32974
33368
|
} : void 0;
|
|
32975
33369
|
let artifactSeq = 0;
|
|
@@ -33018,10 +33412,19 @@ async function runLoop2(deps, ctx) {
|
|
|
33018
33412
|
});
|
|
33019
33413
|
if (harness === "pi" && piFacts) {
|
|
33020
33414
|
const container = deps.harness?.containerFor?.(executor, profile.machine) ?? piContainerFor(executor, profile.machine);
|
|
33021
|
-
await container.
|
|
33022
|
-
|
|
33023
|
-
|
|
33024
|
-
|
|
33415
|
+
const here = await container.identity();
|
|
33416
|
+
if (piFacts.container === void 0 || here === void 0 || piFacts.container === here) {
|
|
33417
|
+
await container.kill(piFacts.pid).catch(() => {
|
|
33418
|
+
});
|
|
33419
|
+
if (piFacts.root !== void 0) await container.remove(piRunPathsAt(piFacts.root)).catch(() => {
|
|
33420
|
+
});
|
|
33421
|
+
} else {
|
|
33422
|
+
onEvent({
|
|
33423
|
+
type: "run_note",
|
|
33424
|
+
kind: "resumed",
|
|
33425
|
+
summary: `the run's pi (pid ${piFacts.pid}) ran in container ${piFacts.container}, not the one this run was handed (${here}): it was not ended here`
|
|
33426
|
+
});
|
|
33427
|
+
}
|
|
33025
33428
|
}
|
|
33026
33429
|
answer = answerUnderEnding(finish2.answer, loopEnding, agent.maxMinutes);
|
|
33027
33430
|
} else if (harness === "pi") {
|
|
@@ -33066,7 +33469,7 @@ async function runLoop2(deps, ctx) {
|
|
|
33066
33469
|
messages,
|
|
33067
33470
|
tools: relayedTools(mergeTools(TOOLSETS[agent.toolset] ?? [], mcpForRun?.tools)),
|
|
33068
33471
|
toolContext,
|
|
33069
|
-
...session ? { notepad: () => session.readNotepad() } : {},
|
|
33472
|
+
...session ? { notepad: () => session.readNotepad(), conversation: () => session.readConversation() } : {},
|
|
33070
33473
|
rules: {
|
|
33071
33474
|
checkout: binding?.workspace ?? "/workspace",
|
|
33072
33475
|
...ownBranch !== void 0 ? { branch: ownBranch } : {},
|
|
@@ -33884,7 +34287,7 @@ async function plan(deps, input) {
|
|
|
33884
34287
|
try {
|
|
33885
34288
|
planId = planIdOf(request.planPath);
|
|
33886
34289
|
} catch (err2) {
|
|
33887
|
-
return { ok: false, reply: `\u{1F6AB} ${
|
|
34290
|
+
return { ok: false, reply: `\u{1F6AB} ${describe6(err2)}` };
|
|
33888
34291
|
}
|
|
33889
34292
|
let text;
|
|
33890
34293
|
try {
|
|
@@ -33892,7 +34295,7 @@ async function plan(deps, input) {
|
|
|
33892
34295
|
} catch (err2) {
|
|
33893
34296
|
return {
|
|
33894
34297
|
ok: false,
|
|
33895
|
-
reply: `\u{1F6AB} The plan \`${request.planPath}\` could not be read at \`${base}\` in ${entry.repo}: ${
|
|
34298
|
+
reply: `\u{1F6AB} The plan \`${request.planPath}\` could not be read at \`${base}\` in ${entry.repo}: ${describe6(err2)}`
|
|
33896
34299
|
};
|
|
33897
34300
|
}
|
|
33898
34301
|
const graph = parsePlanGraph(text, planId);
|
|
@@ -33905,7 +34308,7 @@ async function plan(deps, input) {
|
|
|
33905
34308
|
try {
|
|
33906
34309
|
selected = openPlanCursor(graph, request.units).order;
|
|
33907
34310
|
} catch (err2) {
|
|
33908
|
-
return { ok: false, reply: `\u{1F6AB} ${
|
|
34311
|
+
return { ok: false, reply: `\u{1F6AB} ${describe6(err2)}` };
|
|
33909
34312
|
}
|
|
33910
34313
|
return { ok: true, planned: { kind: "plan", planId, path: request.planPath, base, graph, selected, identity: identity2 } };
|
|
33911
34314
|
}
|
|
@@ -34021,7 +34424,7 @@ async function start(deps, input, instance, units, where, write) {
|
|
|
34021
34424
|
try {
|
|
34022
34425
|
answer = await deps.create(instance.id);
|
|
34023
34426
|
} catch (err2) {
|
|
34024
|
-
answer = { kind: "unanswered", reason:
|
|
34427
|
+
answer = { kind: "unanswered", reason: describe6(err2) };
|
|
34025
34428
|
}
|
|
34026
34429
|
switch (answer.kind) {
|
|
34027
34430
|
case "created": {
|
|
@@ -34043,7 +34446,7 @@ async function start(deps, input, instance, units, where, write) {
|
|
|
34043
34446
|
);
|
|
34044
34447
|
}
|
|
34045
34448
|
}
|
|
34046
|
-
var refused3,
|
|
34449
|
+
var refused3, describe6, RUNNING, ENDED;
|
|
34047
34450
|
var init_handOff = __esm({
|
|
34048
34451
|
"../../src/core/coordinator/handOff.ts"() {
|
|
34049
34452
|
"use strict";
|
|
@@ -34051,7 +34454,7 @@ var init_handOff = __esm({
|
|
|
34051
34454
|
init_coordinator();
|
|
34052
34455
|
init_briefs();
|
|
34053
34456
|
refused3 = (reply) => ({ status: "aborted", reply });
|
|
34054
|
-
|
|
34457
|
+
describe6 = (err2) => err2 instanceof Error ? err2.message : String(err2);
|
|
34055
34458
|
RUNNING = /* @__PURE__ */ new Set(["queued", "running", "paused", "waiting", "waitingForPause"]);
|
|
34056
34459
|
ENDED = /* @__PURE__ */ new Set(["complete", "errored", "terminated"]);
|
|
34057
34460
|
}
|
|
@@ -34744,6 +35147,77 @@ var init_settle = __esm({
|
|
|
34744
35147
|
}
|
|
34745
35148
|
});
|
|
34746
35149
|
|
|
35150
|
+
// ../../src/core/dispatch/reattach.ts
|
|
35151
|
+
function carriedWorkspaceBinding(row) {
|
|
35152
|
+
const recorded = workspaceBindingOf(row.state.binding);
|
|
35153
|
+
if (recorded) return recorded;
|
|
35154
|
+
if (row.meta.selection === "resident")
|
|
35155
|
+
return { backend: "resident", ...row.meta.workspace ? { workspace: row.meta.workspace } : {} };
|
|
35156
|
+
if (row.meta.selection === "sandbox" || row.meta.selection === "local") return { backend: row.meta.selection };
|
|
35157
|
+
return void 0;
|
|
35158
|
+
}
|
|
35159
|
+
function lostWorkspaceNote(why, restarts) {
|
|
35160
|
+
const lost = `resumed after a restart: the run's workspace could not be re-attached (${why})`;
|
|
35161
|
+
return restarts ? `${lost}; the run restarts from its request as a new run in this thread` : `${lost}, and the row's request cannot be read, so the run ends here; re-send it to run it again`;
|
|
35162
|
+
}
|
|
35163
|
+
async function abandonLostWorkspace(ctx) {
|
|
35164
|
+
const { refuse: refuse3, card, shell, closeLines, clock: clock3, run: run2, registry, resume, ledgerRun, why } = ctx;
|
|
35165
|
+
const restored = messageFromInbox(resume.row.meta.request ?? {}, resume.row.startedAt);
|
|
35166
|
+
const summary = lostWorkspaceNote(why, restored !== void 0);
|
|
35167
|
+
const note = { type: "run_note", kind: "resumed", summary, at: clock3() };
|
|
35168
|
+
await refuse3("workspace_lost", async () => {
|
|
35169
|
+
registry.publish(run2.id, note);
|
|
35170
|
+
await card.done(
|
|
35171
|
+
shell.close({
|
|
35172
|
+
kind: "not_started",
|
|
35173
|
+
icon: "\u{1F501}",
|
|
35174
|
+
reason: restored ? "workspace lost across the restart; restarting from the request" : "workspace lost across the restart; re-send to run again",
|
|
35175
|
+
...closeLines(clock3(), false)
|
|
35176
|
+
})
|
|
35177
|
+
);
|
|
35178
|
+
if (ledgerRun)
|
|
35179
|
+
await closeResumedRow(
|
|
35180
|
+
ledgerRun,
|
|
35181
|
+
{ ...resume, events: [...resume.events, { ...note, seq: resume.lastSeq + 1 }] },
|
|
35182
|
+
"the run's workspace could not be re-attached"
|
|
35183
|
+
);
|
|
35184
|
+
});
|
|
35185
|
+
console.log(
|
|
35186
|
+
`[resume] ${resume.row.threadKey} run ${resume.row.runId} ${restored ? "restarts from its request" : "ends"}: ${why}`
|
|
35187
|
+
);
|
|
35188
|
+
return restored?.msg;
|
|
35189
|
+
}
|
|
35190
|
+
function prepareRestartTurn(deps, ctx) {
|
|
35191
|
+
const { request, pending: pending2, clock: clock3 } = ctx;
|
|
35192
|
+
const merged = mergeFollowUps(pending2);
|
|
35193
|
+
const receivedAt = clock3();
|
|
35194
|
+
const msg = {
|
|
35195
|
+
...request,
|
|
35196
|
+
...merged ? {
|
|
35197
|
+
text: `${request.text}
|
|
35198
|
+
|
|
35199
|
+
${merged.text}`,
|
|
35200
|
+
...merged.images || request.images ? { images: [...request.images ?? [], ...merged.images ?? []] } : {},
|
|
35201
|
+
...merged.documents || request.documents ? { documents: [...request.documents ?? [], ...merged.documents ?? []] } : {},
|
|
35202
|
+
...merged.staged || request.staged ? { staged: [...request.staged ?? [], ...merged.staged ?? []] } : {}
|
|
35203
|
+
} : {},
|
|
35204
|
+
receivedAt,
|
|
35205
|
+
originAt: void 0
|
|
35206
|
+
};
|
|
35207
|
+
const trace = startRequestRoot(deps, { channel: channelOf(msg.channelId), receivedAt });
|
|
35208
|
+
return { msg, opts: { trace } };
|
|
35209
|
+
}
|
|
35210
|
+
var init_reattach = __esm({
|
|
35211
|
+
"../../src/core/dispatch/reattach.ts"() {
|
|
35212
|
+
"use strict";
|
|
35213
|
+
init_factory();
|
|
35214
|
+
init_inboxMessage();
|
|
35215
|
+
init_requestTrace();
|
|
35216
|
+
init_threadAdmission();
|
|
35217
|
+
init_admission();
|
|
35218
|
+
}
|
|
35219
|
+
});
|
|
35220
|
+
|
|
34747
35221
|
// ../../src/core/dispatch/lineage.ts
|
|
34748
35222
|
function lineageOf(newest) {
|
|
34749
35223
|
if (newest === void 0 || newest.parentRunId === void 0) return void 0;
|
|
@@ -34803,31 +35277,6 @@ var init_lineage = __esm({
|
|
|
34803
35277
|
});
|
|
34804
35278
|
|
|
34805
35279
|
// ../../src/core/dispatch/thread.ts
|
|
34806
|
-
async function readThreadArtifacts(service, thread, warn = (line3) => console.warn(line3)) {
|
|
34807
|
-
const perRun = [];
|
|
34808
|
-
for (const run2 of [...thread].reverse()) {
|
|
34809
|
-
const events = [];
|
|
34810
|
-
let afterSeq;
|
|
34811
|
-
try {
|
|
34812
|
-
for (; ; ) {
|
|
34813
|
-
const r = await service.getRunEvents(run2.id, afterSeq === void 0 ? {} : { afterSeq });
|
|
34814
|
-
if (!r.ok) {
|
|
34815
|
-
warn(`[thread] ${run2.id}: reading its received files stopped after ${events.length} event(s) \u2014 ${r.error}`);
|
|
34816
|
-
break;
|
|
34817
|
-
}
|
|
34818
|
-
events.push(...r.value.events);
|
|
34819
|
-
if (r.value.nextAfterSeq === void 0) break;
|
|
34820
|
-
afterSeq = r.value.nextAfterSeq;
|
|
34821
|
-
}
|
|
34822
|
-
} catch (err2) {
|
|
34823
|
-
warn(
|
|
34824
|
-
`[thread] ${run2.id}: reading its received files failed after ${events.length} event(s) \u2014 ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
34825
|
-
);
|
|
34826
|
-
}
|
|
34827
|
-
perRun.push(events);
|
|
34828
|
-
}
|
|
34829
|
-
return threadInboundArtifacts(perRun);
|
|
34830
|
-
}
|
|
34831
35280
|
async function readThread(service, threadKey) {
|
|
34832
35281
|
try {
|
|
34833
35282
|
const page2 = await service.listRuns({
|
|
@@ -34869,7 +35318,6 @@ var THREAD_READ_LIMIT;
|
|
|
34869
35318
|
var init_thread = __esm({
|
|
34870
35319
|
"../../src/core/dispatch/thread.ts"() {
|
|
34871
35320
|
"use strict";
|
|
34872
|
-
init_staging();
|
|
34873
35321
|
THREAD_READ_LIMIT = 8;
|
|
34874
35322
|
}
|
|
34875
35323
|
});
|
|
@@ -34989,22 +35437,22 @@ function createRunEnding(deps) {
|
|
|
34989
35437
|
try {
|
|
34990
35438
|
deps.registry.seal(id, replyOk === void 0 ? {} : { replyOk });
|
|
34991
35439
|
} catch (err2) {
|
|
34992
|
-
log(`[ending] seal ${id}: ${
|
|
35440
|
+
log(`[ending] seal ${id}: ${describe7(err2)}`);
|
|
34993
35441
|
}
|
|
34994
35442
|
try {
|
|
34995
35443
|
afterSeal?.();
|
|
34996
35444
|
} catch (err2) {
|
|
34997
|
-
log(`[ending] after seal ${id}: ${
|
|
35445
|
+
log(`[ending] after seal ${id}: ${describe7(err2)}`);
|
|
34998
35446
|
}
|
|
34999
35447
|
}
|
|
35000
35448
|
for (const entry of pending2.splice(0)) {
|
|
35001
35449
|
try {
|
|
35002
35450
|
const result = deps.registry.seal(entry.runId);
|
|
35003
35451
|
void Promise.resolve(entry.write(result, entry.failedAfterFinish)).catch(
|
|
35004
|
-
(err2) => log(`[ending] record ${entry.runId}: ${
|
|
35452
|
+
(err2) => log(`[ending] record ${entry.runId}: ${describe7(err2)}`)
|
|
35005
35453
|
);
|
|
35006
35454
|
} catch (err2) {
|
|
35007
|
-
log(`[ending] record ${entry.runId}: ${
|
|
35455
|
+
log(`[ending] record ${entry.runId}: ${describe7(err2)}`);
|
|
35008
35456
|
}
|
|
35009
35457
|
}
|
|
35010
35458
|
};
|
|
@@ -35014,7 +35462,7 @@ function createRunEnding(deps) {
|
|
|
35014
35462
|
try {
|
|
35015
35463
|
deps.onFinished?.(runId3);
|
|
35016
35464
|
} catch (err2) {
|
|
35017
|
-
log(`[ending] finished ${runId3}: ${
|
|
35465
|
+
log(`[ending] finished ${runId3}: ${describe7(err2)}`);
|
|
35018
35466
|
}
|
|
35019
35467
|
},
|
|
35020
35468
|
register(entry) {
|
|
@@ -35042,7 +35490,7 @@ function createRunEnding(deps) {
|
|
|
35042
35490
|
}
|
|
35043
35491
|
};
|
|
35044
35492
|
}
|
|
35045
|
-
function
|
|
35493
|
+
function describe7(err2) {
|
|
35046
35494
|
return err2 instanceof Error ? err2.message : String(err2);
|
|
35047
35495
|
}
|
|
35048
35496
|
var init_runEnding = __esm({
|
|
@@ -35104,6 +35552,8 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
35104
35552
|
let reserved;
|
|
35105
35553
|
let requestRow;
|
|
35106
35554
|
let fencedWhileAttaching = false;
|
|
35555
|
+
let resumeRowClosed = false;
|
|
35556
|
+
let restartRequest;
|
|
35107
35557
|
const reservationHooks = {
|
|
35108
35558
|
onStop: (mode) => void registered?.control.requestStop(mode),
|
|
35109
35559
|
onFenced: () => {
|
|
@@ -35344,18 +35794,21 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
35344
35794
|
await tellLineage({ kind: "started", runId: runId3 });
|
|
35345
35795
|
const staged = !resume && deps.artifacts && msg.staged && msg.staged.length > 0 ? msg.staged : [];
|
|
35346
35796
|
const nextStagedIndex = stagingIndex();
|
|
35797
|
+
const workspaceFiles = new WorkspaceFiles();
|
|
35347
35798
|
const stagedCopies = staged.length > 0 && agent.machine !== "none" ? copyStaged(staged, {
|
|
35348
35799
|
store: deps.artifacts,
|
|
35349
35800
|
threadKey: msg.threadKey,
|
|
35350
35801
|
nextIndex: nextStagedIndex,
|
|
35351
35802
|
publish: (e) => registry.publish(runId3, e)
|
|
35352
35803
|
}) : void 0;
|
|
35353
|
-
const
|
|
35354
|
-
(
|
|
35355
|
-
|
|
35356
|
-
|
|
35357
|
-
|
|
35358
|
-
|
|
35804
|
+
const threadAssets = !resume && deps.artifacts && thread && thread.length > 0 ? readThreadAssets({ runs: runsService, store: deps.artifacts }, msg.threadKey).then(
|
|
35805
|
+
(assets) => assets.filter((a) => a.runId !== runId3)
|
|
35806
|
+
) : void 0;
|
|
35807
|
+
const earlierStaged = threadAssets && agent.machine !== "none" ? threadAssets.then(
|
|
35808
|
+
(assets) => stageThreadArtifacts(
|
|
35809
|
+
assets.filter((a) => a.direction === "in"),
|
|
35810
|
+
{ nextIndex: nextStagedIndex, publish: (e) => registry.publish(runId3, e) }
|
|
35811
|
+
)
|
|
35359
35812
|
) : void 0;
|
|
35360
35813
|
const reservation = await reserveRun(deps, {
|
|
35361
35814
|
msg,
|
|
@@ -35382,6 +35835,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
35382
35835
|
reserved = reservation.reserved;
|
|
35383
35836
|
requestRow = reservation.requestRow;
|
|
35384
35837
|
}
|
|
35838
|
+
const reattach = resume ? carriedWorkspaceBinding(resume.row) : void 0;
|
|
35385
35839
|
const attach = await attachWorkspace(deps, {
|
|
35386
35840
|
msg,
|
|
35387
35841
|
io,
|
|
@@ -35393,10 +35847,35 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
35393
35847
|
agent,
|
|
35394
35848
|
profile,
|
|
35395
35849
|
repoCtx,
|
|
35396
|
-
root
|
|
35850
|
+
root,
|
|
35851
|
+
...reattach !== void 0 ? { reattach } : {}
|
|
35397
35852
|
});
|
|
35398
35853
|
if (attach.kind === "refused") return ended;
|
|
35854
|
+
if (attach.kind === "reattach_refused") {
|
|
35855
|
+
if (resume) {
|
|
35856
|
+
restartRequest = await abandonLostWorkspace({
|
|
35857
|
+
msg,
|
|
35858
|
+
io,
|
|
35859
|
+
refuse: refuse3,
|
|
35860
|
+
card,
|
|
35861
|
+
shell,
|
|
35862
|
+
closeLines,
|
|
35863
|
+
clock: clock3,
|
|
35864
|
+
run: run2,
|
|
35865
|
+
registry,
|
|
35866
|
+
resume,
|
|
35867
|
+
ledgerRun,
|
|
35868
|
+
why: attach.why
|
|
35869
|
+
});
|
|
35870
|
+
resumeRowClosed = true;
|
|
35871
|
+
}
|
|
35872
|
+
return ended;
|
|
35873
|
+
}
|
|
35399
35874
|
const { round: round2 } = attach;
|
|
35875
|
+
if (resume && ledgerRun) {
|
|
35876
|
+
const rebound = workspaceBindingFor(round2.selection, profile.machine);
|
|
35877
|
+
if (rebound !== void 0) ledgerRun.setState({ binding: rebound });
|
|
35878
|
+
}
|
|
35400
35879
|
const { executor, note, resident } = round2.selection;
|
|
35401
35880
|
if (fencedWhileAttaching) {
|
|
35402
35881
|
console.log(
|
|
@@ -35408,13 +35887,16 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
35408
35887
|
}
|
|
35409
35888
|
const earlier2 = earlierStaged ? await earlierStaged : [];
|
|
35410
35889
|
if (staged.length > 0 || earlier2.length > 0) {
|
|
35411
|
-
|
|
35412
|
-
|
|
35890
|
+
let line3;
|
|
35891
|
+
if (stagedCopies || earlier2.length > 0) {
|
|
35892
|
+
const pulled = await pullStaged([...stagedCopies ? await stagedCopies : [], ...earlier2], {
|
|
35413
35893
|
store: deps.artifacts,
|
|
35414
35894
|
executor,
|
|
35415
35895
|
resident: resident !== void 0
|
|
35416
|
-
})
|
|
35417
|
-
|
|
35896
|
+
});
|
|
35897
|
+
workspaceFiles.record(pulled);
|
|
35898
|
+
line3 = attachmentsLine(pulled);
|
|
35899
|
+
} else line3 = noWorkspaceLine(staged);
|
|
35418
35900
|
const request = messages[messages.length - 1];
|
|
35419
35901
|
if (request && request.role === "user" && line3) {
|
|
35420
35902
|
request.content = Array.isArray(request.content) ? [...request.content, { type: "text", text: line3 }] : [
|
|
@@ -35444,6 +35926,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
35444
35926
|
if (headGate.headAdopted) publishMeta(repoCtx);
|
|
35445
35927
|
const isPrReview = agent.name === "review" && repoCtx.repo !== void 0 && repoCtx.pr !== void 0;
|
|
35446
35928
|
const isCodingPrRun = agent.toolset === "full";
|
|
35929
|
+
const threadFiles = threadAssets ? (await threadAssets).map((a) => describeAsset(a, workspaceFiles.pathOf(a.key))) : [];
|
|
35447
35930
|
const prompt = await composePrompt(deps, {
|
|
35448
35931
|
msg,
|
|
35449
35932
|
agent,
|
|
@@ -35460,11 +35943,13 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
35460
35943
|
root,
|
|
35461
35944
|
...contractBlock !== void 0 && agent.name === "review" ? { contract: contractBlock } : {},
|
|
35462
35945
|
// What the session already knows (session-log item 10): the notepad and
|
|
35463
|
-
// the newest compaction's summary the seed brought back,
|
|
35464
|
-
|
|
35946
|
+
// the newest compaction's summary the seed brought back, and the thread's
|
|
35947
|
+
// files (record 0033) with where each is for this run, for the prompt.
|
|
35948
|
+
...session?.notepad !== void 0 || session?.summary !== void 0 || threadFiles.length > 0 ? {
|
|
35465
35949
|
session: {
|
|
35466
|
-
...session
|
|
35467
|
-
...session
|
|
35950
|
+
...session?.notepad !== void 0 ? { notepad: session.notepad } : {},
|
|
35951
|
+
...session?.summary !== void 0 ? { summary: session.summary } : {},
|
|
35952
|
+
...threadFiles.length > 0 ? { files: threadFiles } : {}
|
|
35468
35953
|
}
|
|
35469
35954
|
} : {}
|
|
35470
35955
|
});
|
|
@@ -35524,7 +36009,14 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
35524
36009
|
seed,
|
|
35525
36010
|
...session ? { seedLog: session.log } : {}
|
|
35526
36011
|
});
|
|
35527
|
-
const sessionTools = sessionCapabilityFor(
|
|
36012
|
+
const sessionTools = sessionCapabilityFor(
|
|
36013
|
+
ledgerRun,
|
|
36014
|
+
deps.runLedger,
|
|
36015
|
+
deps.artifacts ? {
|
|
36016
|
+
read: () => readThreadAssets({ runs: runsService, store: deps.artifacts }, msg.threadKey),
|
|
36017
|
+
pathOf: (key) => workspaceFiles.pathOf(key)
|
|
36018
|
+
} : void 0
|
|
36019
|
+
);
|
|
35528
36020
|
const { spawn: spawn7, runs, steer, wait } = runToolCapabilities(
|
|
35529
36021
|
{ core: deps, dispatch, registry, clock: clock3 },
|
|
35530
36022
|
{
|
|
@@ -35544,6 +36036,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
35544
36036
|
profile,
|
|
35545
36037
|
resolved,
|
|
35546
36038
|
stagingIndex: nextStagedIndex,
|
|
36039
|
+
workspaceFiles,
|
|
35547
36040
|
provider,
|
|
35548
36041
|
model,
|
|
35549
36042
|
messages,
|
|
@@ -35646,7 +36139,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
35646
36139
|
clearInterval(setupHeartbeat);
|
|
35647
36140
|
ending.drain(void 0);
|
|
35648
36141
|
if (registered) deps.runBearers?.revoke(registered.id);
|
|
35649
|
-
if (resume && ledgerRun && !runLoopStarted) {
|
|
36142
|
+
if (resume && ledgerRun && !runLoopStarted && !resumeRowClosed) {
|
|
35650
36143
|
const adopted = ledgerRun;
|
|
35651
36144
|
await root.span(
|
|
35652
36145
|
"post.history_write",
|
|
@@ -35661,7 +36154,15 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
35661
36154
|
const stopMode = settled.kind === "handed-on" ? void 0 : settled.stopMode;
|
|
35662
36155
|
ended.status = caught ? "failed" : refused5 ? "refused" : stopMode ? "stopped" : "completed";
|
|
35663
36156
|
root.end(caught ? "error" : "ok", { status: ended.status });
|
|
35664
|
-
if (
|
|
36157
|
+
if (restartRequest) {
|
|
36158
|
+
const pending2 = settled.kind === "handed-on" ? settled.pending : [];
|
|
36159
|
+
const restart2 = prepareRestartTurn(deps, { request: restartRequest, pending: pending2, clock: clock3 });
|
|
36160
|
+
await dispatch(deps, restart2.msg, io, restart2.opts).catch(
|
|
36161
|
+
(err2) => console.error(
|
|
36162
|
+
`[dispatch] ${msg.threadKey} restart after a lost workspace failed: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
36163
|
+
)
|
|
36164
|
+
);
|
|
36165
|
+
} else if (settled.kind === "handed-on") {
|
|
35665
36166
|
const fresh = prepareFreshTurn(deps, { agent: settled.agent, pending: settled.pending, clock: clock3 });
|
|
35666
36167
|
await dispatch(deps, fresh.msg, fresh.io, fresh.opts).catch(
|
|
35667
36168
|
(err2) => console.error(
|
|
@@ -35704,10 +36205,13 @@ var init_dispatcher = __esm({
|
|
|
35704
36205
|
init_contract();
|
|
35705
36206
|
init_codingChild();
|
|
35706
36207
|
init_settle();
|
|
36208
|
+
init_reattach();
|
|
36209
|
+
init_factory();
|
|
35707
36210
|
init_lineage();
|
|
35708
36211
|
init_seed();
|
|
35709
36212
|
init_session();
|
|
35710
36213
|
init_thread();
|
|
36214
|
+
init_threadAssets();
|
|
35711
36215
|
init_select();
|
|
35712
36216
|
init_spawn();
|
|
35713
36217
|
init_runsService();
|
|
@@ -35718,7 +36222,7 @@ var init_dispatcher = __esm({
|
|
|
35718
36222
|
});
|
|
35719
36223
|
|
|
35720
36224
|
// ../../src/core/runHistoryWriter.ts
|
|
35721
|
-
function
|
|
36225
|
+
function describe8(err2) {
|
|
35722
36226
|
return err2 instanceof Error ? err2.message : String(err2);
|
|
35723
36227
|
}
|
|
35724
36228
|
function createRunHistoryWriter(opts) {
|
|
@@ -35735,7 +36239,7 @@ function createRunHistoryWriter(opts) {
|
|
|
35735
36239
|
try {
|
|
35736
36240
|
opts.onPersisted?.(id);
|
|
35737
36241
|
} catch (err2) {
|
|
35738
|
-
opts.warn(`[run-history] onPersisted hook failed for ${id}: ${
|
|
36242
|
+
opts.warn(`[run-history] onPersisted hook failed for ${id}: ${describe8(err2)}`);
|
|
35739
36243
|
}
|
|
35740
36244
|
};
|
|
35741
36245
|
const attemptAll = async (record2, flag2, sink, span) => {
|
|
@@ -35758,12 +36262,12 @@ function createRunHistoryWriter(opts) {
|
|
|
35758
36262
|
}
|
|
35759
36263
|
if (err2 instanceof PermanentStoreError) {
|
|
35760
36264
|
failures++;
|
|
35761
|
-
opts.warn(`[run-history] ${record2.id} not persisted (permanent, not retried): ${
|
|
36265
|
+
opts.warn(`[run-history] ${record2.id} not persisted (permanent, not retried): ${describe8(err2)}`);
|
|
35762
36266
|
return;
|
|
35763
36267
|
}
|
|
35764
36268
|
if (attempt >= attempts) {
|
|
35765
36269
|
failures++;
|
|
35766
|
-
opts.warn(`[run-history] ${record2.id} not persisted after ${attempts} attempts: ${
|
|
36270
|
+
opts.warn(`[run-history] ${record2.id} not persisted after ${attempts} attempts: ${describe8(err2)}`);
|
|
35767
36271
|
return;
|
|
35768
36272
|
}
|
|
35769
36273
|
await sleep2(jittered(RUN_HISTORY_RETRY_DELAYS_MS[attempt - 1]));
|
|
@@ -35783,7 +36287,7 @@ function createRunHistoryWriter(opts) {
|
|
|
35783
36287
|
}
|
|
35784
36288
|
const p = attemptAll(record2, flag2, writeOpts?.via ?? opts.store, writeOpts?.span).catch((err2) => {
|
|
35785
36289
|
failures++;
|
|
35786
|
-
opts.warn(`[run-history] ${record2.id} writer failed unexpectedly: ${
|
|
36290
|
+
opts.warn(`[run-history] ${record2.id} writer failed unexpectedly: ${describe8(err2)}`);
|
|
35787
36291
|
}).finally(() => {
|
|
35788
36292
|
if (flag2) provisionalFlags.delete(flag2);
|
|
35789
36293
|
void inFlight.delete(p);
|
|
@@ -36200,7 +36704,7 @@ function createLedgerWriteThrough(opts) {
|
|
|
36200
36704
|
return { outcome: "untracked" };
|
|
36201
36705
|
}
|
|
36202
36706
|
if (err2 instanceof PermanentStoreError || attempt >= claimAttempts) {
|
|
36203
|
-
warn(`[ledger] ${req.threadKey} not tracked: claim failed after ${attempt} attempt(s): ${
|
|
36707
|
+
warn(`[ledger] ${req.threadKey} not tracked: claim failed after ${attempt} attempt(s): ${describe9(err2)}`);
|
|
36204
36708
|
return { outcome: "untracked" };
|
|
36205
36709
|
}
|
|
36206
36710
|
await sleep2(RETRY_MS[Math.min(attempt, RETRY_MS.length) - 1]);
|
|
@@ -36362,7 +36866,7 @@ function createLedgerWriteThrough(opts) {
|
|
|
36362
36866
|
if (!recorded.ok) this.detach(`seed record refused (${recorded.reason})`);
|
|
36363
36867
|
else this.seeded = true;
|
|
36364
36868
|
} catch (err2) {
|
|
36365
|
-
this.detach(`seed failed: ${
|
|
36869
|
+
this.detach(`seed failed: ${describe9(err2)}`);
|
|
36366
36870
|
}
|
|
36367
36871
|
}
|
|
36368
36872
|
async step(report2) {
|
|
@@ -36389,7 +36893,7 @@ function createLedgerWriteThrough(opts) {
|
|
|
36389
36893
|
return;
|
|
36390
36894
|
} catch (err2) {
|
|
36391
36895
|
if (err2 instanceof RouteMissingError || err2 instanceof PermanentStoreError || attempt >= 2) {
|
|
36392
|
-
this.detach(`step ${record2.step} failed: ${
|
|
36896
|
+
this.detach(`step ${record2.step} failed: ${describe9(err2)}`);
|
|
36393
36897
|
return;
|
|
36394
36898
|
}
|
|
36395
36899
|
await sleep2(RETRY_MS[0]);
|
|
@@ -36422,7 +36926,7 @@ function createLedgerWriteThrough(opts) {
|
|
|
36422
36926
|
} catch (err2) {
|
|
36423
36927
|
if (err2 instanceof RouteMissingError || err2 instanceof PermanentStoreError || attempt >= 2) {
|
|
36424
36928
|
this.stateDirty = true;
|
|
36425
|
-
warn(`[ledger] ${this.threadKey} state not written: ${
|
|
36929
|
+
warn(`[ledger] ${this.threadKey} state not written: ${describe9(err2)}`);
|
|
36426
36930
|
return;
|
|
36427
36931
|
}
|
|
36428
36932
|
await sleep2(RETRY_MS[0]);
|
|
@@ -36440,7 +36944,7 @@ function createLedgerWriteThrough(opts) {
|
|
|
36440
36944
|
this.detach(`finishing refused (fenced)`);
|
|
36441
36945
|
return "fenced";
|
|
36442
36946
|
} catch (err2) {
|
|
36443
|
-
warn(`[ledger] ${this.threadKey} finishing failed: ${
|
|
36947
|
+
warn(`[ledger] ${this.threadKey} finishing failed: ${describe9(err2)}`);
|
|
36444
36948
|
return "unavailable";
|
|
36445
36949
|
}
|
|
36446
36950
|
}
|
|
@@ -36455,7 +36959,7 @@ function createLedgerWriteThrough(opts) {
|
|
|
36455
36959
|
warn(`[ledger] ${this.threadKey} abandon refused (fenced) \u2014 the row is another generation's`);
|
|
36456
36960
|
} catch (err2) {
|
|
36457
36961
|
warn(
|
|
36458
|
-
`[ledger] ${this.threadKey} abandon failed: ${
|
|
36962
|
+
`[ledger] ${this.threadKey} abandon failed: ${describe9(err2)} \u2014 the sweep will take the row once its lease lapses`
|
|
36459
36963
|
);
|
|
36460
36964
|
}
|
|
36461
36965
|
}
|
|
@@ -36476,7 +36980,7 @@ function createLedgerWriteThrough(opts) {
|
|
|
36476
36980
|
this.onStop(result.stop);
|
|
36477
36981
|
}
|
|
36478
36982
|
} catch (err2) {
|
|
36479
|
-
warn(`[ledger] ${this.threadKey} heartbeat failed: ${
|
|
36983
|
+
warn(`[ledger] ${this.threadKey} heartbeat failed: ${describe9(err2)}`);
|
|
36480
36984
|
}
|
|
36481
36985
|
}
|
|
36482
36986
|
stopHeartbeat() {
|
|
@@ -36554,7 +37058,7 @@ function createLedgerWriteThrough(opts) {
|
|
|
36554
37058
|
warn(`[ledger] inbox push refused for run ${runId3}: no live row \u2014 the follow-up rides in memory only`);
|
|
36555
37059
|
return void 0;
|
|
36556
37060
|
} catch (err2) {
|
|
36557
|
-
warn(`[ledger] inbox push failed for run ${runId3}: ${
|
|
37061
|
+
warn(`[ledger] inbox push failed for run ${runId3}: ${describe9(err2)} \u2014 the follow-up rides in memory only`);
|
|
36558
37062
|
return void 0;
|
|
36559
37063
|
}
|
|
36560
37064
|
},
|
|
@@ -36563,7 +37067,7 @@ function createLedgerWriteThrough(opts) {
|
|
|
36563
37067
|
return await ledger.readInbox(runId3, afterSeq);
|
|
36564
37068
|
} catch (err2) {
|
|
36565
37069
|
warn(
|
|
36566
|
-
err2 instanceof RouteMissingError ? `[ledger] state Worker has no inbox read route \u2014 run ${runId3} resumes with the reclaim's inbox snapshot only` : `[ledger] inbox read failed for run ${runId3}: ${
|
|
37070
|
+
err2 instanceof RouteMissingError ? `[ledger] state Worker has no inbox read route \u2014 run ${runId3} resumes with the reclaim's inbox snapshot only` : `[ledger] inbox read failed for run ${runId3}: ${describe9(err2)} \u2014 resuming with the reclaim's snapshot only`
|
|
36567
37071
|
);
|
|
36568
37072
|
return [];
|
|
36569
37073
|
}
|
|
@@ -36585,12 +37089,12 @@ function createLedgerWriteThrough(opts) {
|
|
|
36585
37089
|
for (const r of candidates) if (markedSet.has(r.runId)) r.markHandedOff();
|
|
36586
37090
|
return { marked };
|
|
36587
37091
|
} catch (err2) {
|
|
36588
|
-
return { marked: [], failed:
|
|
37092
|
+
return { marked: [], failed: describe9(err2) };
|
|
36589
37093
|
}
|
|
36590
37094
|
}
|
|
36591
37095
|
};
|
|
36592
37096
|
}
|
|
36593
|
-
var NullLedgerWriteThrough, NullLedgerRun, RETRY_MS,
|
|
37097
|
+
var NullLedgerWriteThrough, NullLedgerRun, RETRY_MS, describe9;
|
|
36594
37098
|
var init_writeThrough = __esm({
|
|
36595
37099
|
"../../src/core/runLedger/writeThrough.ts"() {
|
|
36596
37100
|
"use strict";
|
|
@@ -36670,7 +37174,7 @@ var init_writeThrough = __esm({
|
|
|
36670
37174
|
}
|
|
36671
37175
|
};
|
|
36672
37176
|
RETRY_MS = [200, 800];
|
|
36673
|
-
|
|
37177
|
+
describe9 = (err2) => err2 instanceof Error ? err2.message : String(err2);
|
|
36674
37178
|
}
|
|
36675
37179
|
});
|
|
36676
37180
|
|
|
@@ -41316,7 +41820,7 @@ async function reclaimRuns(opts) {
|
|
|
41316
41820
|
reclaimed = await ledger.reclaim(gen, now(), LEASE_MS);
|
|
41317
41821
|
} catch (err2) {
|
|
41318
41822
|
warn(
|
|
41319
|
-
err2 instanceof RouteMissingError ? "[reclaim] state Worker has no run-ledger routes \u2014 nothing to take over" : `[reclaim] reclaim failed: ${
|
|
41823
|
+
err2 instanceof RouteMissingError ? "[reclaim] state Worker has no run-ledger routes \u2014 nothing to take over" : `[reclaim] reclaim failed: ${describe10(err2)} \u2014 runs the last generation left stay on the ledger until the next boot`
|
|
41320
41824
|
);
|
|
41321
41825
|
return outcome;
|
|
41322
41826
|
}
|
|
@@ -41384,8 +41888,8 @@ async function reclaimRuns(opts) {
|
|
|
41384
41888
|
`[reclaim] ${row.runId} ${row.threadKey} closed ${status3} (from ${run2.reclaimedFrom}; ${why}; ${events.length} event(s))`
|
|
41385
41889
|
);
|
|
41386
41890
|
} catch (err2) {
|
|
41387
|
-
outcome.failed.push({ runId: row.runId, error:
|
|
41388
|
-
warn(`[reclaim] ${row.runId} ${row.threadKey}: ${
|
|
41891
|
+
outcome.failed.push({ runId: row.runId, error: describe10(err2) });
|
|
41892
|
+
warn(`[reclaim] ${row.runId} ${row.threadKey}: ${describe10(err2)} \u2014 left on the ledger for the next boot`);
|
|
41389
41893
|
}
|
|
41390
41894
|
}
|
|
41391
41895
|
try {
|
|
@@ -41401,7 +41905,7 @@ async function reclaimRuns(opts) {
|
|
|
41401
41905
|
});
|
|
41402
41906
|
}
|
|
41403
41907
|
} catch (err2) {
|
|
41404
|
-
warn(`[reclaim] listing live runs failed: ${
|
|
41908
|
+
warn(`[reclaim] listing live runs failed: ${describe10(err2)} \u2014 the card sweep runs without the ledger's guard`);
|
|
41405
41909
|
}
|
|
41406
41910
|
if (reclaimed.length > 0 || outcome.liveElsewhere.length > 0) {
|
|
41407
41911
|
log(
|
|
@@ -41423,7 +41927,7 @@ function startReclaimSweep(opts) {
|
|
|
41423
41927
|
await opts.onOutcome(outcome);
|
|
41424
41928
|
}
|
|
41425
41929
|
} catch (err2) {
|
|
41426
|
-
warn(`[reclaim] sweep failed: ${
|
|
41930
|
+
warn(`[reclaim] sweep failed: ${describe10(err2)}`);
|
|
41427
41931
|
} finally {
|
|
41428
41932
|
running = false;
|
|
41429
41933
|
}
|
|
@@ -41449,7 +41953,7 @@ async function completenessVerdict(ledger, row, lastStep) {
|
|
|
41449
41953
|
const source2 = transcriptSource(row.meta);
|
|
41450
41954
|
transcript = source2.kind === "session" ? await ledger.readSession(source2.key, source2.from) : await ledger.readTranscript(row.runId);
|
|
41451
41955
|
} catch (err2) {
|
|
41452
|
-
return { resumable: false, why: `transcript unreadable (${
|
|
41956
|
+
return { resumable: false, why: `transcript unreadable (${describe10(err2)})` };
|
|
41453
41957
|
}
|
|
41454
41958
|
if (!transcript.complete) return { resumable: false, why: `transcript incomplete: ${transcript.gap}` };
|
|
41455
41959
|
const verdict = transcriptCompleteness({
|
|
@@ -41470,7 +41974,7 @@ async function completenessVerdict(ledger, row, lastStep) {
|
|
|
41470
41974
|
return { resumable: false, why: verdict.why };
|
|
41471
41975
|
}
|
|
41472
41976
|
}
|
|
41473
|
-
var TERMINAL,
|
|
41977
|
+
var TERMINAL, describe10;
|
|
41474
41978
|
var init_boot = __esm({
|
|
41475
41979
|
"../../src/core/boot.ts"() {
|
|
41476
41980
|
"use strict";
|
|
@@ -41487,7 +41991,7 @@ var init_boot = __esm({
|
|
|
41487
41991
|
"failed",
|
|
41488
41992
|
"interrupted"
|
|
41489
41993
|
]);
|
|
41490
|
-
|
|
41994
|
+
describe10 = (err2) => err2 instanceof Error ? err2.message : String(err2);
|
|
41491
41995
|
}
|
|
41492
41996
|
});
|
|
41493
41997
|
|
|
@@ -42336,6 +42840,17 @@ var init_toolRules = __esm({
|
|
|
42336
42840
|
});
|
|
42337
42841
|
|
|
42338
42842
|
// ../../src/core/harness/pi/relay.ts
|
|
42843
|
+
async function relayToolCall(harness, calls, ask, opts = {}) {
|
|
42844
|
+
const answer = calls.join(ask.toolCallId, () => runRelayedTool(harness, ask, { signal: calls.signal }));
|
|
42845
|
+
const window = new AbortController();
|
|
42846
|
+
const sleep2 = opts.sleep ?? sleepUnlessAborted;
|
|
42847
|
+
const progress = await Promise.race([
|
|
42848
|
+
answer.then((a) => ({ done: true, answer: a })),
|
|
42849
|
+
sleep2(opts.windowMs ?? RELAY_POLL_WINDOW_MS, window.signal).then(() => ({ done: false }))
|
|
42850
|
+
]);
|
|
42851
|
+
window.abort();
|
|
42852
|
+
return progress;
|
|
42853
|
+
}
|
|
42339
42854
|
function relayedToolDefinitions(harness) {
|
|
42340
42855
|
return harness.tools.map(({ name, description, inputSchema }) => ({ name, description, inputSchema }));
|
|
42341
42856
|
}
|
|
@@ -42356,18 +42871,23 @@ function authorizeToolCall(harness, ask) {
|
|
|
42356
42871
|
if (verdict.verdict === "allowed") return { allow: true };
|
|
42357
42872
|
return refuse3(verdict.reason);
|
|
42358
42873
|
}
|
|
42359
|
-
async function runRelayedTool(harness, ask) {
|
|
42874
|
+
async function runRelayedTool(harness, ask, opts = {}) {
|
|
42360
42875
|
const tool = harness.tools.find((t) => t.name === ask.tool);
|
|
42361
42876
|
if (!tool) return { content: [{ type: "text", text: `Unknown tool: ${ask.tool}` }], isError: true };
|
|
42362
42877
|
const span = harness.toolSpan(ask.toolCallId);
|
|
42363
42878
|
const base = harness.toolContext;
|
|
42364
|
-
const
|
|
42365
|
-
|
|
42366
|
-
span
|
|
42367
|
-
|
|
42368
|
-
|
|
42369
|
-
|
|
42370
|
-
|
|
42879
|
+
const readConversation = base.conversation;
|
|
42880
|
+
const ctx = {
|
|
42881
|
+
...span ? {
|
|
42882
|
+
...base,
|
|
42883
|
+
span,
|
|
42884
|
+
executor: new TracingExecutor(base.executor, span, harness.backend),
|
|
42885
|
+
publish: (e) => harness.emit(withSpanId2(e, span.id)),
|
|
42886
|
+
...base.github?.api.withSpan ? { github: { ...base.github, api: base.github.api.withSpan(span) } } : {}
|
|
42887
|
+
} : { ...base, publish: (e) => harness.emit(e) },
|
|
42888
|
+
...opts.signal && !base.signal ? { signal: opts.signal } : {},
|
|
42889
|
+
...readConversation && harness.callSeen ? { conversation: () => harness.callSeen(ask.toolCallId).then(() => readConversation()) } : {}
|
|
42890
|
+
};
|
|
42371
42891
|
try {
|
|
42372
42892
|
const input = typeof ask.input === "object" && ask.input !== null ? ask.input : {};
|
|
42373
42893
|
const output = await tool.run(input, ctx);
|
|
@@ -42395,30 +42915,64 @@ function withSpanId2(e, spanId) {
|
|
|
42395
42915
|
return e;
|
|
42396
42916
|
}
|
|
42397
42917
|
}
|
|
42398
|
-
var HarnessRegistry;
|
|
42918
|
+
var HarnessRegistry, RELAY_POLL_WINDOW_MS, RelayedCalls;
|
|
42399
42919
|
var init_relay = __esm({
|
|
42400
42920
|
"../../src/core/harness/pi/relay.ts"() {
|
|
42401
42921
|
"use strict";
|
|
42402
42922
|
init_tracingExecutor();
|
|
42403
42923
|
init_types3();
|
|
42924
|
+
init_awaitChildren();
|
|
42404
42925
|
init_runEvents();
|
|
42405
42926
|
init_toolRules();
|
|
42406
42927
|
HarnessRegistry = class {
|
|
42407
42928
|
live = /* @__PURE__ */ new Map();
|
|
42408
|
-
/** The run drives a pi from here
|
|
42929
|
+
/** The run drives a pi from here, its relayed calls kept beside it; the
|
|
42930
|
+
* returned function forgets it and ends whatever call still runs. */
|
|
42409
42931
|
register(harness) {
|
|
42410
|
-
|
|
42932
|
+
const entry = { harness, calls: new RelayedCalls() };
|
|
42933
|
+
this.live.set(harness.runId, entry);
|
|
42411
42934
|
return () => {
|
|
42412
|
-
if (this.live.get(harness.runId)
|
|
42935
|
+
if (this.live.get(harness.runId) !== entry) return;
|
|
42936
|
+
this.live.delete(harness.runId);
|
|
42937
|
+
entry.calls.end();
|
|
42413
42938
|
};
|
|
42414
42939
|
}
|
|
42415
42940
|
get(runId3) {
|
|
42416
|
-
return this.live.get(runId3);
|
|
42941
|
+
return this.live.get(runId3)?.harness;
|
|
42942
|
+
}
|
|
42943
|
+
/** The run's relayed calls, for as long as it is registered. */
|
|
42944
|
+
calls(runId3) {
|
|
42945
|
+
return this.live.get(runId3)?.calls;
|
|
42417
42946
|
}
|
|
42418
42947
|
size() {
|
|
42419
42948
|
return this.live.size;
|
|
42420
42949
|
}
|
|
42421
42950
|
};
|
|
42951
|
+
RELAY_POLL_WINDOW_MS = 3e4;
|
|
42952
|
+
RelayedCalls = class {
|
|
42953
|
+
calls = /* @__PURE__ */ new Map();
|
|
42954
|
+
ending = new AbortController();
|
|
42955
|
+
get size() {
|
|
42956
|
+
return this.calls.size;
|
|
42957
|
+
}
|
|
42958
|
+
/** Aborted when the run ends: the signal every call here runs under. */
|
|
42959
|
+
get signal() {
|
|
42960
|
+
return this.ending.signal;
|
|
42961
|
+
}
|
|
42962
|
+
/** The call's answer as a promise: started by `start` on the first ask, the same promise after. */
|
|
42963
|
+
join(callId, start3) {
|
|
42964
|
+
let answer = this.calls.get(callId);
|
|
42965
|
+
if (!answer) {
|
|
42966
|
+
answer = start3();
|
|
42967
|
+
this.calls.set(callId, answer);
|
|
42968
|
+
}
|
|
42969
|
+
return answer;
|
|
42970
|
+
}
|
|
42971
|
+
end() {
|
|
42972
|
+
this.ending.abort();
|
|
42973
|
+
this.calls.clear();
|
|
42974
|
+
}
|
|
42975
|
+
};
|
|
42422
42976
|
}
|
|
42423
42977
|
});
|
|
42424
42978
|
|
|
@@ -42467,7 +43021,15 @@ async function handleHarnessRequest(deps, req) {
|
|
|
42467
43021
|
deps.log?.(`[harness] run=${door.runId} authorize ${ask.tool} \u2192 ${answer2.allow ? "allow" : "refuse"}`);
|
|
42468
43022
|
return { status: 200, body: { ...answer2 } };
|
|
42469
43023
|
}
|
|
42470
|
-
const
|
|
43024
|
+
const progress = await relayToolCall(harness, deps.harnesses.calls(door.runId), ask, {
|
|
43025
|
+
...deps.relayWindowMs !== void 0 ? { windowMs: deps.relayWindowMs } : {},
|
|
43026
|
+
...deps.sleep ? { sleep: deps.sleep } : {}
|
|
43027
|
+
});
|
|
43028
|
+
if (!progress.done) {
|
|
43029
|
+
deps.log?.(`[harness] run=${door.runId} tool ${ask.tool} \u2192 pending`);
|
|
43030
|
+
return { status: 202, body: { pending: true, toolCallId: ask.toolCallId } };
|
|
43031
|
+
}
|
|
43032
|
+
const { answer } = progress;
|
|
42471
43033
|
deps.log?.(`[harness] run=${door.runId} tool ${ask.tool} \u2192 ${answer.isError ? "error" : "ok"}`);
|
|
42472
43034
|
return { status: 200, body: { ...answer } };
|
|
42473
43035
|
}
|
|
@@ -42803,7 +43365,7 @@ async function openThreadFromRequester(deps, instance, lead, at) {
|
|
|
42803
43365
|
}
|
|
42804
43366
|
};
|
|
42805
43367
|
} catch (err2) {
|
|
42806
|
-
return { ok: false, response: json(502, { ok: false, error: "thread_failed", message:
|
|
43368
|
+
return { ok: false, response: json(502, { ok: false, error: "thread_failed", message: describe11(err2), at }) };
|
|
42807
43369
|
}
|
|
42808
43370
|
}
|
|
42809
43371
|
async function ensureReviewThread(deps, instance, row, at) {
|
|
@@ -42929,8 +43491,8 @@ async function spawn6(body, deps) {
|
|
|
42929
43491
|
try {
|
|
42930
43492
|
turn = await composeChild(req.brief, instance, row, briefReaders(deps, instance, io));
|
|
42931
43493
|
} catch (err2) {
|
|
42932
|
-
log(`[coordinator] ${instance.id} ${req.step}: the brief could not be composed: ${
|
|
42933
|
-
return json(502, { ok: false, error: "brief_failed", message:
|
|
43494
|
+
log(`[coordinator] ${instance.id} ${req.step}: the brief could not be composed: ${describe11(err2)}`);
|
|
43495
|
+
return json(502, { ok: false, error: "brief_failed", message: describe11(err2), at });
|
|
42934
43496
|
}
|
|
42935
43497
|
} else {
|
|
42936
43498
|
turn = { prompt: req.prompt };
|
|
@@ -42980,7 +43542,7 @@ async function spawn6(body, deps) {
|
|
|
42980
43542
|
);
|
|
42981
43543
|
void settled.then((end) => {
|
|
42982
43544
|
if (end.kind === "threw")
|
|
42983
|
-
log(`[coordinator] ${instance.id} ${req.step}: the child's dispatch threw: ${
|
|
43545
|
+
log(`[coordinator] ${instance.id} ${req.step}: the child's dispatch threw: ${describe11(end.err)}`);
|
|
42984
43546
|
});
|
|
42985
43547
|
const first = await Promise.race([started.then((id) => ({ kind: "started", id })), settled]);
|
|
42986
43548
|
if (first.kind === "started" || startedId !== void 0) {
|
|
@@ -42988,7 +43550,7 @@ async function spawn6(body, deps) {
|
|
|
42988
43550
|
log(`[coordinator] ${instance.id} ${req.step}: spawned ${req.preset} run ${runId3} in ${threadKey}`);
|
|
42989
43551
|
return json(200, { ok: true, runId: runId3, threadKey, at });
|
|
42990
43552
|
}
|
|
42991
|
-
if (first.kind === "threw") return json(502, { ok: false, error: "spawn_failed", message:
|
|
43553
|
+
if (first.kind === "threw") return json(502, { ok: false, error: "spawn_failed", message: describe11(first.err), at });
|
|
42992
43554
|
const refusal = first.outcome.refusal;
|
|
42993
43555
|
if (refusal === "coordinator_thread_live") {
|
|
42994
43556
|
const now = await liveOnThread(deps.runs, instance, threadKey);
|
|
@@ -43141,7 +43703,7 @@ async function prCheck(body, deps) {
|
|
|
43141
43703
|
at
|
|
43142
43704
|
});
|
|
43143
43705
|
} catch (err2) {
|
|
43144
|
-
return json(502, { ok: false, error: "github_unavailable", message:
|
|
43706
|
+
return json(502, { ok: false, error: "github_unavailable", message: describe11(err2), at });
|
|
43145
43707
|
}
|
|
43146
43708
|
}
|
|
43147
43709
|
async function plan2(body, deps) {
|
|
@@ -43250,7 +43812,7 @@ async function branch(body, deps) {
|
|
|
43250
43812
|
await deps.createBranchRef(instance.repo, name, base);
|
|
43251
43813
|
return json(200, { ok: true, branch: name, base, at });
|
|
43252
43814
|
} catch (err2) {
|
|
43253
|
-
return json(200, { ok: false, reason:
|
|
43815
|
+
return json(200, { ok: false, reason: describe11(err2), at });
|
|
43254
43816
|
}
|
|
43255
43817
|
}
|
|
43256
43818
|
function unitLines(units) {
|
|
@@ -43302,7 +43864,7 @@ async function round(body, deps) {
|
|
|
43302
43864
|
instance,
|
|
43303
43865
|
units.map((u) => u.unit === updated.unit ? updated : u)
|
|
43304
43866
|
).catch(
|
|
43305
|
-
(err2) => (deps.log ?? console.warn)(`[coordinator] ${instance.id}: the card could not be redrawn: ${
|
|
43867
|
+
(err2) => (deps.log ?? console.warn)(`[coordinator] ${instance.id}: the card could not be redrawn: ${describe11(err2)}`)
|
|
43306
43868
|
);
|
|
43307
43869
|
return json(200, { ok: true, at });
|
|
43308
43870
|
}
|
|
@@ -43336,7 +43898,7 @@ async function unitEnd(body, deps) {
|
|
|
43336
43898
|
told = true;
|
|
43337
43899
|
} catch (err2) {
|
|
43338
43900
|
(deps.log ?? console.warn)(
|
|
43339
|
-
`[coordinator] ${instance.id} ${row.unit}: the report could not be posted: ${
|
|
43901
|
+
`[coordinator] ${instance.id} ${row.unit}: the report could not be posted: ${describe11(err2)}`
|
|
43340
43902
|
);
|
|
43341
43903
|
}
|
|
43342
43904
|
}
|
|
@@ -43350,7 +43912,7 @@ ${ending.report}` + (rendered !== void 0 ? `
|
|
|
43350
43912
|
${rendered}` : "");
|
|
43351
43913
|
await deps.github.commentIssue(instance.repo, row.issue, comment).catch(
|
|
43352
43914
|
(err2) => (deps.log ?? console.warn)(
|
|
43353
|
-
`[coordinator] ${instance.id} ${row.unit}: the board comment could not be posted: ${
|
|
43915
|
+
`[coordinator] ${instance.id} ${row.unit}: the board comment could not be posted: ${describe11(err2)}`
|
|
43354
43916
|
)
|
|
43355
43917
|
);
|
|
43356
43918
|
}
|
|
@@ -43405,7 +43967,7 @@ async function merge(body, deps, subject2) {
|
|
|
43405
43967
|
try {
|
|
43406
43968
|
facts2 = await deps.fetchPrFacts(pr);
|
|
43407
43969
|
} catch (err2) {
|
|
43408
|
-
return json(502, { ok: false, error: "github_unavailable", message:
|
|
43970
|
+
return json(502, { ok: false, error: "github_unavailable", message: describe11(err2), at });
|
|
43409
43971
|
}
|
|
43410
43972
|
if (facts2 === void 0)
|
|
43411
43973
|
return json(502, { ok: false, error: "github_unavailable", message: `${where} could not be read`, at });
|
|
@@ -43457,7 +44019,7 @@ async function merge(body, deps, subject2) {
|
|
|
43457
44019
|
title: facts2.title ?? `Merge pull request #${pr.number}`
|
|
43458
44020
|
});
|
|
43459
44021
|
} catch (err2) {
|
|
43460
|
-
return json(502, { ok: false, error: "github_unavailable", message:
|
|
44022
|
+
return json(502, { ok: false, error: "github_unavailable", message: describe11(err2), at });
|
|
43461
44023
|
}
|
|
43462
44024
|
if (!merged.ok) {
|
|
43463
44025
|
log(
|
|
@@ -43632,13 +44194,13 @@ function createAdminCoordinatorHandler(deps) {
|
|
|
43632
44194
|
}
|
|
43633
44195
|
write(res, await answerCoordinatorStep(door, read.body, deps));
|
|
43634
44196
|
} catch (err2) {
|
|
43635
|
-
(deps.log ?? console.error)(`[coordinator] ${
|
|
44197
|
+
(deps.log ?? console.error)(`[coordinator] ${describe11(err2)}`);
|
|
43636
44198
|
write(res, json(500, { ok: false, error: "internal error" }));
|
|
43637
44199
|
}
|
|
43638
44200
|
})();
|
|
43639
44201
|
};
|
|
43640
44202
|
}
|
|
43641
|
-
var COORDINATOR_ADMIN_PREFIX, MAX_SPAWN_PROMPT_CHARS, FINISHED_LOOKBACK_PAGES, MAX_ADMIN_BODY_BYTES, UNIT_ID, PRESETS_OF_KIND, invalid, json,
|
|
44203
|
+
var COORDINATOR_ADMIN_PREFIX, MAX_SPAWN_PROMPT_CHARS, FINISHED_LOOKBACK_PAGES, MAX_ADMIN_BODY_BYTES, UNIT_ID, PRESETS_OF_KIND, invalid, json, describe11, EVERY_RUN, REVIEW_POSTED_CHECKS, REVIEW_POSTED_RECHECK_MS, ROUND_OUTCOMES, ENDING_ICON, STEPS;
|
|
43642
44204
|
var init_adminCoordinator = __esm({
|
|
43643
44205
|
"../../src/channels/adminCoordinator.ts"() {
|
|
43644
44206
|
"use strict";
|
|
@@ -43671,7 +44233,7 @@ var init_adminCoordinator = __esm({
|
|
|
43671
44233
|
};
|
|
43672
44234
|
invalid = (error) => ({ ok: false, error });
|
|
43673
44235
|
json = (status3, body) => ({ status: status3, body });
|
|
43674
|
-
|
|
44236
|
+
describe11 = (err2) => err2 instanceof Error ? err2.message : String(err2);
|
|
43675
44237
|
EVERY_RUN = { kind: "all" };
|
|
43676
44238
|
REVIEW_POSTED_CHECKS = 3;
|
|
43677
44239
|
REVIEW_POSTED_RECHECK_MS = 2e3;
|