@coreplane/switchboard 1.260.6 → 1.261.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-memory/worker.ts +90 -2
- 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/core/coordinator/driver.ts +17 -5
- package/dist/assets/src/core/pipelineStanding.ts +24 -0
- package/dist/assets/src/core/plane/decide.ts +25 -0
- package/dist/assets/src/core/reviewVerdict.ts +33 -6
- package/dist/assets/src/core/runEvents.ts +5 -0
- package/dist/assets/src/core/runFriction.ts +2 -0
- package/dist/assets/src/core/runLedger/types.ts +21 -0
- package/dist/assets/src/core/runLiveState.ts +205 -0
- package/dist/assets/src/core/runRecord.ts +4 -0
- package/dist/assets/src/core/ship/coordinator.ts +330 -72
- package/dist/assets/src/core/ship/renewal.ts +1 -1
- package/dist/cli.js +1784 -673
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -195,7 +195,9 @@ async function ensureWorkArea(at, version2, workers, deps) {
|
|
|
195
195
|
deps.log(`[deploy] materialised the shipped tree (version ${version2}) under ${at.workArea}`);
|
|
196
196
|
}
|
|
197
197
|
if (plan3.install.length > 0) {
|
|
198
|
-
deps.log(
|
|
198
|
+
deps.log(
|
|
199
|
+
`[deploy] npm ci --include-workspace-root --workspace ${plan3.install.join(" --workspace ")} under ${at.workArea}`
|
|
200
|
+
);
|
|
199
201
|
const r = await deps.install(at.workArea, plan3.install);
|
|
200
202
|
if (r.code !== 0)
|
|
201
203
|
return {
|
|
@@ -241,10 +243,22 @@ function packageSourceOnHost(at = OPERATOR_ROOT) {
|
|
|
241
243
|
function cliVersionOnHost(at = OPERATOR_ROOT) {
|
|
242
244
|
return at.mode === "package" ? packageSourceOnHost(at).version : packageVersion();
|
|
243
245
|
}
|
|
246
|
+
function workAreaNpmCiArgs(workspaces) {
|
|
247
|
+
return [
|
|
248
|
+
"ci",
|
|
249
|
+
"--include-workspace-root",
|
|
250
|
+
"--no-audit",
|
|
251
|
+
"--no-fund",
|
|
252
|
+
...workspaces.flatMap((w) => ["--workspace", w])
|
|
253
|
+
];
|
|
254
|
+
}
|
|
244
255
|
function npmCi(cwd, workspaces) {
|
|
245
256
|
return new Promise((resolve13) => {
|
|
246
|
-
const
|
|
247
|
-
|
|
257
|
+
const child = spawn("npm", workAreaNpmCiArgs(workspaces), {
|
|
258
|
+
cwd,
|
|
259
|
+
env: process.env,
|
|
260
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
261
|
+
});
|
|
248
262
|
let output = "";
|
|
249
263
|
child.stdout.on("data", (c) => output += c.toString());
|
|
250
264
|
child.stderr.on("data", (c) => output += c.toString());
|
|
@@ -3264,7 +3278,7 @@ function renewalDecision(input) {
|
|
|
3264
3278
|
};
|
|
3265
3279
|
}
|
|
3266
3280
|
function renderRenewal(decision, grant2, options = {}) {
|
|
3267
|
-
const recourse = options.idle ? "the next reply in this thread continues the unit" : "
|
|
3281
|
+
const recourse = options.idle ? "the next reply in this thread continues the unit" : "start ship again with the original task";
|
|
3268
3282
|
const senders = options.senders?.length ? `, with ${options.senders.length} message${options.senders.length === 1 ? "" : "s"} from ${options.senders.join(", ")}` : "";
|
|
3269
3283
|
if (decision.renew)
|
|
3270
3284
|
return `budget renewed, ${decision.segment - 1} of ${grant2.renewals}, continues ${decision.from !== void 0 ? decision.from.slice(0, 7) : "the branch's head"}${senders}`;
|
|
@@ -3564,11 +3578,11 @@ function buildReviewPostBody(answer, verdict, target) {
|
|
|
3564
3578
|
...target ? [`head \`${target.head.slice(0, 7)}\``] : [],
|
|
3565
3579
|
verdict ? findingCounts(verdict.findings) : "the run ended without a submit_verdict call"
|
|
3566
3580
|
];
|
|
3567
|
-
const
|
|
3581
|
+
const fixedParts = [verdictLine(verdict), `> [!${calloutKind(verdict)}]
|
|
3568
3582
|
> ${facts2.join(" \xB7 ")}`];
|
|
3569
3583
|
const findings = verdict?.findings ?? [];
|
|
3570
3584
|
if (findings.length > 0) {
|
|
3571
|
-
|
|
3585
|
+
fixedParts.push(
|
|
3572
3586
|
[
|
|
3573
3587
|
"| Severity | Finding | Where |",
|
|
3574
3588
|
"| --- | --- | --- |",
|
|
@@ -3578,15 +3592,25 @@ function buildReviewPostBody(answer, verdict, target) {
|
|
|
3578
3592
|
].join("\n")
|
|
3579
3593
|
);
|
|
3580
3594
|
}
|
|
3595
|
+
const marker = verdictMarker(verdict, target);
|
|
3596
|
+
const fixedBody = [...fixedParts, marker].join("\n\n");
|
|
3581
3597
|
const prose2 = answer.trim();
|
|
3582
|
-
if (prose2)
|
|
3598
|
+
if (!prose2) return fixedBody;
|
|
3599
|
+
const details2 = (text, truncated) => `<details>
|
|
3583
3600
|
<summary>Full review</summary>
|
|
3584
3601
|
|
|
3585
|
-
${
|
|
3602
|
+
${text}${truncated ? `${text ? "\n\n" : ""}${REVIEW_TRUNCATION_NOTE}` : ""}
|
|
3586
3603
|
|
|
3587
|
-
</details
|
|
3588
|
-
|
|
3589
|
-
|
|
3604
|
+
</details>`;
|
|
3605
|
+
const render3 = (text, truncated) => [...fixedParts, details2(text, truncated), marker].join("\n\n");
|
|
3606
|
+
const full = render3(prose2, false);
|
|
3607
|
+
if ([...full].length <= MAX_REVIEW_POST_CODE_POINTS) return full;
|
|
3608
|
+
const clippedShell = render3("", true);
|
|
3609
|
+
const proseSeparatorCodePoints = 2;
|
|
3610
|
+
const proseBudget = MAX_REVIEW_POST_CODE_POINTS - [...clippedShell].length - proseSeparatorCodePoints;
|
|
3611
|
+
if (proseBudget > 0) return render3([...prose2].slice(0, proseBudget).join(""), true);
|
|
3612
|
+
if ([...clippedShell].length <= MAX_REVIEW_POST_CODE_POINTS) return clippedShell;
|
|
3613
|
+
return full;
|
|
3590
3614
|
}
|
|
3591
3615
|
function buildReviewChannelReply(input) {
|
|
3592
3616
|
const { answer, verdict, posted, liveUrl } = input;
|
|
@@ -3675,7 +3699,7 @@ function redactVerdict(v, redact = redactSecrets) {
|
|
|
3675
3699
|
function redactDispositions(dispositions, redact = redactSecrets) {
|
|
3676
3700
|
return dispositions.map((d) => ({ findingId: d.findingId, disposition: d.disposition, note: redact(d.note) }));
|
|
3677
3701
|
}
|
|
3678
|
-
var FINDING_SEVERITIES, ADDRESS_SEVERITIES, DEFAULT_ADDRESS_SEVERITY, isAddressSeverity, severityRank, LGTM_TOKEN, CHANGES_TOKEN, NO_VERDICT_LINE, escapeMarkdownTableCell, unescapeMarkdownTableCell, isRepoPath, VERDICT_KINDS, DISPOSITION_KINDS, isRecordLike, REVIEW_POST_HEAD;
|
|
3702
|
+
var FINDING_SEVERITIES, ADDRESS_SEVERITIES, DEFAULT_ADDRESS_SEVERITY, isAddressSeverity, severityRank, LGTM_TOKEN, CHANGES_TOKEN, NO_VERDICT_LINE, MAX_REVIEW_POST_CODE_POINTS, REVIEW_TRUNCATION_NOTE, escapeMarkdownTableCell, unescapeMarkdownTableCell, isRepoPath, VERDICT_KINDS, DISPOSITION_KINDS, isRecordLike, REVIEW_POST_HEAD;
|
|
3679
3703
|
var init_reviewVerdict = __esm({
|
|
3680
3704
|
"../../src/core/reviewVerdict.ts"() {
|
|
3681
3705
|
"use strict";
|
|
@@ -3690,6 +3714,8 @@ var init_reviewVerdict = __esm({
|
|
|
3690
3714
|
LGTM_TOKEN = "LGTM:";
|
|
3691
3715
|
CHANGES_TOKEN = "Changes requested:";
|
|
3692
3716
|
NO_VERDICT_LINE = "No verdict submitted \u2014 not approving.";
|
|
3717
|
+
MAX_REVIEW_POST_CODE_POINTS = 65e3;
|
|
3718
|
+
REVIEW_TRUNCATION_NOTE = "_(review truncated to fit GitHub's review size limit)_";
|
|
3693
3719
|
escapeMarkdownTableCell = (text) => oneLine2(text).replace(/\\/g, "\\\\").replace(/\|/g, "\\|");
|
|
3694
3720
|
unescapeMarkdownTableCell = (text) => text.replace(/\\([\\|])/g, "$1");
|
|
3695
3721
|
isRepoPath = (file) => /^[^\s`]+$/.test(file) && !/^[a-z][a-z0-9+.-]*:\/\//i.test(file);
|
|
@@ -3711,10 +3737,10 @@ function interruptionCauseOfWords(words) {
|
|
|
3711
3737
|
return void 0;
|
|
3712
3738
|
}
|
|
3713
3739
|
function shipInterruptedNote(prUrl3, cause, idle = false) {
|
|
3714
|
-
const
|
|
3715
|
-
const
|
|
3716
|
-
const
|
|
3717
|
-
return `${opening} ${
|
|
3740
|
+
const opening = cause === "container_replaced" ? "\u26A0\uFE0F Work stopped before the next review because the repository container was replaced and the run could not continue." : cause === "sandbox_fault" ? "\u26A0\uFE0F Work stopped before the next review because the sandbox failed and the run could not continue." : cause === "bot_restart" ? "\u26A0\uFE0F Work stopped before the next review because Switchboard restarted and the run could not continue." : "\u26A0\uFE0F Work stopped before the next review because the run could not continue.";
|
|
3741
|
+
const saved = prUrl3 ? `The existing pull request is ${prUrl3}; Switchboard did not verify the stopped run's latest commit there.` : "No open pull request was verified for the stopped run's latest commit.";
|
|
3742
|
+
const next = idle ? "The unit remains live; a reply in this thread is recorded as its continuation action." : "No review was started. Next action: start ship again after the remote branch and pull request state can be verified.";
|
|
3743
|
+
return `${opening} ${saved} ${next}`;
|
|
3718
3744
|
}
|
|
3719
3745
|
function planIdOf(planPath) {
|
|
3720
3746
|
const base = planPath.split("/").pop() ?? "";
|
|
@@ -4078,6 +4104,7 @@ function isHeadMaterial(event) {
|
|
|
4078
4104
|
case "context":
|
|
4079
4105
|
case "reference":
|
|
4080
4106
|
case "run_meta":
|
|
4107
|
+
case "run_state":
|
|
4081
4108
|
case "route":
|
|
4082
4109
|
return true;
|
|
4083
4110
|
case "run_note":
|
|
@@ -4847,7 +4874,7 @@ function analyzeRunFriction(events, opts = {}) {
|
|
|
4847
4874
|
return;
|
|
4848
4875
|
}
|
|
4849
4876
|
if (ev.type === "artifact" && ev.direction === "out") outboundArtifacts++;
|
|
4850
|
-
if (ev.type === "skill_use" || ev.type === "artifact" || ev.type === "review_artifact" || ev.type === "pr_description" || ev.type === "pr_opened" || ev.type === "coordinator_tag" || ev.type === "ship_handoff" || ev.type === "child_interrupted" || ev.type === "child_resumed" || ev.type === "review_posted" || ev.type === "ship_round" || ev.type === "ship_unit" || ev.type === "route" || ev.type === "operator" || ev.type === "refusal" || ev.type === "reference" || ev.type === "lease" || ev.type === "pushed_head") {
|
|
4877
|
+
if (ev.type === "skill_use" || ev.type === "artifact" || ev.type === "review_artifact" || ev.type === "pr_description" || ev.type === "pr_opened" || ev.type === "coordinator_tag" || ev.type === "ship_handoff" || ev.type === "child_interrupted" || ev.type === "child_resumed" || ev.type === "review_posted" || ev.type === "ship_round" || ev.type === "ship_unit" || ev.type === "route" || ev.type === "operator" || ev.type === "refusal" || ev.type === "reference" || ev.type === "run_state" || ev.type === "lease" || ev.type === "pushed_head") {
|
|
4851
4878
|
sideFactEvents++;
|
|
4852
4879
|
return;
|
|
4853
4880
|
}
|
|
@@ -4929,6 +4956,7 @@ function analyzeRunFriction(events, opts = {}) {
|
|
|
4929
4956
|
}
|
|
4930
4957
|
return;
|
|
4931
4958
|
}
|
|
4959
|
+
if (ev.type !== "run_note") return;
|
|
4932
4960
|
switch (ev.kind) {
|
|
4933
4961
|
case "wrap_up":
|
|
4934
4962
|
wrapUp = { index, at: ev.at };
|
|
@@ -5882,6 +5910,26 @@ var init_contract2 = __esm({
|
|
|
5882
5910
|
});
|
|
5883
5911
|
|
|
5884
5912
|
// ../../src/core/pipelineStanding.ts
|
|
5913
|
+
function hostedStageDetail(stage) {
|
|
5914
|
+
switch (stage) {
|
|
5915
|
+
case "coding":
|
|
5916
|
+
return "coding a unit";
|
|
5917
|
+
case "review":
|
|
5918
|
+
return "reviewing a unit";
|
|
5919
|
+
case "fix":
|
|
5920
|
+
return "fixing review findings";
|
|
5921
|
+
case "approved":
|
|
5922
|
+
return "waiting for checks and merge";
|
|
5923
|
+
case "merge-ready":
|
|
5924
|
+
return "ready for a person to merge";
|
|
5925
|
+
case "merged":
|
|
5926
|
+
return "a unit merged";
|
|
5927
|
+
case "idle":
|
|
5928
|
+
return "waiting for the next pipeline step";
|
|
5929
|
+
case "ended":
|
|
5930
|
+
return "finishing the pipeline";
|
|
5931
|
+
}
|
|
5932
|
+
}
|
|
5885
5933
|
function endingWordOf(kind) {
|
|
5886
5934
|
return ENDING_WORDS[kind] ?? kind;
|
|
5887
5935
|
}
|
|
@@ -6008,10 +6056,11 @@ function isPipelineSummaryShape(v) {
|
|
|
6008
6056
|
}
|
|
6009
6057
|
return true;
|
|
6010
6058
|
}
|
|
6011
|
-
var STAGES, OPEN_STAGES, ROUND_STAGE, ENDING_STAGE, ENDING_WORDS, ROUND_OUTCOME_WORDS, isFinite_;
|
|
6059
|
+
var HOSTED_PIPELINE_STARTING_DETAIL, STAGES, OPEN_STAGES, ROUND_STAGE, ENDING_STAGE, ENDING_WORDS, ROUND_OUTCOME_WORDS, isFinite_;
|
|
6012
6060
|
var init_pipelineStanding = __esm({
|
|
6013
6061
|
"../../src/core/pipelineStanding.ts"() {
|
|
6014
6062
|
"use strict";
|
|
6063
|
+
HOSTED_PIPELINE_STARTING_DETAIL = "pipeline starting";
|
|
6015
6064
|
STAGES = [
|
|
6016
6065
|
"coding",
|
|
6017
6066
|
"review",
|
|
@@ -6530,15 +6579,15 @@ function capEvent(event, maxBytes) {
|
|
|
6530
6579
|
}
|
|
6531
6580
|
return { event: capped4, bytes: size };
|
|
6532
6581
|
}
|
|
6533
|
-
function fitRecordToBudget(
|
|
6534
|
-
const cappedAll =
|
|
6535
|
-
const measure = (evs) => utf8ByteLength(JSON.stringify({ ...
|
|
6536
|
-
const whole = { ...
|
|
6582
|
+
function fitRecordToBudget(record3, maxBytes = MAX_RECORD_BYTES) {
|
|
6583
|
+
const cappedAll = record3.events.map((e) => capEvent(e, MAX_EVENT_BYTES));
|
|
6584
|
+
const measure = (evs) => utf8ByteLength(JSON.stringify({ ...record3, events: evs, storedEventCount: evs.length, truncated: true }));
|
|
6585
|
+
const whole = { ...record3, events: cappedAll.map((c) => c.event), storedEventCount: cappedAll.length };
|
|
6537
6586
|
if (utf8ByteLength(JSON.stringify(whole)) <= maxBytes) return whole;
|
|
6538
6587
|
const baseline = measure([]);
|
|
6539
6588
|
const capped4 = dropSpanPairsFromTheMiddle(cappedAll, maxBytes - baseline);
|
|
6540
6589
|
const events = capped4.map((c) => c.event);
|
|
6541
|
-
if (measure(events) <= maxBytes) return { ...
|
|
6590
|
+
if (measure(events) <= maxBytes) return { ...record3, events, storedEventCount: events.length, truncated: true };
|
|
6542
6591
|
const sizes = capped4.map((c) => c.bytes + 1);
|
|
6543
6592
|
let remaining = maxBytes - measure([]);
|
|
6544
6593
|
let head = 0;
|
|
@@ -6555,7 +6604,7 @@ function fitRecordToBudget(record2, maxBytes = MAX_RECORD_BYTES) {
|
|
|
6555
6604
|
while (kept.length > 0 && measure(kept) > maxBytes) {
|
|
6556
6605
|
kept.splice(Math.floor(kept.length / 2), 1);
|
|
6557
6606
|
}
|
|
6558
|
-
return { ...
|
|
6607
|
+
return { ...record3, events: kept, storedEventCount: kept.length, truncated: true };
|
|
6559
6608
|
}
|
|
6560
6609
|
function headLength(events) {
|
|
6561
6610
|
let n2 = 0;
|
|
@@ -6673,9 +6722,9 @@ function dominantFriction(byCategory) {
|
|
|
6673
6722
|
}
|
|
6674
6723
|
return best;
|
|
6675
6724
|
}
|
|
6676
|
-
function pointOf(
|
|
6677
|
-
if (
|
|
6678
|
-
const usage =
|
|
6725
|
+
function pointOf(record3, prices) {
|
|
6726
|
+
if (record3.provisional === true) return void 0;
|
|
6727
|
+
const usage = record3.usage ?? emptyUsage();
|
|
6679
6728
|
const priced = llmUsdOfUsage(usage, prices);
|
|
6680
6729
|
let inputTokens = 0;
|
|
6681
6730
|
let outputTokens = 0;
|
|
@@ -6687,27 +6736,27 @@ function pointOf(record2, prices) {
|
|
|
6687
6736
|
cacheReadTokens += m.cacheReadTokens;
|
|
6688
6737
|
cacheWriteTokens += m.cacheWriteTokens;
|
|
6689
6738
|
}
|
|
6690
|
-
const shape =
|
|
6739
|
+
const shape = record3.diagnosis.shape;
|
|
6691
6740
|
const blobs = {
|
|
6692
6741
|
schema: POINT_SCHEMA,
|
|
6693
|
-
agent:
|
|
6694
|
-
preset:
|
|
6695
|
-
model:
|
|
6696
|
-
status:
|
|
6697
|
-
"failure kind":
|
|
6698
|
-
"dominant friction": dominantFriction(
|
|
6699
|
-
channel:
|
|
6700
|
-
repository:
|
|
6701
|
-
"machine class":
|
|
6702
|
-
"route class":
|
|
6703
|
-
reply:
|
|
6704
|
-
lineage:
|
|
6705
|
-
requester:
|
|
6706
|
-
identity:
|
|
6707
|
-
"run id":
|
|
6742
|
+
agent: record3.agent ?? "",
|
|
6743
|
+
preset: record3.profile?.preset ?? "",
|
|
6744
|
+
model: record3.model ?? "",
|
|
6745
|
+
status: record3.status,
|
|
6746
|
+
"failure kind": record3.failure?.kind ?? "",
|
|
6747
|
+
"dominant friction": dominantFriction(record3.diagnosis.byCategory),
|
|
6748
|
+
channel: record3.channelId,
|
|
6749
|
+
repository: record3.repo ?? "",
|
|
6750
|
+
"machine class": record3.profile?.machine ?? "",
|
|
6751
|
+
"route class": record3.route !== void 0 ? "routed" : "chosen",
|
|
6752
|
+
reply: record3.replyOk === true ? "ok" : record3.replyOk === false ? "failed" : "none",
|
|
6753
|
+
lineage: record3.parentRunId !== void 0 ? "child" : "root",
|
|
6754
|
+
requester: record3.userId,
|
|
6755
|
+
identity: record3.profile?.identity ?? "",
|
|
6756
|
+
"run id": record3.id
|
|
6708
6757
|
};
|
|
6709
6758
|
const doubles = {
|
|
6710
|
-
wall:
|
|
6759
|
+
wall: record3.finishedAt - (record3.receivedAt ?? record3.startedAt),
|
|
6711
6760
|
"getting ready": shape?.gettingReadyMs ?? 0,
|
|
6712
6761
|
thinking: shape?.thinkingMs ?? 0,
|
|
6713
6762
|
tools: shape?.toolsMs ?? 0,
|
|
@@ -6721,15 +6770,15 @@ function pointOf(record2, prices) {
|
|
|
6721
6770
|
"cache read tokens": cacheReadTokens,
|
|
6722
6771
|
"cache write tokens": cacheWriteTokens,
|
|
6723
6772
|
dollars: priced.usd,
|
|
6724
|
-
steps:
|
|
6725
|
-
"tool calls": isFinite_2(
|
|
6726
|
-
events:
|
|
6773
|
+
steps: record3.stepCount ?? 0,
|
|
6774
|
+
"tool calls": isFinite_2(record3.diagnosis.toolCalls) ? record3.diagnosis.toolCalls : 0,
|
|
6775
|
+
events: record3.eventCount,
|
|
6727
6776
|
"unpriced tokens": priced.unpricedTokens,
|
|
6728
|
-
minutes:
|
|
6729
|
-
"finished at":
|
|
6777
|
+
minutes: record3.profile?.minutes ?? 0,
|
|
6778
|
+
"finished at": record3.finishedAt
|
|
6730
6779
|
};
|
|
6731
6780
|
return {
|
|
6732
|
-
indexes: [capBlob(
|
|
6781
|
+
indexes: [capBlob(record3.agent ?? UNKNOWN_AGENT)],
|
|
6733
6782
|
blobs: POINT_COLUMNS.blobs.map((n2) => capBlob(blobs[n2])),
|
|
6734
6783
|
doubles: POINT_COLUMNS.doubles.map((n2) => doubles[n2])
|
|
6735
6784
|
};
|
|
@@ -10367,12 +10416,8 @@ function containerApplicationName(script, className) {
|
|
|
10367
10416
|
return `${script}-${className.toLowerCase()}`;
|
|
10368
10417
|
}
|
|
10369
10418
|
function bindLiveGate(gate, script, healthUrl) {
|
|
10370
|
-
|
|
10371
|
-
|
|
10372
|
-
healthUrl,
|
|
10373
|
-
bearerEnv: gate.bearerEnv,
|
|
10374
|
-
containerApp: containerApplicationName(script, gate.containerClass)
|
|
10375
|
-
};
|
|
10419
|
+
const containerApp = containerApplicationName(script, gate.containerClass);
|
|
10420
|
+
return gate.kind === "bot" ? { kind: "bot", healthUrl, containerApp } : { kind: "sandbox", healthUrl, bearerEnv: gate.bearerEnv, containerApp };
|
|
10376
10421
|
}
|
|
10377
10422
|
function workersFor(profile) {
|
|
10378
10423
|
return WORKER_SPECS.flatMap(({ preflight, liveGate, ...spec }) => {
|
|
@@ -10387,8 +10432,8 @@ function workersFor(profile) {
|
|
|
10387
10432
|
script,
|
|
10388
10433
|
baseUrl,
|
|
10389
10434
|
healthUrl,
|
|
10390
|
-
//
|
|
10391
|
-
...preflight ? { preflight: liveGate?.kind === "
|
|
10435
|
+
// The bot preflight reads the same URL as its application + health live gate.
|
|
10436
|
+
...preflight ? { preflight: liveGate?.kind === "bot" ? { ...preflight, healthUrl } : preflight } : {},
|
|
10392
10437
|
...liveGate ? { liveGate: bindLiveGate(liveGate, script, healthUrl) } : {}
|
|
10393
10438
|
}
|
|
10394
10439
|
];
|
|
@@ -10499,7 +10544,7 @@ function formatPlan(plan3) {
|
|
|
10499
10544
|
plan3.steps.forEach((s, i) => {
|
|
10500
10545
|
const pf = s.retryOnPreflightRefusal ? ` \u2014 preflight (retry every ${plan3.pollMs / 1e3}s up to ${(s.waitMaxMs ?? plan3.waitMaxMs) / 6e4} min)` : s.forcedBy ? ` \u2014 preflight FORCED (${s.forcedBy}=1)` : "";
|
|
10501
10546
|
const env = s.requiredEnv.length > 0 ? ` \u2014 needs ${s.requiredEnv.map((r) => r.anyOf.length === 1 ? r.anyOf[0] : `one of ${r.anyOf.join(" / ")}`).join(", ")}` : "";
|
|
10502
|
-
const live = s.liveGate ? s.liveGate.kind === "
|
|
10547
|
+
const live = s.liveGate ? s.liveGate.kind === "bot" ? ` \u2014 then wait until live (${s.liveGate.containerApp} advances to the deployed image + ${s.liveGate.healthUrl} build.commit exactly == HEAD)` : ` \u2014 then wait until live (${s.liveGate.healthUrl} build.commit == HEAD + every running ${s.liveGate.containerApp} instance on the app version + an /exec probe answers ok from one)` : "";
|
|
10503
10548
|
const cap = s.capabilities.length > 0 ? ` \u2014 credential must pass ${s.capabilities.map((c) => `\`${c.command.join(" ")}\` (${c.needs})`).join(" and ")}` : "";
|
|
10504
10549
|
lines.push(
|
|
10505
10550
|
` ${i + 1}. ${s.name} (${s.script}) \u2014 ${s.dir}: ${s.command.join(" ")}${pf}${env}${cap}${live}
|
|
@@ -10570,7 +10615,7 @@ function classifyDeployOutput(exitCode, output) {
|
|
|
10570
10615
|
const firstError = lines.find((l) => isErrorish(l) && !/^npm ERR!/i.test(l)) ?? lines.find(isErrorish);
|
|
10571
10616
|
return { kind: "failed", reason: firstError ?? `exit ${exitCode}` };
|
|
10572
10617
|
}
|
|
10573
|
-
var UNSET_ENV, DEPLOY_FORCE_ENV, SANDBOX_CONTAINER_CLASS, SANDBOX_BEARER_ENV, R2_CAPABILITY, RESIDENT_BEARER_ENVS, RESIDENT_WAIT_MAX_MS, CONTAINERS_CAPABILITY, WORKER_DIRS, WORKER_SPECS, DEPLOY_ORDER, CONFIG_DOCUMENT_KEY, hasImage, ANSI_SEQUENCE;
|
|
10618
|
+
var UNSET_ENV, DEPLOY_FORCE_ENV, BOT_CONTAINER_CLASS, SANDBOX_CONTAINER_CLASS, SANDBOX_BEARER_ENV, R2_CAPABILITY, RESIDENT_BEARER_ENVS, RESIDENT_WAIT_MAX_MS, CONTAINERS_CAPABILITY, WORKER_DIRS, WORKER_SPECS, DEPLOY_ORDER, CONFIG_DOCUMENT_KEY, hasImage, ANSI_SEQUENCE;
|
|
10574
10619
|
var init_plan = __esm({
|
|
10575
10620
|
"../../src/deploy/plan.ts"() {
|
|
10576
10621
|
"use strict";
|
|
@@ -10582,6 +10627,7 @@ var init_plan = __esm({
|
|
|
10582
10627
|
init_profile2();
|
|
10583
10628
|
UNSET_ENV = ["CLOUDFLARE_ACCOUNT_ID"];
|
|
10584
10629
|
DEPLOY_FORCE_ENV = "SWITCHBOARD_DEPLOY_FORCE";
|
|
10630
|
+
BOT_CONTAINER_CLASS = "SwitchboardServer";
|
|
10585
10631
|
SANDBOX_CONTAINER_CLASS = "SwitchboardSandbox";
|
|
10586
10632
|
SANDBOX_BEARER_ENV = "SANDBOX_TOKEN";
|
|
10587
10633
|
R2_CAPABILITY = {
|
|
@@ -10642,10 +10688,10 @@ var init_plan = __esm({
|
|
|
10642
10688
|
]
|
|
10643
10689
|
},
|
|
10644
10690
|
preflight: { forceEnv: DEPLOY_FORCE_ENV, baseUrlEnv: "SWITCHBOARD_BASE_URL" },
|
|
10645
|
-
liveGate: { kind: "
|
|
10691
|
+
liveGate: { kind: "bot", containerClass: BOT_CONTAINER_CLASS },
|
|
10646
10692
|
// The preflight reads the container application and the deploy pushes the image: both need Containers.
|
|
10647
10693
|
capabilities: [CONTAINERS_CAPABILITY],
|
|
10648
|
-
why: "container shim \u2014 preflight refuses only over a rollout in progress (runs in flight hand off); done only when the
|
|
10694
|
+
why: "container shim \u2014 preflight refuses only over a rollout in progress (runs in flight hand off); done only when the application advances to the deployed image and /healthz serves the exact commit. A rotated bot secret needs no build: `wrangler secret put` alone leaves the running container on its old env \u2014 `deploy restart` restarts it on the current application target"
|
|
10649
10695
|
},
|
|
10650
10696
|
{
|
|
10651
10697
|
name: "resident",
|
|
@@ -11765,11 +11811,11 @@ var init_runStoreWorker = __esm({
|
|
|
11765
11811
|
fetchImpl;
|
|
11766
11812
|
abandoned() {
|
|
11767
11813
|
}
|
|
11768
|
-
async put(
|
|
11769
|
-
if (!RUN_ID_PATTERN.test(
|
|
11770
|
-
throw new PermanentStoreError(`run store: refusing to put malformed id ${JSON.stringify(
|
|
11771
|
-
const body = { storeKey: this.opts.storeKey, record:
|
|
11772
|
-
const point = pointOf(
|
|
11814
|
+
async put(record3, trace) {
|
|
11815
|
+
if (!RUN_ID_PATTERN.test(record3.id))
|
|
11816
|
+
throw new PermanentStoreError(`run store: refusing to put malformed id ${JSON.stringify(record3.id)}`);
|
|
11817
|
+
const body = { storeKey: this.opts.storeKey, record: record3 };
|
|
11818
|
+
const point = pointOf(record3, this.opts.prices);
|
|
11773
11819
|
if (point !== void 0) body.point = point;
|
|
11774
11820
|
if (this.opts.policy) {
|
|
11775
11821
|
body.policy = this.opts.policy;
|
|
@@ -11939,6 +11985,66 @@ var init_supersede = __esm({
|
|
|
11939
11985
|
}
|
|
11940
11986
|
});
|
|
11941
11987
|
|
|
11988
|
+
// ../../src/deploy/botLiveGate.ts
|
|
11989
|
+
function judge(input) {
|
|
11990
|
+
if ("error" in input.app)
|
|
11991
|
+
return waiting(`container application ${input.containerApp} unreadable: ${input.app.error}`);
|
|
11992
|
+
const app = input.app.value;
|
|
11993
|
+
let rollout;
|
|
11994
|
+
if (input.target) {
|
|
11995
|
+
if (input.target.image !== null && app.image !== input.target.image)
|
|
11996
|
+
return waiting(
|
|
11997
|
+
`container application ${input.containerApp} still targets ${app.image ?? "an unknown image"}; expected ${input.target.image}`
|
|
11998
|
+
);
|
|
11999
|
+
if ("error" in input.before)
|
|
12000
|
+
return waiting(
|
|
12001
|
+
`container application ${input.containerApp} pre-deploy version unreadable (${input.before.error}); cannot prove the application version advanced`
|
|
12002
|
+
);
|
|
12003
|
+
if (app.version <= input.before.value.version)
|
|
12004
|
+
return waiting(
|
|
12005
|
+
`container application ${input.containerApp} is still at pre-deploy version ${input.before.value.version}; expected a newer application version`
|
|
12006
|
+
);
|
|
12007
|
+
rollout = ` at version ${app.version} (up from ${input.before.value.version})`;
|
|
12008
|
+
} else {
|
|
12009
|
+
rollout = ` at version ${app.version} (Worker-only deploy; no application change printed)`;
|
|
12010
|
+
}
|
|
12011
|
+
if ("error" in input.health) return waiting(`health: GET /healthz failed: ${input.health.error}`);
|
|
12012
|
+
if (input.health.status !== 200)
|
|
12013
|
+
return waiting(
|
|
12014
|
+
`health: GET /healthz \u2192 HTTP ${input.health.status}; expected the deployed container's exact build identity`
|
|
12015
|
+
);
|
|
12016
|
+
if (!input.health.body || input.health.body.ok !== true)
|
|
12017
|
+
return waiting("health: /healthz is not ready or did not answer with JSON");
|
|
12018
|
+
const commit = servedCommit(input.health.body);
|
|
12019
|
+
if (!commit) return waiting("health: /healthz carries no build identity");
|
|
12020
|
+
if (commit !== input.expectedCommit)
|
|
12021
|
+
return waiting(`health: serving commit ${commit}, expected exact ${input.expectedCommit}`);
|
|
12022
|
+
if (input.health.body.draining === true)
|
|
12023
|
+
return waiting("health: the exact deployed commit answers but its container is draining");
|
|
12024
|
+
const target = input.target?.image ?? app.image ?? "an unchanged image";
|
|
12025
|
+
return {
|
|
12026
|
+
kind: "live",
|
|
12027
|
+
summary: `container application ${input.containerApp} targets ${target}${rollout}; /healthz serves exact ${commit}`
|
|
12028
|
+
};
|
|
12029
|
+
}
|
|
12030
|
+
function decideBotLive(input, deadlineMs = LIVE_GATE_DEADLINE_MS) {
|
|
12031
|
+
const decision = judge(input);
|
|
12032
|
+
if (decision.kind !== "waiting" || input.elapsedMs < deadlineMs) return decision;
|
|
12033
|
+
return {
|
|
12034
|
+
kind: "failed",
|
|
12035
|
+
reason: `${decision.reason} \u2014 still not live after ${Math.round(input.elapsedMs / MINUTE_MS)} min (deadline ${deadlineMs / MINUTE_MS} min)`
|
|
12036
|
+
};
|
|
12037
|
+
}
|
|
12038
|
+
var waiting;
|
|
12039
|
+
var init_botLiveGate = __esm({
|
|
12040
|
+
"../../src/deploy/botLiveGate.ts"() {
|
|
12041
|
+
"use strict";
|
|
12042
|
+
init_budgets();
|
|
12043
|
+
init_liveGate();
|
|
12044
|
+
waiting = (reason2) => ({ kind: "waiting", reason: reason2 });
|
|
12045
|
+
}
|
|
12046
|
+
});
|
|
12047
|
+
|
|
11942
12048
|
// ../../src/execution/sandboxErrors.ts
|
|
11943
12049
|
function fleetBusyRunEndedLine(run2, thread, err2) {
|
|
11944
12050
|
if (typeof err2 !== "object" || err2 === null) return null;
|
|
@@ -12025,51 +12131,51 @@ function rolloutAdvanced(app, before, target) {
|
|
|
12025
12131
|
reason: `rollout: pre-deploy version unreadable (${before.error}); application image ${app.image === null ? "?" : shortImage(app.image)} is not the deploy's ${shortImage(target.image)}`
|
|
12026
12132
|
};
|
|
12027
12133
|
}
|
|
12028
|
-
function
|
|
12134
|
+
function judge2(input) {
|
|
12029
12135
|
const worker = decideWorker(input.health, input.deployedCommit);
|
|
12030
|
-
if (!worker.ok) return worker.fatal ? { kind: "failed", reason: worker.reason } :
|
|
12031
|
-
if (input.app === null) return
|
|
12032
|
-
if ("error" in input.app) return
|
|
12136
|
+
if (!worker.ok) return worker.fatal ? { kind: "failed", reason: worker.reason } : waiting2(worker.reason);
|
|
12137
|
+
if (input.app === null) return waiting2("rollout: not read yet");
|
|
12138
|
+
if ("error" in input.app) return waiting2(`rollout: ${input.app.error}`);
|
|
12033
12139
|
const app = input.app.value;
|
|
12034
12140
|
const appVersion = app.version;
|
|
12035
12141
|
let advancedFrom = null;
|
|
12036
12142
|
if (input.target) {
|
|
12037
12143
|
const advanced = rolloutAdvanced(app, input.before, input.target);
|
|
12038
|
-
if (!advanced.ok) return
|
|
12144
|
+
if (!advanced.ok) return waiting2(advanced.reason);
|
|
12039
12145
|
advancedFrom = advanced.from;
|
|
12040
12146
|
}
|
|
12041
|
-
if (input.instances === null) return
|
|
12042
|
-
if ("error" in input.instances) return
|
|
12147
|
+
if (input.instances === null) return waiting2("rollout: instances not read yet");
|
|
12148
|
+
if ("error" in input.instances) return waiting2(`rollout: ${input.instances.error}`);
|
|
12043
12149
|
const running = input.instances.value.filter((i) => i.state === "running");
|
|
12044
12150
|
const rolloutSummary = advancedFrom === null ? `Worker-only deploy \u2014 no container change (${running.length} running instance(s) on version ${appVersion})` : `rollout complete (${running.length} running instance(s) on version ${appVersion}, ${advancedFrom})`;
|
|
12045
12151
|
const stale = running.filter((i) => i.version !== appVersion);
|
|
12046
12152
|
if (stale.length > 0) {
|
|
12047
12153
|
const versions = [...new Set(stale.map((i) => i.version === null ? "?" : String(i.version)))].join("/");
|
|
12048
|
-
return
|
|
12154
|
+
return waiting2(
|
|
12049
12155
|
`rollout in progress \u2014 ${stale.length} of ${running.length} running instance(s) still on version ${versions}, app version ${appVersion}`
|
|
12050
12156
|
);
|
|
12051
12157
|
}
|
|
12052
|
-
if (input.probe === null) return
|
|
12053
|
-
if ("error" in input.probe) return
|
|
12158
|
+
if (input.probe === null) return waiting2("probe: not sent yet");
|
|
12159
|
+
if ("error" in input.probe) return waiting2(`probe: ${input.probe.error}`);
|
|
12054
12160
|
const body = input.probe.body;
|
|
12055
12161
|
if (body.reason === FLEET_BUSY_REASON)
|
|
12056
|
-
return
|
|
12162
|
+
return waiting2("probe: fleet busy \u2014 no free instance for the probe thread (max_instances reached)");
|
|
12057
12163
|
if (typeof body.error === "string" && CONTAINER_STARTING.test(body.error))
|
|
12058
|
-
return
|
|
12164
|
+
return waiting2("probe: container starting");
|
|
12059
12165
|
if ("error" in body) {
|
|
12060
12166
|
const failed = body.error === "" ? "/exec failed with an EMPTY error" : `/exec failed \u2014 ${typeof body.error === "string" ? body.error : JSON.stringify(body.error)}`;
|
|
12061
|
-
return
|
|
12167
|
+
return waiting2(`probe: ${failed} \u2014 the probe's container may still run the previous image`);
|
|
12062
12168
|
}
|
|
12063
12169
|
if (body.exitCode !== 0) {
|
|
12064
12170
|
const stderr = typeof body.stderr === "string" ? body.stderr.trim() : "";
|
|
12065
|
-
return
|
|
12171
|
+
return waiting2(`probe: \`${PROBE_COMMAND}\` exited ${String(body.exitCode)}${stderr ? `: ${stderr}` : ""}`);
|
|
12066
12172
|
}
|
|
12067
12173
|
const stdout = typeof body.stdout === "string" ? body.stdout.trim() : "";
|
|
12068
|
-
if (stdout !== "ok") return
|
|
12174
|
+
if (stdout !== "ok") return waiting2(`probe: \`${PROBE_COMMAND}\` printed ${JSON.stringify(stdout)}`);
|
|
12069
12175
|
const mine = input.instances.value.find((i) => i.name === input.probeThreadKey);
|
|
12070
|
-
if (!mine) return
|
|
12176
|
+
if (!mine) return waiting2(`probe instance ${input.probeThreadKey} not listed yet`);
|
|
12071
12177
|
if (mine.version !== appVersion)
|
|
12072
|
-
return
|
|
12178
|
+
return waiting2(
|
|
12073
12179
|
`probe instance ${input.probeThreadKey} is on version ${mine.version === null ? "?" : mine.version}, app version ${appVersion} \u2014 the probe landed on a previous image`
|
|
12074
12180
|
);
|
|
12075
12181
|
return {
|
|
@@ -12078,7 +12184,7 @@ function judge(input) {
|
|
|
12078
12184
|
};
|
|
12079
12185
|
}
|
|
12080
12186
|
function decideSandboxLive(input, deadlineMs = LIVE_GATE_DEADLINE_MS) {
|
|
12081
|
-
const d =
|
|
12187
|
+
const d = judge2(input);
|
|
12082
12188
|
if (d.kind !== "waiting" || input.elapsedMs < deadlineMs) return d;
|
|
12083
12189
|
return {
|
|
12084
12190
|
kind: "failed",
|
|
@@ -12152,7 +12258,7 @@ function parseExecStream(text) {
|
|
|
12152
12258
|
return { error: `/exec answered no JSON document: ${JSON.stringify(text.trim().slice(0, 120))}` };
|
|
12153
12259
|
}
|
|
12154
12260
|
}
|
|
12155
|
-
var PROBE_COMMAND, PROBE_TIMEOUT_MS, CONTAINER_STARTING,
|
|
12261
|
+
var PROBE_COMMAND, PROBE_TIMEOUT_MS, CONTAINER_STARTING, waiting2, isRecord2, ANSI_SEQUENCE2, SECTION_GUTTER;
|
|
12156
12262
|
var init_sandboxLiveGate = __esm({
|
|
12157
12263
|
"../../src/deploy/sandboxLiveGate.ts"() {
|
|
12158
12264
|
"use strict";
|
|
@@ -12161,7 +12267,7 @@ var init_sandboxLiveGate = __esm({
|
|
|
12161
12267
|
PROBE_COMMAND = "echo ok";
|
|
12162
12268
|
PROBE_TIMEOUT_MS = 6e4;
|
|
12163
12269
|
CONTAINER_STARTING = /Container is starting/i;
|
|
12164
|
-
|
|
12270
|
+
waiting2 = (reason2) => ({ kind: "waiting", reason: reason2 });
|
|
12165
12271
|
isRecord2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
12166
12272
|
ANSI_SEQUENCE2 = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
|
|
12167
12273
|
SECTION_GUTTER = /^[\s│├╭╰|]+/;
|
|
@@ -12487,26 +12593,6 @@ async function fetchHealthz(url) {
|
|
|
12487
12593
|
const r = await readHealthz(url);
|
|
12488
12594
|
return "body" in r ? r.body : void 0;
|
|
12489
12595
|
}
|
|
12490
|
-
async function waitUntilLive(step, healthUrl, expectedCommit, io, clock4, previousStartedAt) {
|
|
12491
|
-
const started = clock4();
|
|
12492
|
-
for (; ; ) {
|
|
12493
|
-
const elapsed2 = clock4() - started;
|
|
12494
|
-
const body = await fetchHealthz(healthUrl);
|
|
12495
|
-
const d = decideLive(body, expectedCommit, elapsed2, LIVE_GATE_DEADLINE_MS, {
|
|
12496
|
-
...previousStartedAt !== void 0 ? { previousStartedAt } : {}
|
|
12497
|
-
});
|
|
12498
|
-
if (d.kind === "live") return { live: true, detail: `commit ${d.commit.slice(0, 7)}`, waitedMs: elapsed2 };
|
|
12499
|
-
if (d.kind === "timeout")
|
|
12500
|
-
return {
|
|
12501
|
-
live: false,
|
|
12502
|
-
reason: `${d.reason} \u2014 gave up after ${Math.round(elapsed2 / 6e4)} min (drain deadline ${LIVE_GATE_DEADLINE_MS / 6e4} min)`
|
|
12503
|
-
};
|
|
12504
|
-
io.log(
|
|
12505
|
-
`[deploy:all] ${step.name}: deployed, not live yet \u2014 ${d.reason} (${Math.floor(elapsed2 / 6e4)}m ${Math.floor(elapsed2 % 6e4 / 1e3)}s)`
|
|
12506
|
-
);
|
|
12507
|
-
await sleep(LIVE_GATE_POLL_MS);
|
|
12508
|
-
}
|
|
12509
|
-
}
|
|
12510
12596
|
async function wranglerJson(dir, args) {
|
|
12511
12597
|
const r = await run("npx", ["wrangler", ...args], { cwd: workerDir(dir), unset: UNSET_ENV });
|
|
12512
12598
|
if (r.code !== 0)
|
|
@@ -12527,6 +12613,29 @@ async function resolveContainerAppId(dir, containerApp) {
|
|
|
12527
12613
|
containerAppIds.set(containerApp, id);
|
|
12528
12614
|
return { value: id };
|
|
12529
12615
|
}
|
|
12616
|
+
async function waitUntilBotLive(step, gate, expectedCommit, rollout, io, deps = defaultSandboxGateDeps) {
|
|
12617
|
+
const started = deps.now();
|
|
12618
|
+
for (; ; ) {
|
|
12619
|
+
const elapsed2 = deps.now() - started;
|
|
12620
|
+
const app = await deps.readAppState(step.dir, gate.containerApp);
|
|
12621
|
+
const health = await deps.readHealth(gate.healthUrl);
|
|
12622
|
+
const decision = decideBotLive({
|
|
12623
|
+
containerApp: gate.containerApp,
|
|
12624
|
+
health,
|
|
12625
|
+
app,
|
|
12626
|
+
before: rollout.before,
|
|
12627
|
+
target: rollout.target,
|
|
12628
|
+
expectedCommit,
|
|
12629
|
+
elapsedMs: elapsed2
|
|
12630
|
+
});
|
|
12631
|
+
if (decision.kind === "live") return { live: true, detail: decision.summary, waitedMs: deps.now() - started };
|
|
12632
|
+
if (decision.kind === "failed") return { live: false, reason: decision.reason };
|
|
12633
|
+
io.log(
|
|
12634
|
+
`[deploy:all] ${step.name}: deployed, not live yet \u2014 ${decision.reason} (${Math.floor(elapsed2 / 6e4)}m ${Math.floor(elapsed2 % 6e4 / 1e3)}s)`
|
|
12635
|
+
);
|
|
12636
|
+
await deps.sleep(LIVE_GATE_POLL_MS);
|
|
12637
|
+
}
|
|
12638
|
+
}
|
|
12530
12639
|
async function waitUntilSandboxLive(step, gate, expectedCommit, rollout, io, deps = defaultSandboxGateDeps) {
|
|
12531
12640
|
const bearer = deps.env[gate.bearerEnv];
|
|
12532
12641
|
if (!bearer)
|
|
@@ -12567,7 +12676,7 @@ async function waitUntilSandboxLive(step, gate, expectedCommit, rollout, io, dep
|
|
|
12567
12676
|
async function readAppBeforeUpload(step, gate, io, deps) {
|
|
12568
12677
|
const before = await deps.readAppState(step.dir, gate.containerApp);
|
|
12569
12678
|
io.log(
|
|
12570
|
-
"value" in before ? `[deploy:all] ${step.name}: container application at version ${before.value.version}${before.value.image ? ` (image ${shortImage(before.value.image)})` : ""} before the upload` : `[deploy:all] ${step.name}: could not read the container application before the upload \u2014 ${before.error}; the gate will need the deploy's image to show`
|
|
12679
|
+
"value" in before ? `[deploy:all] ${step.name}: container application at version ${before.value.version}${before.value.image ? ` (image ${shortImage(before.value.image)})` : ""} before the upload` : gate.kind === "sandbox" ? `[deploy:all] ${step.name}: could not read the container application before the upload \u2014 ${before.error}; the gate will need the deploy's image to show` : `[deploy:all] ${step.name}: could not read the container application before the upload \u2014 ${before.error}; the gate requires a readable pre-deploy version to prove advancement`
|
|
12571
12680
|
);
|
|
12572
12681
|
return before;
|
|
12573
12682
|
}
|
|
@@ -12643,8 +12752,7 @@ async function deployStepLoop(step, plan3, expectedCommit, io, deps, exec, root,
|
|
|
12643
12752
|
for (; ; ) {
|
|
12644
12753
|
io.log(`
|
|
12645
12754
|
[deploy:all] \u25B6 ${step.name} (${step.script}) \u2014 ${step.dir}: ${step.command.join(" ")}`);
|
|
12646
|
-
const
|
|
12647
|
-
const previousStartedAt = step.liveGate && step.liveGate.kind !== "sandbox" ? await fetchHealthz(step.liveGate.healthUrl).then((b) => b ? servedStartedAt(b) : void 0) : void 0;
|
|
12755
|
+
const application = step.liveGate ? { before: await readAppBeforeUpload(step, step.liveGate, io, deps) } : void 0;
|
|
12648
12756
|
const r = await exec(step, io);
|
|
12649
12757
|
const outcome = classifyDeployOutput(r.code, r.output);
|
|
12650
12758
|
if (outcome.kind === "deployed") {
|
|
@@ -12657,15 +12765,20 @@ async function deployStepLoop(step, plan3, expectedCommit, io, deps, exec, root,
|
|
|
12657
12765
|
);
|
|
12658
12766
|
const liveGate = step.liveGate;
|
|
12659
12767
|
const gate = await root.span("deploy.wait_live", async (wait2) => {
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12768
|
+
if (!application) throw new Error(`${step.name}: live gate has no application state`);
|
|
12769
|
+
const target = rolloutTargetFromDeployOutput(r.output);
|
|
12770
|
+
const from = "value" in application.before ? `version ${application.before.value.version}` : "its pre-deploy version";
|
|
12771
|
+
io.log(
|
|
12772
|
+
target ? `[deploy:all] ${step.name}: wrangler printed a container change \u2014 ${target.image ? `image ${shortImage(target.image)}` : "configuration only, image unchanged"}; the application must leave ${from}` : `[deploy:all] ${step.name}: wrangler printed no container change \u2014 Worker-only deploy, no rollout expected`
|
|
12773
|
+
);
|
|
12774
|
+
const g = liveGate.kind === "sandbox" ? await waitUntilSandboxLive(
|
|
12775
|
+
step,
|
|
12776
|
+
liveGate,
|
|
12777
|
+
expectedCommit,
|
|
12778
|
+
{ before: application.before, target },
|
|
12779
|
+
io,
|
|
12780
|
+
deps
|
|
12781
|
+
) : await waitUntilBotLive(step, liveGate, expectedCommit, { before: application.before, target }, io, deps);
|
|
12669
12782
|
wait2.setAttrs(g.live ? { outcome: "live", waitedMs: g.waitedMs } : { outcome: "not_live" });
|
|
12670
12783
|
return g;
|
|
12671
12784
|
});
|
|
@@ -13082,6 +13195,7 @@ var init_run = __esm({
|
|
|
13082
13195
|
init_planeDeploy();
|
|
13083
13196
|
init_wranglerTemplate();
|
|
13084
13197
|
init_supersede();
|
|
13198
|
+
init_botLiveGate();
|
|
13085
13199
|
init_sandboxLiveGate();
|
|
13086
13200
|
sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
13087
13201
|
workerDir = (dir) => workPath(OPERATOR_ROOT, dir);
|
|
@@ -16134,6 +16248,7 @@ var init_resident = __esm({
|
|
|
16134
16248
|
* here: its `runtime-replaced` is the typed restart (`opWithReattach`). */
|
|
16135
16249
|
runtimeReplacedStreak = 0;
|
|
16136
16250
|
lastBinding;
|
|
16251
|
+
attachAttempt = 0;
|
|
16137
16252
|
/** The thread's binding as the resident answered it on the most recent
|
|
16138
16253
|
* successful attach — including a mid-run re-attach after an eviction, which
|
|
16139
16254
|
* may land on a newer sha than the one the run started on. Undefined until
|
|
@@ -16300,6 +16415,7 @@ var init_resident = __esm({
|
|
|
16300
16415
|
* an operation's wall clock is the command's, and a recovery attach is not
|
|
16301
16416
|
* the command. */
|
|
16302
16417
|
async attach(span, opts = {}) {
|
|
16418
|
+
this.attachAttempt++;
|
|
16303
16419
|
const answer = await this.attachOnce(span, this.attachBoundMs("/attach"), opts.signal);
|
|
16304
16420
|
if (answer.ok) return answer.binding;
|
|
16305
16421
|
if (isDrainingRefusal(answer)) {
|
|
@@ -16348,14 +16464,16 @@ var init_resident = __esm({
|
|
|
16348
16464
|
t0 + (left === void 0 ? DRAIN_WAIT_MAX_MS : Math.max(0, left - DRAIN_LEASE_RESERVE_MS))
|
|
16349
16465
|
);
|
|
16350
16466
|
let answer = first;
|
|
16351
|
-
|
|
16352
|
-
|
|
16353
|
-
|
|
16467
|
+
await this.opts.onLiveStateObservation?.({
|
|
16468
|
+
state: "waiting_deploy",
|
|
16469
|
+
bound: deadline,
|
|
16470
|
+
reason: "deploy",
|
|
16471
|
+
attempt: this.attachAttempt
|
|
16472
|
+
});
|
|
16354
16473
|
const waitSpan = span?.start("dispatch.workspace.attach.drain-wait");
|
|
16355
16474
|
try {
|
|
16356
16475
|
for (; ; ) {
|
|
16357
16476
|
const now = systemClock();
|
|
16358
|
-
note(now);
|
|
16359
16477
|
if (now >= deadline)
|
|
16360
16478
|
throw new ResidentDrainingError(this.opts.resource, now - t0, drainingUntil(answer), refusalWords(answer));
|
|
16361
16479
|
await wakePause(Math.min(DRAIN_POLL_MS, deadline - now), opts.signal, "/attach");
|
|
@@ -16393,7 +16511,6 @@ var init_resident = __esm({
|
|
|
16393
16511
|
}
|
|
16394
16512
|
throw err2;
|
|
16395
16513
|
} finally {
|
|
16396
|
-
this.opts.onSetupNote?.(void 0);
|
|
16397
16514
|
}
|
|
16398
16515
|
}
|
|
16399
16516
|
/** One `/attach`, answered rather than thrown: the binding on a 200, else
|
|
@@ -16700,6 +16817,13 @@ var init_resident = __esm({
|
|
|
16700
16817
|
}
|
|
16701
16818
|
};
|
|
16702
16819
|
const t0 = systemClock();
|
|
16820
|
+
const wakeBound = t0 + wakeWaitBudget(opts.budgetMs);
|
|
16821
|
+
await this.opts.onLiveStateObservation?.({
|
|
16822
|
+
state: "waiting_repository",
|
|
16823
|
+
bound: wakeBound,
|
|
16824
|
+
reason: "repository_container",
|
|
16825
|
+
attempt: this.attachAttempt
|
|
16826
|
+
});
|
|
16703
16827
|
let transient = opts.origin === "transient-refusal";
|
|
16704
16828
|
const definite = (why) => residentWakeStrike(route2, refusal, why, "refused", opts.origin);
|
|
16705
16829
|
const decide = (view) => transient && isUnansweredProbe(view) ? {
|
|
@@ -17331,7 +17455,7 @@ async function branchHeadSubject(repo, branch2) {
|
|
|
17331
17455
|
if (typeof message4 !== "string" || message4.trim() === "") return void 0;
|
|
17332
17456
|
return message4.split("\n", 1)[0].trim();
|
|
17333
17457
|
}
|
|
17334
|
-
async function
|
|
17458
|
+
async function readHeadRef(repo, branch2, headers) {
|
|
17335
17459
|
let res;
|
|
17336
17460
|
try {
|
|
17337
17461
|
res = await fetch(`https://api.github.com/repos/${repo}/git/ref/heads/${encodeGithubRef(branch2)}`, {
|
|
@@ -17339,13 +17463,17 @@ async function headRefTipSha(repo, branch2, headers) {
|
|
|
17339
17463
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
17340
17464
|
});
|
|
17341
17465
|
} catch {
|
|
17342
|
-
return
|
|
17466
|
+
return { kind: "unverified" };
|
|
17343
17467
|
}
|
|
17344
|
-
if (
|
|
17468
|
+
if (res.status === 404) return { kind: "missing" };
|
|
17469
|
+
if (!res.ok) return { kind: "unverified" };
|
|
17345
17470
|
const data = await res.json().catch(() => null);
|
|
17346
|
-
|
|
17347
|
-
|
|
17348
|
-
|
|
17471
|
+
const sha = data?.object?.sha;
|
|
17472
|
+
return data?.object?.type === "commit" && typeof sha === "string" && /^[0-9a-f]{40}$/.test(sha) ? { kind: "verified", sha } : { kind: "unverified" };
|
|
17473
|
+
}
|
|
17474
|
+
async function headRefTipSha(repo, branch2, headers) {
|
|
17475
|
+
const read = await readHeadRef(repo, branch2, headers);
|
|
17476
|
+
return read.kind === "verified" ? read.sha : void 0;
|
|
17349
17477
|
}
|
|
17350
17478
|
function preferRefTip(where, prSha, refTip, branch2) {
|
|
17351
17479
|
if (refTip === void 0) return prSha;
|
|
@@ -17395,8 +17523,11 @@ async function fetchPullRequestFacts(pr) {
|
|
|
17395
17523
|
const prSha = typeof data.head?.sha === "string" && /^[0-9a-f]{40}$/.test(data.head.sha) ? data.head.sha : void 0;
|
|
17396
17524
|
const sameRepoHead = headRepo === pr.repo.toLowerCase();
|
|
17397
17525
|
const headRef = typeof data.head?.ref === "string" && data.head.ref ? data.head.ref : void 0;
|
|
17398
|
-
const
|
|
17399
|
-
const
|
|
17526
|
+
const headRead = sameRepoHead && headRef !== void 0 ? await readHeadRef(pr.repo, headRef, headers) : void 0;
|
|
17527
|
+
const headBranchExists = headRead?.kind === "verified" ? true : headRead?.kind === "missing" ? false : void 0;
|
|
17528
|
+
const refTip = headRead?.kind === "verified" ? headRead.sha : void 0;
|
|
17529
|
+
const sha = sameRepoHead && headRef !== void 0 ? preferRefTip(`${pr.repo}#${pr.number}`, prSha, refTip, headRef) : prSha;
|
|
17530
|
+
const verifiedHead = sameRepoHead && headRef !== void 0 && prSha !== void 0 && refTip === prSha ? { repo: pr.repo, ref: headRef, sha: refTip } : void 0;
|
|
17400
17531
|
let closedBy = typeof data.closed_by?.login === "string" ? data.closed_by.login : void 0;
|
|
17401
17532
|
if (data.state === "closed" && !(typeof data.merged_at === "string" && data.merged_at) && closedBy === void 0) {
|
|
17402
17533
|
try {
|
|
@@ -17421,6 +17552,7 @@ async function fetchPullRequestFacts(pr) {
|
|
|
17421
17552
|
} : {},
|
|
17422
17553
|
...headRef !== void 0 ? { headRef } : {},
|
|
17423
17554
|
...sha ? { headSha: sha } : {},
|
|
17555
|
+
...verifiedHead !== void 0 ? { verifiedHead } : {},
|
|
17424
17556
|
...headBranchExists !== void 0 ? { headBranchExists } : {},
|
|
17425
17557
|
sameRepoHead,
|
|
17426
17558
|
...typeof data.base?.ref === "string" && data.base.ref ? { baseRef: data.base.ref } : {},
|
|
@@ -18413,7 +18545,7 @@ async function makeExecutor(opts, ctx, span) {
|
|
|
18413
18545
|
resolveEnvs: () => gitIdentityEnvs(ctx.profile.identity, authorSourceOf(opts, ctx)),
|
|
18414
18546
|
...ctx.ownPr !== void 0 ? { ownPr: ctx.ownPr } : {},
|
|
18415
18547
|
...ctx.remainingMs !== void 0 ? { remainingMs: ctx.remainingMs } : {},
|
|
18416
|
-
...ctx.
|
|
18548
|
+
...ctx.onLiveStateObservation !== void 0 ? { onLiveStateObservation: ctx.onLiveStateObservation } : {}
|
|
18417
18549
|
},
|
|
18418
18550
|
nonWarm,
|
|
18419
18551
|
span,
|
|
@@ -18595,7 +18727,7 @@ async function reattachWorkspace(opts, ctx, recorded, span) {
|
|
|
18595
18727
|
// resident holds its own credential, so the pairs alone ride.
|
|
18596
18728
|
resolveEnvs: () => gitIdentityEnvs(ctx.profile.identity, authorSourceOf(opts, ctx)),
|
|
18597
18729
|
...ctx.remainingMs !== void 0 ? { remainingMs: ctx.remainingMs } : {},
|
|
18598
|
-
...ctx.
|
|
18730
|
+
...ctx.onLiveStateObservation !== void 0 ? { onLiveStateObservation: ctx.onLiveStateObservation } : {}
|
|
18599
18731
|
});
|
|
18600
18732
|
let binding;
|
|
18601
18733
|
try {
|
|
@@ -21048,8 +21180,8 @@ function pageEvents(events, opts) {
|
|
|
21048
21180
|
if (page2.length < rest.length && page2.length > 0) out.nextAfterSeq = page2[page2.length - 1].seq;
|
|
21049
21181
|
return out;
|
|
21050
21182
|
}
|
|
21051
|
-
function toListItem(
|
|
21052
|
-
const { events: _events, ...rest } =
|
|
21183
|
+
function toListItem(record3, bytes) {
|
|
21184
|
+
const { events: _events, ...rest } = record3;
|
|
21053
21185
|
return { ...rest, bytes };
|
|
21054
21186
|
}
|
|
21055
21187
|
function retentionPolicyOf(cfg) {
|
|
@@ -21200,19 +21332,19 @@ var init_runStore = __esm({
|
|
|
21200
21332
|
}
|
|
21201
21333
|
abandoned() {
|
|
21202
21334
|
}
|
|
21203
|
-
async put(
|
|
21204
|
-
if (!isValidRunId(
|
|
21335
|
+
async put(record3) {
|
|
21336
|
+
if (!isValidRunId(record3.id))
|
|
21205
21337
|
return { ok: true, retained: this.readIndex().length, stored: false, rewritten: false };
|
|
21206
21338
|
this.ensureDir();
|
|
21207
|
-
const content = JSON.stringify(
|
|
21339
|
+
const content = JSON.stringify(record3);
|
|
21208
21340
|
const bytes = utf8ByteLength(content);
|
|
21209
21341
|
const index = this.readIndex();
|
|
21210
|
-
const prev = index.find((r) => r.id ===
|
|
21211
|
-
const rewritten = prev !== void 0 && !sameStoredVersion(prev, { ...
|
|
21212
|
-
this.writeAtomic(this.recordPath(
|
|
21213
|
-
const item = toListItem(
|
|
21214
|
-
const kept = this.compact([...index.filter((r) => r.id !==
|
|
21215
|
-
return { ok: true, retained: kept.length, stored: kept.some((r) => r.id ===
|
|
21342
|
+
const prev = index.find((r) => r.id === record3.id);
|
|
21343
|
+
const rewritten = prev !== void 0 && !sameStoredVersion(prev, { ...record3, bytes });
|
|
21344
|
+
this.writeAtomic(this.recordPath(record3.id), content);
|
|
21345
|
+
const item = toListItem(record3, bytes);
|
|
21346
|
+
const kept = this.compact([...index.filter((r) => r.id !== record3.id), item]);
|
|
21347
|
+
return { ok: true, retained: kept.length, stored: kept.some((r) => r.id === record3.id), rewritten };
|
|
21216
21348
|
}
|
|
21217
21349
|
/** Retention is decided from the index alone (no per-file stat); the one
|
|
21218
21350
|
* file that matters is then read directly — a torn or missing file lands
|
|
@@ -21239,16 +21371,16 @@ var init_runStore = __esm({
|
|
|
21239
21371
|
return selectListItems(this.retainedIntact(), opts);
|
|
21240
21372
|
}
|
|
21241
21373
|
async events(id, opts) {
|
|
21242
|
-
const
|
|
21243
|
-
return
|
|
21374
|
+
const record3 = await this.get(id);
|
|
21375
|
+
return record3 ? pageEvents(record3.events, opts) : null;
|
|
21244
21376
|
}
|
|
21245
21377
|
async usage(query) {
|
|
21246
21378
|
const items = this.retainedIntact();
|
|
21247
21379
|
const records = [];
|
|
21248
21380
|
for (const item of items) {
|
|
21249
21381
|
if (item.finishedAt < query.sinceMs || item.finishedAt >= query.untilMs) continue;
|
|
21250
|
-
const
|
|
21251
|
-
if (
|
|
21382
|
+
const record3 = await this.get(item.id);
|
|
21383
|
+
if (record3) records.push(record3);
|
|
21252
21384
|
}
|
|
21253
21385
|
const parent = (id) => {
|
|
21254
21386
|
const p = items.find((i) => i.id === id);
|
|
@@ -21966,24 +22098,24 @@ function predicateWith(rules, actor, action, resourceType, kind) {
|
|
|
21966
22098
|
function predicateFor(actor, action, resourceType, kind) {
|
|
21967
22099
|
return predicateWith(POLICY, actor, action, resourceType, kind);
|
|
21968
22100
|
}
|
|
21969
|
-
function matchesPredicate(predicate,
|
|
22101
|
+
function matchesPredicate(predicate, record3) {
|
|
21970
22102
|
switch (predicate.kind) {
|
|
21971
22103
|
case "none":
|
|
21972
22104
|
return false;
|
|
21973
22105
|
case "all":
|
|
21974
22106
|
return true;
|
|
21975
22107
|
case "channels-in":
|
|
21976
|
-
return
|
|
22108
|
+
return record3.channelId !== void 0 && holds(predicate.channelIds, record3.channelId);
|
|
21977
22109
|
case "user-is":
|
|
21978
|
-
return
|
|
22110
|
+
return record3.userId !== void 0 && record3.userId === predicate.userId;
|
|
21979
22111
|
case "repos-in":
|
|
21980
|
-
return
|
|
22112
|
+
return record3.repo !== void 0 && holds(predicate.repos, record3.repo);
|
|
21981
22113
|
case "visibility-in":
|
|
21982
|
-
return predicate.visibilities.has(
|
|
22114
|
+
return predicate.visibilities.has(record3.channelVisibility ?? "unknown");
|
|
21983
22115
|
case "or":
|
|
21984
|
-
return predicate.of.some((p) => matchesPredicate(p,
|
|
22116
|
+
return predicate.of.some((p) => matchesPredicate(p, record3));
|
|
21985
22117
|
case "and":
|
|
21986
|
-
return predicate.of.length > 0 && predicate.of.every((p) => matchesPredicate(p,
|
|
22118
|
+
return predicate.of.length > 0 && predicate.of.every((p) => matchesPredicate(p, record3));
|
|
21987
22119
|
}
|
|
21988
22120
|
return false;
|
|
21989
22121
|
}
|
|
@@ -25400,6 +25532,199 @@ var init_frictionProposals = __esm({
|
|
|
25400
25532
|
}
|
|
25401
25533
|
});
|
|
25402
25534
|
|
|
25535
|
+
// ../../src/core/runLiveState.ts
|
|
25536
|
+
function safeLiveStateDetail(detail) {
|
|
25537
|
+
if (detail === void 0) return void 0;
|
|
25538
|
+
const line4 = oneLine(detail);
|
|
25539
|
+
if (line4 === "" || UNSAFE_DETAIL.test(line4)) return void 0;
|
|
25540
|
+
return redactAndCap(line4, LIVE_STATE_DETAIL_MAX - 1);
|
|
25541
|
+
}
|
|
25542
|
+
function assignRunLiveState(current, currentSeq, input) {
|
|
25543
|
+
if (input.expectedSeq !== currentSeq) return { ok: false, reason: "stale-sequence" };
|
|
25544
|
+
if (current === void 0 && input.state !== "admitted") return { ok: false, reason: "invalid-transition" };
|
|
25545
|
+
if (current?.state === "ended") return { ok: false, reason: "terminal" };
|
|
25546
|
+
if (input.state !== "ended") {
|
|
25547
|
+
if (input.bound === void 0) return { ok: false, reason: "bound-required" };
|
|
25548
|
+
if (!Number.isFinite(input.bound) || input.bound < input.at) return { ok: false, reason: "invalid-bound" };
|
|
25549
|
+
} else if (input.cause === void 0) return { ok: false, reason: "cause-required" };
|
|
25550
|
+
if (current !== void 0 && current.state !== input.state && !TRANSITIONS[current.state].includes(input.state))
|
|
25551
|
+
return { ok: false, reason: "invalid-transition" };
|
|
25552
|
+
const detail = safeLiveStateDetail(input.detail);
|
|
25553
|
+
const liveState = {
|
|
25554
|
+
state: input.state,
|
|
25555
|
+
since: current?.state === input.state ? current.since : input.at,
|
|
25556
|
+
...input.state !== "ended" ? { bound: input.bound } : {},
|
|
25557
|
+
...detail !== void 0 ? { detail } : {}
|
|
25558
|
+
};
|
|
25559
|
+
if (current?.state === input.state) return { ok: true, liveState };
|
|
25560
|
+
return {
|
|
25561
|
+
ok: true,
|
|
25562
|
+
liveState,
|
|
25563
|
+
event: {
|
|
25564
|
+
type: "run_state",
|
|
25565
|
+
...liveState,
|
|
25566
|
+
...input.state === "ended" ? { cause: input.cause } : {},
|
|
25567
|
+
at: input.at
|
|
25568
|
+
}
|
|
25569
|
+
};
|
|
25570
|
+
}
|
|
25571
|
+
function foldRunLiveState(events, materialized = {}) {
|
|
25572
|
+
let liveState = materialized.liveState;
|
|
25573
|
+
let liveStateSeq = materialized.liveStateSeq ?? 0;
|
|
25574
|
+
let leaseEndsAt;
|
|
25575
|
+
for (const event of [...events].sort((left, right) => (left.seq ?? 0) - (right.seq ?? 0))) {
|
|
25576
|
+
if (event.type === "lease" && event.endsAt !== void 0) leaseEndsAt = event.endsAt;
|
|
25577
|
+
const seq = event.seq ?? 0;
|
|
25578
|
+
if (seq <= liveStateSeq) continue;
|
|
25579
|
+
if (event.type === "run_state" && RUN_LIVE_STATE_NAMES.includes(event.state) && event.since !== void 0) {
|
|
25580
|
+
liveState = {
|
|
25581
|
+
state: event.state,
|
|
25582
|
+
since: event.since,
|
|
25583
|
+
...event.bound !== void 0 ? { bound: event.bound } : {},
|
|
25584
|
+
...event.detail !== void 0 ? { detail: event.detail } : {}
|
|
25585
|
+
};
|
|
25586
|
+
liveStateSeq = seq;
|
|
25587
|
+
continue;
|
|
25588
|
+
}
|
|
25589
|
+
if (event.type === "tool_call" && liveState?.state === "working" && event.at !== void 0 && event.boundMs !== void 0) {
|
|
25590
|
+
liveState = { ...liveState, bound: event.at + event.boundMs, detail: "running a tool" };
|
|
25591
|
+
liveStateSeq = seq;
|
|
25592
|
+
continue;
|
|
25593
|
+
}
|
|
25594
|
+
if (event.type === "tool_result" && liveState?.state === "working" && leaseEndsAt !== void 0) {
|
|
25595
|
+
liveState = { ...liveState, bound: leaseEndsAt, detail: "model turn" };
|
|
25596
|
+
liveStateSeq = seq;
|
|
25597
|
+
}
|
|
25598
|
+
}
|
|
25599
|
+
return {
|
|
25600
|
+
...liveState !== void 0 ? { liveState } : {},
|
|
25601
|
+
...liveStateSeq > 0 ? { liveStateSeq } : {}
|
|
25602
|
+
};
|
|
25603
|
+
}
|
|
25604
|
+
var RUN_LIVE_STATE_NAMES, LIVE_STATE_DETAIL_MAX, TRANSITIONS, UNSAFE_DETAIL;
|
|
25605
|
+
var init_runLiveState = __esm({
|
|
25606
|
+
"../../src/core/runLiveState.ts"() {
|
|
25607
|
+
"use strict";
|
|
25608
|
+
init_redact();
|
|
25609
|
+
RUN_LIVE_STATE_NAMES = [
|
|
25610
|
+
"admitted",
|
|
25611
|
+
"waiting_deploy",
|
|
25612
|
+
"waiting_repository",
|
|
25613
|
+
"falling_back",
|
|
25614
|
+
"preparing",
|
|
25615
|
+
"working",
|
|
25616
|
+
"waiting_provider",
|
|
25617
|
+
"wrapping_up",
|
|
25618
|
+
"ended"
|
|
25619
|
+
];
|
|
25620
|
+
LIVE_STATE_DETAIL_MAX = 160;
|
|
25621
|
+
TRANSITIONS = {
|
|
25622
|
+
admitted: ["waiting_deploy", "waiting_repository", "falling_back", "preparing", "working", "wrapping_up", "ended"],
|
|
25623
|
+
waiting_deploy: ["waiting_repository", "falling_back", "preparing", "working", "wrapping_up", "ended"],
|
|
25624
|
+
waiting_repository: ["waiting_deploy", "falling_back", "preparing", "working", "wrapping_up", "ended"],
|
|
25625
|
+
falling_back: ["preparing", "working", "wrapping_up", "ended"],
|
|
25626
|
+
preparing: ["waiting_deploy", "waiting_repository", "falling_back", "working", "wrapping_up", "ended"],
|
|
25627
|
+
working: [
|
|
25628
|
+
"waiting_deploy",
|
|
25629
|
+
"waiting_repository",
|
|
25630
|
+
"falling_back",
|
|
25631
|
+
"preparing",
|
|
25632
|
+
"waiting_provider",
|
|
25633
|
+
"wrapping_up",
|
|
25634
|
+
"ended"
|
|
25635
|
+
],
|
|
25636
|
+
waiting_provider: ["working", "wrapping_up", "ended"],
|
|
25637
|
+
wrapping_up: ["ended"],
|
|
25638
|
+
ended: []
|
|
25639
|
+
};
|
|
25640
|
+
UNSAFE_DETAIL = /(?:\bimage-stale\b|\battach-failed\b|\bparked-provider\b|<\/?(?:html|body|head)\b|\bbad gateway\b)/i;
|
|
25641
|
+
}
|
|
25642
|
+
});
|
|
25643
|
+
|
|
25644
|
+
// ../../src/core/plane/decide.ts
|
|
25645
|
+
function liveStateWords(state) {
|
|
25646
|
+
switch (state) {
|
|
25647
|
+
case "admitted":
|
|
25648
|
+
return "admitted";
|
|
25649
|
+
case "waiting_deploy":
|
|
25650
|
+
return "waiting for the current deploy";
|
|
25651
|
+
case "waiting_repository":
|
|
25652
|
+
return "waiting for the repository container";
|
|
25653
|
+
case "falling_back":
|
|
25654
|
+
return "switching to a fallback workspace";
|
|
25655
|
+
case "preparing":
|
|
25656
|
+
return "preparing the workspace";
|
|
25657
|
+
case "working":
|
|
25658
|
+
return "working";
|
|
25659
|
+
case "waiting_provider":
|
|
25660
|
+
return "waiting for the model provider";
|
|
25661
|
+
case "wrapping_up":
|
|
25662
|
+
return "wrapping up";
|
|
25663
|
+
case "ended":
|
|
25664
|
+
return "ended";
|
|
25665
|
+
}
|
|
25666
|
+
}
|
|
25667
|
+
function causeOfClose(status3, restarting) {
|
|
25668
|
+
switch (status3) {
|
|
25669
|
+
case "completed":
|
|
25670
|
+
return "completed";
|
|
25671
|
+
case "failed":
|
|
25672
|
+
return "failed";
|
|
25673
|
+
case "stopped_soft":
|
|
25674
|
+
case "stopped_hard":
|
|
25675
|
+
case "stopped":
|
|
25676
|
+
return "stopped";
|
|
25677
|
+
default:
|
|
25678
|
+
return restarting === true ? "resident_replaced" : "lease_lapsed";
|
|
25679
|
+
}
|
|
25680
|
+
}
|
|
25681
|
+
function endingCauseWords(cause) {
|
|
25682
|
+
switch (cause) {
|
|
25683
|
+
case "completed":
|
|
25684
|
+
return "it completed";
|
|
25685
|
+
case "failed":
|
|
25686
|
+
return "it failed";
|
|
25687
|
+
case "stopped":
|
|
25688
|
+
return "it was stopped";
|
|
25689
|
+
case "withdrawn":
|
|
25690
|
+
return "its wait was withdrawn";
|
|
25691
|
+
case "refused":
|
|
25692
|
+
return "its admission was refused";
|
|
25693
|
+
case "lease_lapsed":
|
|
25694
|
+
return "its lease lapsed with no heartbeat";
|
|
25695
|
+
case "resident_replaced":
|
|
25696
|
+
return "the resident container running it was replaced";
|
|
25697
|
+
case "runner_gone":
|
|
25698
|
+
return "the runner instance driving it is gone";
|
|
25699
|
+
}
|
|
25700
|
+
}
|
|
25701
|
+
function isReissueSteerText(text) {
|
|
25702
|
+
return /^the model provider .+ is answering again — re-issue the held turn and continue$/.test(text.trim());
|
|
25703
|
+
}
|
|
25704
|
+
function waitingWords(waiting3) {
|
|
25705
|
+
if (waiting3.length === 0) return "its turn";
|
|
25706
|
+
return waiting3.map(
|
|
25707
|
+
(c) => c.kind === "thread_free" ? "the thread's live run" : c.kind === "deploy_settled" ? "the pending deploy" : c.kind === "seat" ? `a seat on ${c.resident}` : c.kind === "memory" ? `memory on ${c.resident}` : c.kind === "provider_up" ? `the ${c.provider} provider` : `the ${c.window} window`
|
|
25708
|
+
).join(", then ");
|
|
25709
|
+
}
|
|
25710
|
+
var PLANE_ENDING_CAUSES;
|
|
25711
|
+
var init_decide = __esm({
|
|
25712
|
+
"../../src/core/plane/decide.ts"() {
|
|
25713
|
+
"use strict";
|
|
25714
|
+
init_budgets();
|
|
25715
|
+
PLANE_ENDING_CAUSES = [
|
|
25716
|
+
"completed",
|
|
25717
|
+
"failed",
|
|
25718
|
+
"stopped",
|
|
25719
|
+
"withdrawn",
|
|
25720
|
+
"refused",
|
|
25721
|
+
"lease_lapsed",
|
|
25722
|
+
"resident_replaced",
|
|
25723
|
+
"runner_gone"
|
|
25724
|
+
];
|
|
25725
|
+
}
|
|
25726
|
+
});
|
|
25727
|
+
|
|
25403
25728
|
// ../../src/core/runEventLines.ts
|
|
25404
25729
|
function parseRunEventLines(text) {
|
|
25405
25730
|
const events = [];
|
|
@@ -25465,6 +25790,8 @@ function isRunEvent(v) {
|
|
|
25465
25790
|
return typeof o.url === "string" && typeof o.number === "number" && typeof o.created === "boolean";
|
|
25466
25791
|
case "pushed_head":
|
|
25467
25792
|
return typeof o.ref === "string" && typeof o.sha === "string" && (o.by === "push" || o.by === "salvage");
|
|
25793
|
+
case "run_state":
|
|
25794
|
+
return typeof o.state === "string" && LIVE_STATES.has(o.state) && typeof o.since === "number" && (o.state === "ended" ? typeof o.cause === "string" && ENDING_CAUSES.has(o.cause) : typeof o.bound === "number");
|
|
25468
25795
|
case "review_posted":
|
|
25469
25796
|
return typeof o.repo === "string" && typeof o.number === "number" && typeof o.head === "string";
|
|
25470
25797
|
case "ship_round":
|
|
@@ -25487,12 +25814,16 @@ function isRunEvent(v) {
|
|
|
25487
25814
|
return false;
|
|
25488
25815
|
}
|
|
25489
25816
|
}
|
|
25490
|
-
var NOTE_KINDS;
|
|
25817
|
+
var NOTE_KINDS, LIVE_STATES, ENDING_CAUSES;
|
|
25491
25818
|
var init_runEventLines = __esm({
|
|
25492
25819
|
"../../src/core/runEventLines.ts"() {
|
|
25493
25820
|
"use strict";
|
|
25494
25821
|
init_runEvents();
|
|
25822
|
+
init_runLiveState();
|
|
25823
|
+
init_decide();
|
|
25495
25824
|
NOTE_KINDS = new Set(RUN_NOTE_KINDS);
|
|
25825
|
+
LIVE_STATES = new Set(RUN_LIVE_STATE_NAMES);
|
|
25826
|
+
ENDING_CAUSES = new Set(PLANE_ENDING_CAUSES);
|
|
25496
25827
|
}
|
|
25497
25828
|
});
|
|
25498
25829
|
|
|
@@ -28644,23 +28975,23 @@ var init_turnEffort = __esm({
|
|
|
28644
28975
|
function tokenize2(text) {
|
|
28645
28976
|
return text.toLowerCase().match(/[a-z0-9]+/g) ?? [];
|
|
28646
28977
|
}
|
|
28647
|
-
function keywordMatch(
|
|
28978
|
+
function keywordMatch(record3, query) {
|
|
28648
28979
|
const queryTokens = typeof query === "string" ? tokenize2(query) : query;
|
|
28649
28980
|
if (queryTokens.length === 0) return 0;
|
|
28650
|
-
const recordTokens = /* @__PURE__ */ new Set([...tokenize2(
|
|
28981
|
+
const recordTokens = /* @__PURE__ */ new Set([...tokenize2(record3.keywords.join(" ")), ...tokenize2(record3.text)]);
|
|
28651
28982
|
let hits = 0;
|
|
28652
28983
|
for (const token2 of queryTokens) {
|
|
28653
28984
|
if (recordTokens.has(token2)) hits++;
|
|
28654
28985
|
}
|
|
28655
28986
|
return hits / queryTokens.length;
|
|
28656
28987
|
}
|
|
28657
|
-
function recencyScore(
|
|
28658
|
-
const ts =
|
|
28988
|
+
function recencyScore(record3, now, tau = RECENCY_TAU_MS) {
|
|
28989
|
+
const ts = record3.lastUsedAt ?? record3.createdAt;
|
|
28659
28990
|
const age = Math.max(0, now - ts);
|
|
28660
28991
|
return Math.exp(-age / tau);
|
|
28661
28992
|
}
|
|
28662
|
-
function scoreRecord(
|
|
28663
|
-
return weights.keyword * keywordMatch(
|
|
28993
|
+
function scoreRecord(record3, query, now, weights = DEFAULT_WEIGHTS, tau = RECENCY_TAU_MS) {
|
|
28994
|
+
return weights.keyword * keywordMatch(record3, query) + weights.recency * recencyScore(record3, now, tau);
|
|
28664
28995
|
}
|
|
28665
28996
|
function estimateTokens(text) {
|
|
28666
28997
|
return Math.ceil(text.length / 4);
|
|
@@ -28668,11 +28999,11 @@ function estimateTokens(text) {
|
|
|
28668
28999
|
function applyBudget(records, budget) {
|
|
28669
29000
|
const out = [];
|
|
28670
29001
|
let tokens = 0;
|
|
28671
|
-
for (const
|
|
29002
|
+
for (const record3 of records) {
|
|
28672
29003
|
if (out.length >= budget.maxRecords) break;
|
|
28673
|
-
const cost = estimateTokens(renderMemoryBullet(
|
|
29004
|
+
const cost = estimateTokens(renderMemoryBullet(record3));
|
|
28674
29005
|
if (out.length > 0 && tokens + cost > budget.maxTokens) break;
|
|
28675
|
-
out.push(
|
|
29006
|
+
out.push(record3);
|
|
28676
29007
|
tokens += cost;
|
|
28677
29008
|
}
|
|
28678
29009
|
return out;
|
|
@@ -28683,8 +29014,8 @@ function memoryBlockPrefix(resource) {
|
|
|
28683
29014
|
function sanitizeMemoryField(s) {
|
|
28684
29015
|
return s.replace(/[\x00-\x1f\x7f-\x9f\u2028\u2029]/g, " ").replace(/\s+/g, " ").trim().replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
28685
29016
|
}
|
|
28686
|
-
function renderMemoryBullet(
|
|
28687
|
-
return `- ${sanitizeMemoryField(
|
|
29017
|
+
function renderMemoryBullet(record3) {
|
|
29018
|
+
return `- ${sanitizeMemoryField(record3.text)} (source: ${sanitizeMemoryField(record3.sourceThreadKey)})`;
|
|
28688
29019
|
}
|
|
28689
29020
|
function renderMemoryBlock(resource, records) {
|
|
28690
29021
|
const bullets = records.map(renderMemoryBullet);
|
|
@@ -29270,7 +29601,7 @@ function parseConfirmation(v) {
|
|
|
29270
29601
|
function isRefusal(v) {
|
|
29271
29602
|
return typeof v === "string" && CONFIRMATION_REFUSALS.includes(v);
|
|
29272
29603
|
}
|
|
29273
|
-
function
|
|
29604
|
+
function judge3(rows, id, actorIds, now, kind) {
|
|
29274
29605
|
const row2 = rows.get(id);
|
|
29275
29606
|
if (!row2) return { ok: false, refused: "used" };
|
|
29276
29607
|
if (kind === "consume" && row2.expiresAt <= now) {
|
|
@@ -29340,13 +29671,13 @@ var init_confirmations = __esm({
|
|
|
29340
29671
|
}
|
|
29341
29672
|
async consume(id, actorIds) {
|
|
29342
29673
|
const rows = this.read();
|
|
29343
|
-
const out =
|
|
29674
|
+
const out = judge3(rows, id, actorIds, this.clock(), "consume");
|
|
29344
29675
|
this.write(rows);
|
|
29345
29676
|
return out;
|
|
29346
29677
|
}
|
|
29347
29678
|
async cancel(id, actorIds) {
|
|
29348
29679
|
const rows = this.read();
|
|
29349
|
-
const out =
|
|
29680
|
+
const out = judge3(rows, id, actorIds, this.clock(), "cancel");
|
|
29350
29681
|
this.write(rows);
|
|
29351
29682
|
return out;
|
|
29352
29683
|
}
|
|
@@ -29354,7 +29685,7 @@ var init_confirmations = __esm({
|
|
|
29354
29685
|
const rows = this.read();
|
|
29355
29686
|
const id = threadRowId(rows, threadKey);
|
|
29356
29687
|
if (id === void 0) return { ok: false, refused: "used" };
|
|
29357
|
-
const out =
|
|
29688
|
+
const out = judge3(rows, id, actorIds, this.clock(), "cancel");
|
|
29358
29689
|
this.write(rows);
|
|
29359
29690
|
return out;
|
|
29360
29691
|
}
|
|
@@ -29835,16 +30166,16 @@ async function reflect(deps) {
|
|
|
29835
30166
|
dropped.push(`${placement.from} (${placement.reason})`);
|
|
29836
30167
|
continue;
|
|
29837
30168
|
}
|
|
29838
|
-
let
|
|
30169
|
+
let record3 = plain7;
|
|
29839
30170
|
if (placement.narrowed) {
|
|
29840
|
-
const { supersedes: _supersedes, restates: _restates, ...withoutPointers } =
|
|
29841
|
-
|
|
30171
|
+
const { supersedes: _supersedes, restates: _restates, ...withoutPointers } = record3;
|
|
30172
|
+
record3 = withoutPointers;
|
|
29842
30173
|
const line4 = `${placement.narrowed.from} \u2192 ${placement.target.kind} (${placement.narrowed.reason})`;
|
|
29843
30174
|
narrowed.set(line4, (narrowed.get(line4) ?? 0) + 1);
|
|
29844
30175
|
}
|
|
29845
30176
|
let batch = byScope.get(placement.target.key);
|
|
29846
30177
|
if (!batch) byScope.set(placement.target.key, batch = []);
|
|
29847
|
-
batch.push(
|
|
30178
|
+
batch.push(record3);
|
|
29848
30179
|
}
|
|
29849
30180
|
if (narrowed.size > 0)
|
|
29850
30181
|
warn(`write narrowed by policy: ${[...narrowed].map(([line4, n2]) => `${n2}\xD7 ${line4}`).join(", ")}`);
|
|
@@ -31675,8 +32006,8 @@ ${line4}`
|
|
|
31675
32006
|
const list = await call(() => api.residents());
|
|
31676
32007
|
if (list.status !== 200) throw residentFailure(list);
|
|
31677
32008
|
const residents = list.data.residents ?? [];
|
|
31678
|
-
const
|
|
31679
|
-
if (!
|
|
32009
|
+
const record3 = residents.find((rec2) => rec2.resource === repoResourceId(args.slug));
|
|
32010
|
+
if (!record3) {
|
|
31680
32011
|
const slugs = residents.map(
|
|
31681
32012
|
(rec2) => String(rec2.resource ?? "").replace(/^repo:/, "").toLowerCase()
|
|
31682
32013
|
).filter(Boolean);
|
|
@@ -31696,7 +32027,7 @@ ${line4}`
|
|
|
31696
32027
|
${line4}` : ""}`
|
|
31697
32028
|
);
|
|
31698
32029
|
}
|
|
31699
|
-
body.commands = { ...obj(
|
|
32030
|
+
body.commands = { ...obj(record3.commands), ...commands };
|
|
31700
32031
|
}
|
|
31701
32032
|
if (options.ref !== void 0) body.defaultRef = options.ref;
|
|
31702
32033
|
const r = await call(() => api.reconfigure(body));
|
|
@@ -31721,11 +32052,11 @@ ${line4}` : ""}`
|
|
|
31721
32052
|
|
|
31722
32053
|
// ../../src/core/reviewAbridge.ts
|
|
31723
32054
|
import { resolve as resolve10 } from "node:path";
|
|
31724
|
-
function meatArtifactOf(
|
|
31725
|
-
return
|
|
32055
|
+
function meatArtifactOf(record3) {
|
|
32056
|
+
return record3.events.find((e) => isReadingDiff(e) && e.poweredBy === "meat");
|
|
31726
32057
|
}
|
|
31727
|
-
function gitArtifactOf(
|
|
31728
|
-
return
|
|
32058
|
+
function gitArtifactOf(record3) {
|
|
32059
|
+
return record3.events.find((e) => isReadingDiff(e) && e.poweredBy === "git");
|
|
31729
32060
|
}
|
|
31730
32061
|
function summarize(a) {
|
|
31731
32062
|
return {
|
|
@@ -31739,16 +32070,16 @@ function summarize(a) {
|
|
|
31739
32070
|
};
|
|
31740
32071
|
}
|
|
31741
32072
|
async function appendReviewArtifact(store, runId3, artifact, at) {
|
|
31742
|
-
const
|
|
31743
|
-
if (!
|
|
31744
|
-
const kept =
|
|
31745
|
-
const replaced = kept.length !==
|
|
31746
|
-
const seq = Math.max(0, ...storedEventSeqs(
|
|
32073
|
+
const record3 = await store.get(runId3);
|
|
32074
|
+
if (!record3) throw new Error("the run's record is gone \u2014 nothing to append to");
|
|
32075
|
+
const kept = record3.events.filter((e) => !(isReadingDiff(e) && e.poweredBy === "meat"));
|
|
32076
|
+
const replaced = kept.length !== record3.events.length;
|
|
32077
|
+
const seq = Math.max(0, ...storedEventSeqs(record3.events), ...record3.events.map((e) => e.seq ?? 0)) + 1;
|
|
31747
32078
|
const event = { type: "review_artifact", artifact: "reading_diff", ...artifact, at, seq };
|
|
31748
32079
|
const next = fitRecordToBudget({
|
|
31749
|
-
...
|
|
32080
|
+
...record3,
|
|
31750
32081
|
events: [...kept, event],
|
|
31751
|
-
eventCount:
|
|
32082
|
+
eventCount: record3.eventCount + (replaced ? 0 : 1),
|
|
31752
32083
|
storedEventCount: kept.length + 1
|
|
31753
32084
|
});
|
|
31754
32085
|
if (!next.events.includes(event))
|
|
@@ -31837,19 +32168,19 @@ var init_reviewAbridge = __esm({
|
|
|
31837
32168
|
async decide(req) {
|
|
31838
32169
|
const job = this.jobs.get(req.runId);
|
|
31839
32170
|
if (job) return { state: "running", startedAt: job.startedAt };
|
|
31840
|
-
const
|
|
31841
|
-
if (!
|
|
31842
|
-
const existing = meatArtifactOf(
|
|
32171
|
+
const record3 = await this.deps.store.get(req.runId);
|
|
32172
|
+
if (!record3) throw new AbridgeRefusal("not_found", "run not found");
|
|
32173
|
+
const existing = meatArtifactOf(record3);
|
|
31843
32174
|
if (existing && !req.force) return { state: "done", reused: true, artifact: summarize(existing) };
|
|
31844
32175
|
const failed = this.failures.get(req.runId);
|
|
31845
32176
|
if (failed && !req.force) return { state: "failed", ...failed };
|
|
31846
|
-
const git2 = gitArtifactOf(
|
|
32177
|
+
const git2 = gitArtifactOf(record3);
|
|
31847
32178
|
if (!git2)
|
|
31848
32179
|
throw new AbridgeRefusal("conflict", `run ${req.runId} carries no reading diff \u2014 only PR review runs record one`);
|
|
31849
32180
|
const startedAt = this.deps.clock();
|
|
31850
32181
|
const model = req.model ?? this.deps.defaultModel();
|
|
31851
32182
|
this.failures.delete(req.runId);
|
|
31852
|
-
const done = this.produce(
|
|
32183
|
+
const done = this.produce(record3, git2, model).finally(() => this.jobs.delete(req.runId));
|
|
31853
32184
|
this.jobs.set(req.runId, { startedAt, done });
|
|
31854
32185
|
return { state: "running", startedAt };
|
|
31855
32186
|
}
|
|
@@ -31859,8 +32190,8 @@ var init_reviewAbridge = __esm({
|
|
|
31859
32190
|
if (job) return { state: "running", startedAt: job.startedAt };
|
|
31860
32191
|
const failed = this.failures.get(runId3);
|
|
31861
32192
|
if (failed) return { state: "failed", ...failed };
|
|
31862
|
-
const
|
|
31863
|
-
const existing =
|
|
32193
|
+
const record3 = await this.deps.store.get(runId3);
|
|
32194
|
+
const existing = record3 ? meatArtifactOf(record3) : void 0;
|
|
31864
32195
|
return existing ? { state: "done", reused: true, artifact: summarize(existing) } : { state: "absent" };
|
|
31865
32196
|
}
|
|
31866
32197
|
/** The running job's final state, or the current state when none runs. */
|
|
@@ -31891,10 +32222,10 @@ var init_reviewAbridge = __esm({
|
|
|
31891
32222
|
if (!(err2 instanceof AbridgeRefusal)) this.deps.warn(`[reading-diff] ${runId3} abridge failed: ${describe(err2)}`);
|
|
31892
32223
|
}
|
|
31893
32224
|
}
|
|
31894
|
-
async produce(
|
|
32225
|
+
async produce(record3, git2, model) {
|
|
31895
32226
|
const at = () => this.deps.clock();
|
|
31896
32227
|
try {
|
|
31897
|
-
const input = await this.input(
|
|
32228
|
+
const input = await this.input(record3, git2);
|
|
31898
32229
|
const meat = await this.deps.meat({ diff: input.diff, model, timeoutMs: this.deps.timeoutMs() });
|
|
31899
32230
|
if (!meat.ok) throw new Error(meat.reason);
|
|
31900
32231
|
const capped4 = capDiff(sanitizeArtifactText(meat.result.diff));
|
|
@@ -31910,12 +32241,12 @@ var init_reviewAbridge = __esm({
|
|
|
31910
32241
|
inputBytes: input.bytes,
|
|
31911
32242
|
model
|
|
31912
32243
|
};
|
|
31913
|
-
const stored = await appendReviewArtifact(this.deps.store,
|
|
31914
|
-
return this.conclude(
|
|
32244
|
+
const stored = await appendReviewArtifact(this.deps.store, record3.id, artifact, at());
|
|
32245
|
+
return this.conclude(record3.id, { state: "done", reused: false, artifact: summarize(stored) });
|
|
31915
32246
|
} catch (err2) {
|
|
31916
32247
|
const failed = { reason: redactSecrets(describe(err2)), at: at() };
|
|
31917
|
-
this.failures.set(
|
|
31918
|
-
return this.conclude(
|
|
32248
|
+
this.failures.set(record3.id, failed);
|
|
32249
|
+
return this.conclude(record3.id, { state: "failed", ...failed });
|
|
31919
32250
|
}
|
|
31920
32251
|
}
|
|
31921
32252
|
conclude(runId3, state) {
|
|
@@ -31924,8 +32255,8 @@ var init_reviewAbridge = __esm({
|
|
|
31924
32255
|
}
|
|
31925
32256
|
/** The complete diff: GitHub's compare of base...head first; the recorded
|
|
31926
32257
|
* git diff only when that fails AND it is whole. */
|
|
31927
|
-
async input(
|
|
31928
|
-
const meta =
|
|
32258
|
+
async input(record3, git2) {
|
|
32259
|
+
const meta = record3.events.find((e) => e.type === "run_meta");
|
|
31929
32260
|
let compareFailure;
|
|
31930
32261
|
if (!meta?.repo || !meta.headSha) compareFailure = "the run records no repo and head to compare";
|
|
31931
32262
|
else {
|
|
@@ -31944,7 +32275,7 @@ var init_reviewAbridge = __esm({
|
|
|
31944
32275
|
}
|
|
31945
32276
|
}
|
|
31946
32277
|
if (git2.truncated) throw new Error(`diff unavailable: ${compareFailure} and the recorded diff is truncated`);
|
|
31947
|
-
this.deps.warn(`[reading-diff] ${
|
|
32278
|
+
this.deps.warn(`[reading-diff] ${record3.id} using the recorded diff: ${compareFailure}`);
|
|
31948
32279
|
return { diff: git2.diff, source: "recorded", bytes: Buffer.byteLength(git2.diff) };
|
|
31949
32280
|
}
|
|
31950
32281
|
};
|
|
@@ -32237,6 +32568,8 @@ function assembleRunRecord(input) {
|
|
|
32237
32568
|
...seal?.replyNote !== void 0 ? { replyNote: seal.replyNote } : {},
|
|
32238
32569
|
...snap !== null ? { stepCount: snap.stepCount } : {},
|
|
32239
32570
|
status: input.status,
|
|
32571
|
+
...snap?.liveState !== void 0 ? { liveState: snap.liveState } : {},
|
|
32572
|
+
...snap?.liveStateSeq !== void 0 ? { liveStateSeq: snap.liveStateSeq } : {},
|
|
32240
32573
|
eventCount: Math.max(snap?.eventCount ?? atFinish.length, seal?.eventCount ?? 0),
|
|
32241
32574
|
storedEventCount: events.length,
|
|
32242
32575
|
truncated: false,
|
|
@@ -32420,43 +32753,6 @@ var init_record = __esm({
|
|
|
32420
32753
|
}
|
|
32421
32754
|
});
|
|
32422
32755
|
|
|
32423
|
-
// ../../src/core/plane/decide.ts
|
|
32424
|
-
function endingCauseWords(cause) {
|
|
32425
|
-
switch (cause) {
|
|
32426
|
-
case "completed":
|
|
32427
|
-
return "it completed";
|
|
32428
|
-
case "failed":
|
|
32429
|
-
return "it failed";
|
|
32430
|
-
case "stopped":
|
|
32431
|
-
return "it was stopped";
|
|
32432
|
-
case "withdrawn":
|
|
32433
|
-
return "its wait was withdrawn";
|
|
32434
|
-
case "refused":
|
|
32435
|
-
return "its admission was refused";
|
|
32436
|
-
case "lease_lapsed":
|
|
32437
|
-
return "its lease lapsed with no heartbeat";
|
|
32438
|
-
case "resident_replaced":
|
|
32439
|
-
return "the resident container running it was replaced";
|
|
32440
|
-
case "runner_gone":
|
|
32441
|
-
return "the runner instance driving it is gone";
|
|
32442
|
-
}
|
|
32443
|
-
}
|
|
32444
|
-
function isReissueSteerText(text) {
|
|
32445
|
-
return /^the model provider .+ is answering again — re-issue the held turn and continue$/.test(text.trim());
|
|
32446
|
-
}
|
|
32447
|
-
function waitingWords(waiting2) {
|
|
32448
|
-
if (waiting2.length === 0) return "its turn";
|
|
32449
|
-
return waiting2.map(
|
|
32450
|
-
(c) => c.kind === "thread_free" ? "the thread's live run" : c.kind === "deploy_settled" ? "the pending deploy" : c.kind === "seat" ? `a seat on ${c.resident}` : c.kind === "memory" ? `memory on ${c.resident}` : c.kind === "provider_up" ? `the ${c.provider} provider` : `the ${c.window} window`
|
|
32451
|
-
).join(", then ");
|
|
32452
|
-
}
|
|
32453
|
-
var init_decide = __esm({
|
|
32454
|
-
"../../src/core/plane/decide.ts"() {
|
|
32455
|
-
"use strict";
|
|
32456
|
-
init_budgets();
|
|
32457
|
-
}
|
|
32458
|
-
});
|
|
32459
|
-
|
|
32460
32756
|
// ../../src/core/runsService.ts
|
|
32461
32757
|
function runResource(view) {
|
|
32462
32758
|
return {
|
|
@@ -32493,6 +32789,8 @@ function ledgerView(row2, events) {
|
|
|
32493
32789
|
...m.repo !== void 0 ? { repo: m.repo } : {},
|
|
32494
32790
|
startedAt: row2.startedAt,
|
|
32495
32791
|
finished: false,
|
|
32792
|
+
...row2.liveState !== void 0 ? { liveState: row2.liveState } : {},
|
|
32793
|
+
...row2.liveStateSeq !== void 0 ? { liveStateSeq: row2.liveStateSeq } : {},
|
|
32496
32794
|
eventCount: events.length,
|
|
32497
32795
|
...activity !== void 0 ? { activity } : {},
|
|
32498
32796
|
...m.sourceUrl !== void 0 ? { sourceUrl: m.sourceUrl } : {},
|
|
@@ -32531,6 +32829,8 @@ function liveView(s) {
|
|
|
32531
32829
|
...s.stepCount !== void 0 ? { stepCount: s.stepCount } : {},
|
|
32532
32830
|
...s.schema !== void 0 ? { schema: s.schema } : {},
|
|
32533
32831
|
...s.status !== void 0 ? { status: s.status } : {},
|
|
32832
|
+
...s.liveState !== void 0 ? { liveState: s.liveState } : {},
|
|
32833
|
+
...s.liveStateSeq !== void 0 ? { liveStateSeq: s.liveStateSeq } : {},
|
|
32534
32834
|
eventCount: s.eventCount,
|
|
32535
32835
|
...s.stop ? { stop: s.stop } : {},
|
|
32536
32836
|
...s.activity !== void 0 ? { activity: s.activity } : {},
|
|
@@ -32628,7 +32928,7 @@ function createRunsService(deps) {
|
|
|
32628
32928
|
const prices = deps.prices ?? NO_PRICES;
|
|
32629
32929
|
const clock4 = deps.clock ?? systemClock;
|
|
32630
32930
|
const warn = deps.warn ?? ((m) => console.warn(m));
|
|
32631
|
-
const
|
|
32931
|
+
const describe13 = (err2) => err2 instanceof Error ? err2.message : String(err2);
|
|
32632
32932
|
let listing;
|
|
32633
32933
|
const liveRows = () => {
|
|
32634
32934
|
if (!ledger) return null;
|
|
@@ -32648,7 +32948,7 @@ function createRunsService(deps) {
|
|
|
32648
32948
|
try {
|
|
32649
32949
|
rows = await pending2;
|
|
32650
32950
|
} catch (err2) {
|
|
32651
|
-
warn(`[runs] run ledger list failed \u2014 showing this process's runs only: ${
|
|
32951
|
+
warn(`[runs] run ledger list failed \u2014 showing this process's runs only: ${describe13(err2)}`);
|
|
32652
32952
|
return [];
|
|
32653
32953
|
}
|
|
32654
32954
|
const foreign = rows.filter((row2) => !registry.getById(row2.runId));
|
|
@@ -32658,7 +32958,7 @@ function createRunsService(deps) {
|
|
|
32658
32958
|
try {
|
|
32659
32959
|
events = await ledger.readEvents(row2.runId);
|
|
32660
32960
|
} catch (err2) {
|
|
32661
|
-
warn(`[runs] run ledger events read failed for ${row2.runId}: ${
|
|
32961
|
+
warn(`[runs] run ledger events read failed for ${row2.runId}: ${describe13(err2)}`);
|
|
32662
32962
|
}
|
|
32663
32963
|
return ledgerView(row2, events);
|
|
32664
32964
|
})
|
|
@@ -32672,7 +32972,7 @@ function createRunsService(deps) {
|
|
|
32672
32972
|
if (!row2) return null;
|
|
32673
32973
|
return { row: row2, events: await ledger.readEvents(id) };
|
|
32674
32974
|
} catch (err2) {
|
|
32675
|
-
warn(`[runs] run ledger read failed for ${id}: ${
|
|
32975
|
+
warn(`[runs] run ledger read failed for ${id}: ${describe13(err2)}`);
|
|
32676
32976
|
return null;
|
|
32677
32977
|
}
|
|
32678
32978
|
};
|
|
@@ -32681,21 +32981,23 @@ function createRunsService(deps) {
|
|
|
32681
32981
|
try {
|
|
32682
32982
|
const row2 = await ledger.planeQueued(id);
|
|
32683
32983
|
if (!row2) return null;
|
|
32984
|
+
const stampedChannel = row2.request.channelId;
|
|
32684
32985
|
const channelAt = row2.threadKey.lastIndexOf(":");
|
|
32685
|
-
const
|
|
32986
|
+
const channelId = typeof stampedChannel === "string" ? stampedChannel : channelAt > 0 ? row2.threadKey.slice(0, channelAt) : void 0;
|
|
32987
|
+
const waiting3 = waitingWords(row2.conditions);
|
|
32686
32988
|
return {
|
|
32687
32989
|
id: row2.runId,
|
|
32688
|
-
...
|
|
32990
|
+
...channelId !== void 0 ? { channelId } : {},
|
|
32689
32991
|
userId: row2.requester,
|
|
32690
32992
|
threadKey: row2.threadKey,
|
|
32691
32993
|
startedAt: row2.queuedAt,
|
|
32692
32994
|
finished: false,
|
|
32693
32995
|
eventCount: 0,
|
|
32694
|
-
queued: { state: row2.state, position: row2.position, waiting:
|
|
32695
|
-
activity: row2.state === "waiting" ? `queued at position ${row2.position} \u2014 waiting on ${
|
|
32996
|
+
queued: { state: row2.state, position: row2.position, waiting: waiting3 },
|
|
32997
|
+
activity: row2.state === "waiting" ? `queued at position ${row2.position} \u2014 waiting on ${waiting3}` : row2.state === "admitted" ? "admitted \u2014 starting" : "withdrawn"
|
|
32696
32998
|
};
|
|
32697
32999
|
} catch (err2) {
|
|
32698
|
-
warn(`[runs] plane queued read failed for ${id}: ${
|
|
33000
|
+
warn(`[runs] plane queued read failed for ${id}: ${describe13(err2)}`);
|
|
32699
33001
|
return null;
|
|
32700
33002
|
}
|
|
32701
33003
|
};
|
|
@@ -32713,7 +33015,7 @@ function createRunsService(deps) {
|
|
|
32713
33015
|
row2 = await storeSummary(id);
|
|
32714
33016
|
} catch (err2) {
|
|
32715
33017
|
warn(
|
|
32716
|
-
`[runs] history store read failed for ${id} \u2014 serving the registry row without its record: ${
|
|
33018
|
+
`[runs] history store read failed for ${id} \u2014 serving the registry row without its record: ${describe13(err2)}`
|
|
32717
33019
|
);
|
|
32718
33020
|
return {};
|
|
32719
33021
|
}
|
|
@@ -32758,12 +33060,12 @@ function createRunsService(deps) {
|
|
|
32758
33060
|
if (marked.ok) runnerStopped = true;
|
|
32759
33061
|
else warn(`[runs] the runner's stop mark was refused for ${id} (${marked.reason})`);
|
|
32760
33062
|
} catch (err2) {
|
|
32761
|
-
warn(`[runs] the runner's stop mark failed for ${id}: ${
|
|
33063
|
+
warn(`[runs] the runner's stop mark failed for ${id}: ${describe13(err2)}`);
|
|
32762
33064
|
}
|
|
32763
33065
|
try {
|
|
32764
33066
|
unitRows = await units.listUnits(instanceId);
|
|
32765
33067
|
} catch (err2) {
|
|
32766
|
-
warn(`[runs] unit rows unavailable for the hard stop of ${id}: ${
|
|
33068
|
+
warn(`[runs] unit rows unavailable for the hard stop of ${id}: ${describe13(err2)}`);
|
|
32767
33069
|
}
|
|
32768
33070
|
}
|
|
32769
33071
|
registry.publish(id, { type: "answer", text: hostedSealAnswer(unitRows, runnerStopped), at: clock4() });
|
|
@@ -32777,7 +33079,7 @@ function createRunsService(deps) {
|
|
|
32777
33079
|
if (row2) {
|
|
32778
33080
|
const finishedAt = snap?.finishedAt ?? at;
|
|
32779
33081
|
const m = row2.meta;
|
|
32780
|
-
const
|
|
33082
|
+
const record3 = assembleRunRecord({
|
|
32781
33083
|
run: { id, ...summary?.label !== void 0 ? { label: summary.label } : {} },
|
|
32782
33084
|
snap,
|
|
32783
33085
|
agent: m.agent ?? "ship",
|
|
@@ -32805,11 +33107,11 @@ function createRunsService(deps) {
|
|
|
32805
33107
|
}),
|
|
32806
33108
|
seal
|
|
32807
33109
|
});
|
|
32808
|
-
const done = await ledger.finish(id, row2.ownerGen,
|
|
33110
|
+
const done = await ledger.finish(id, row2.ownerGen, record3);
|
|
32809
33111
|
if (!done.ok) warn(`[runs] run ledger finish refused for ${id} (${done.reason ?? "unknown"})`);
|
|
32810
33112
|
}
|
|
32811
33113
|
} catch (err2) {
|
|
32812
|
-
warn(`[runs] run ledger finish failed for ${id}: ${
|
|
33114
|
+
warn(`[runs] run ledger finish failed for ${id}: ${describe13(err2)}`);
|
|
32813
33115
|
}
|
|
32814
33116
|
}
|
|
32815
33117
|
return { ok: true, value: { id, mode: "hard", state: "stopping" } };
|
|
@@ -32903,12 +33205,12 @@ function createRunsService(deps) {
|
|
|
32903
33205
|
const queued = await queuedRun(id);
|
|
32904
33206
|
return queued ? { ok: true, value: queued } : notFound;
|
|
32905
33207
|
}
|
|
32906
|
-
const
|
|
32907
|
-
if (!
|
|
33208
|
+
const record3 = await storeGet(id);
|
|
33209
|
+
if (!record3) {
|
|
32908
33210
|
const queued = await queuedRun(id);
|
|
32909
33211
|
return queued ? { ok: true, value: queued } : notFound;
|
|
32910
33212
|
}
|
|
32911
|
-
const { events, ...rest } =
|
|
33213
|
+
const { events, ...rest } = record3;
|
|
32912
33214
|
const view = persistedView(rest, prices);
|
|
32913
33215
|
view.events = events;
|
|
32914
33216
|
return { ok: true, value: view };
|
|
@@ -32988,7 +33290,7 @@ function createRunsService(deps) {
|
|
|
32988
33290
|
const r = await ledger.requestStop(id, mode);
|
|
32989
33291
|
if (r.ok) return { ok: true, value: { id, mode, state: "stopping" } };
|
|
32990
33292
|
} catch (err2) {
|
|
32991
|
-
warn(`[runs] run ledger stop failed for ${id}: ${
|
|
33293
|
+
warn(`[runs] run ledger stop failed for ${id}: ${describe13(err2)}`);
|
|
32992
33294
|
}
|
|
32993
33295
|
}
|
|
32994
33296
|
if (await storeSummary(id)) return conflict;
|
|
@@ -32998,7 +33300,7 @@ function createRunsService(deps) {
|
|
|
32998
33300
|
if (r.withdrawn) return { ok: true, value: { id, mode, state: "withdrawn" } };
|
|
32999
33301
|
if (await ledger.planeQueued(id) !== null) return conflict;
|
|
33000
33302
|
} catch (err2) {
|
|
33001
|
-
warn(`[runs] plane withdraw failed for ${id}: ${
|
|
33303
|
+
warn(`[runs] plane withdraw failed for ${id}: ${describe13(err2)}`);
|
|
33002
33304
|
}
|
|
33003
33305
|
}
|
|
33004
33306
|
return notFound;
|
|
@@ -34789,11 +35091,11 @@ var init_runLedgerWorker = __esm({
|
|
|
34789
35091
|
this.checkIds(runId3, gen);
|
|
34790
35092
|
return this.writeTurns(runId3, gen, turns, session);
|
|
34791
35093
|
}
|
|
34792
|
-
async step(runId3, gen,
|
|
35094
|
+
async step(runId3, gen, record3, turns, session) {
|
|
34793
35095
|
this.checkIds(runId3, gen);
|
|
34794
35096
|
const written = await this.writeTurns(runId3, gen, turns, session);
|
|
34795
35097
|
if (!written.ok) return written;
|
|
34796
|
-
return this.fenceResult(await this.post("/runs/step", { storeKey: this.opts.storeKey, runId: runId3, gen, record:
|
|
35098
|
+
return this.fenceResult(await this.post("/runs/step", { storeKey: this.opts.storeKey, runId: runId3, gen, record: record3 }));
|
|
34797
35099
|
}
|
|
34798
35100
|
checkSessionKey(key) {
|
|
34799
35101
|
if (!SESSION_KEY_PATTERN.test(key))
|
|
@@ -34929,6 +35231,11 @@ var init_runLedgerWorker = __esm({
|
|
|
34929
35231
|
if (events.length === 0) return { ok: true };
|
|
34930
35232
|
return this.fenceResult(await this.post("/runs/append", { storeKey: this.opts.storeKey, runId: runId3, gen, events }));
|
|
34931
35233
|
}
|
|
35234
|
+
async assignLiveState(runId3, gen, assignment) {
|
|
35235
|
+
this.checkIds(runId3, gen);
|
|
35236
|
+
const r = await this.post("/runs/live-state", { storeKey: this.opts.storeKey, runId: runId3, gen, assignment });
|
|
35237
|
+
return r.data;
|
|
35238
|
+
}
|
|
34932
35239
|
async setState(runId3, gen, state) {
|
|
34933
35240
|
this.checkIds(runId3, gen);
|
|
34934
35241
|
return this.fenceResult(await this.post("/runs/state", { storeKey: this.opts.storeKey, runId: runId3, gen, state }));
|
|
@@ -34959,20 +35266,20 @@ var init_runLedgerWorker = __esm({
|
|
|
34959
35266
|
this.checkIds(runId3, gen);
|
|
34960
35267
|
return this.fenceResult(await this.post("/runs/finishing", { storeKey: this.opts.storeKey, runId: runId3, gen }));
|
|
34961
35268
|
}
|
|
34962
|
-
async finish(runId3, gen,
|
|
35269
|
+
async finish(runId3, gen, record3) {
|
|
34963
35270
|
this.checkIds(runId3, gen);
|
|
34964
|
-
const point = pointOf(
|
|
35271
|
+
const point = pointOf(record3, this.opts.prices);
|
|
34965
35272
|
const r = await this.post("/runs/finish", {
|
|
34966
35273
|
storeKey: this.opts.storeKey,
|
|
34967
35274
|
runId: runId3,
|
|
34968
35275
|
gen,
|
|
34969
|
-
record:
|
|
35276
|
+
record: record3,
|
|
34970
35277
|
...point !== void 0 ? { point } : {}
|
|
34971
35278
|
});
|
|
34972
35279
|
const f = this.fenceResult(r);
|
|
34973
35280
|
if (!f.ok) return f;
|
|
34974
|
-
if (
|
|
34975
|
-
await this.post("/runs/session/clear-owner", { key:
|
|
35281
|
+
if (record3.session)
|
|
35282
|
+
await this.post("/runs/session/clear-owner", { key: record3.session.key, runId: runId3, gen }).catch(() => {
|
|
34976
35283
|
});
|
|
34977
35284
|
return { ok: true, stored: r.data.stored === true };
|
|
34978
35285
|
}
|
|
@@ -35671,6 +35978,19 @@ function runPageLink(id) {
|
|
|
35671
35978
|
if (!base) return void 0;
|
|
35672
35979
|
return `${base.replace(/\/+$/, "")}/runs/${encodeURIComponent(id)}`;
|
|
35673
35980
|
}
|
|
35981
|
+
function threadPageLink(threadKey, publicBaseUrl = process.env.PUBLIC_BASE_URL) {
|
|
35982
|
+
if (!publicBaseUrl?.trim()) return void 0;
|
|
35983
|
+
try {
|
|
35984
|
+
const base = new URL(publicBaseUrl.trim());
|
|
35985
|
+
if (!["https:", "http:"].includes(base.protocol) || base.username || base.password) return void 0;
|
|
35986
|
+
base.search = "";
|
|
35987
|
+
base.hash = "";
|
|
35988
|
+
base.pathname = `${base.pathname.replace(/\/+$/, "")}/threads/${encodeURIComponent(threadKey).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`)}`;
|
|
35989
|
+
return base.href;
|
|
35990
|
+
} catch {
|
|
35991
|
+
return void 0;
|
|
35992
|
+
}
|
|
35993
|
+
}
|
|
35674
35994
|
function artifactLink(id, key, token2) {
|
|
35675
35995
|
const page2 = runPageLink(id);
|
|
35676
35996
|
if (!page2) return void 0;
|
|
@@ -35757,6 +36077,9 @@ function activityLine(e) {
|
|
|
35757
36077
|
case "lease":
|
|
35758
36078
|
return "lease started";
|
|
35759
36079
|
// the harness's clocks: head material the run loop keeps off the card — never arrives here
|
|
36080
|
+
case "run_state":
|
|
36081
|
+
return "";
|
|
36082
|
+
// Existing renderers stay until the surface cutover to the shared wording table.
|
|
35760
36083
|
case "skill_use":
|
|
35761
36084
|
return `\u{1F4DA} skill ${e.skill} loaded`;
|
|
35762
36085
|
case "artifact":
|
|
@@ -36345,9 +36668,9 @@ function recordPrOf(ctx) {
|
|
|
36345
36668
|
}
|
|
36346
36669
|
function inheritedPr(thread, records, repo) {
|
|
36347
36670
|
const turn = thread.pr && thread.pr.repo === repo ? { repo, number: thread.pr.number, source: "turn", at: thread.prAt } : void 0;
|
|
36348
|
-
const
|
|
36349
|
-
if (!turn || !
|
|
36350
|
-
return turn.at !== void 0 &&
|
|
36671
|
+
const record3 = records?.pr && records.pr.repo === repo ? { repo, number: records.pr.number, source: "record", at: records.pr.at } : void 0;
|
|
36672
|
+
if (!turn || !record3) return turn ?? record3;
|
|
36673
|
+
return turn.at !== void 0 && record3.at !== void 0 && turn.at > record3.at ? turn : record3;
|
|
36351
36674
|
}
|
|
36352
36675
|
async function openPrHeadSha(pr) {
|
|
36353
36676
|
const head = await prHead(pr).catch(() => void 0);
|
|
@@ -36700,7 +37023,7 @@ async function attachRoundWorkspace(input) {
|
|
|
36700
37023
|
...input.round.stopSignal !== void 0 ? { stopSignal: input.round.stopSignal } : {},
|
|
36701
37024
|
...input.round.remainingMs !== void 0 ? { remainingMs: input.round.remainingMs } : {},
|
|
36702
37025
|
...input.round.requester !== void 0 ? { requester: input.round.requester } : {},
|
|
36703
|
-
...input.round.
|
|
37026
|
+
...input.round.onLiveStateObservation !== void 0 ? { onLiveStateObservation: input.round.onLiveStateObservation } : {}
|
|
36704
37027
|
},
|
|
36705
37028
|
input.span
|
|
36706
37029
|
);
|
|
@@ -36955,7 +37278,7 @@ async function classifyMove(fetchPrCommits, q) {
|
|
|
36955
37278
|
async function runReviewPostStep(input) {
|
|
36956
37279
|
const { agent, repoCtx, verdict, carried, logKey } = input;
|
|
36957
37280
|
const { reviewHead, observedHead } = input.heads;
|
|
36958
|
-
const
|
|
37281
|
+
const record3 = (outcome) => {
|
|
36959
37282
|
if (input.publish && agent.name === "review" && !input.hardStopped) {
|
|
36960
37283
|
const where = outcome.posted ? void 0 : repoCtx.repo && repoCtx.pr ? `${repoCtx.repo}#${repoCtx.pr}` : void 0;
|
|
36961
37284
|
input.publish(
|
|
@@ -37054,7 +37377,7 @@ ${carriedFooter(carried)}` : rendered;
|
|
|
37054
37377
|
console.error(`[review-post] ${logKey} failed for ${where}: ${reason2}`);
|
|
37055
37378
|
await input.reply(`\u2139\uFE0F Review not posted to ${where}: ${reason2} \u2014 this verdict is Slack-only.`).catch(() => {
|
|
37056
37379
|
});
|
|
37057
|
-
return
|
|
37380
|
+
return record3({ posted: false, reason: reason2 });
|
|
37058
37381
|
}
|
|
37059
37382
|
console.log(
|
|
37060
37383
|
`[review-post] ${logKey} \u2192 ${where} (${verdict?.verdict ?? "no verdict"})${carried ? ` carried ${carried.reviewed.slice(0, 7)} \u2192 ${pinned.slice(0, 7)}` : ""}`
|
|
@@ -37070,14 +37393,14 @@ ${carriedFooter(carried)}` : rendered;
|
|
|
37070
37393
|
await input.reply(moved).catch(() => {
|
|
37071
37394
|
});
|
|
37072
37395
|
}
|
|
37073
|
-
return
|
|
37396
|
+
return record3({
|
|
37074
37397
|
posted: true,
|
|
37075
37398
|
target: { repo: postTarget.repo, number: postTarget.number },
|
|
37076
37399
|
head: pinned,
|
|
37077
37400
|
...verdict !== void 0 ? { verdict: verdict.verdict } : {}
|
|
37078
37401
|
});
|
|
37079
37402
|
}
|
|
37080
|
-
return
|
|
37403
|
+
return record3({ posted: false, reason: skipReason });
|
|
37081
37404
|
}
|
|
37082
37405
|
var init_reviewRound = __esm({
|
|
37083
37406
|
"../../src/core/reviewRound.ts"() {
|
|
@@ -37434,11 +37757,11 @@ var init_authorize2 = __esm({
|
|
|
37434
37757
|
});
|
|
37435
37758
|
|
|
37436
37759
|
// ../../src/core/runHistoryWriter.ts
|
|
37437
|
-
async function putOnce(sink,
|
|
37760
|
+
async function putOnce(sink, record3) {
|
|
37438
37761
|
try {
|
|
37439
|
-
return await sink.put(
|
|
37762
|
+
return await sink.put(record3);
|
|
37440
37763
|
} catch (err2) {
|
|
37441
|
-
sink.abandoned(
|
|
37764
|
+
sink.abandoned(record3, describe2(err2));
|
|
37442
37765
|
throw err2;
|
|
37443
37766
|
}
|
|
37444
37767
|
}
|
|
@@ -37462,28 +37785,28 @@ function createRunHistoryWriter(opts) {
|
|
|
37462
37785
|
opts.warn(`[run-history] onPersisted hook failed for ${id}: ${describe2(err2)}`);
|
|
37463
37786
|
}
|
|
37464
37787
|
};
|
|
37465
|
-
const attemptAll = async (
|
|
37788
|
+
const attemptAll = async (record3, flag2, sink, span) => {
|
|
37466
37789
|
const attempts = RUN_HISTORY_RETRY_DELAYS_MS.length + 1;
|
|
37467
37790
|
const giveUp = async (why) => {
|
|
37468
37791
|
failures++;
|
|
37469
37792
|
try {
|
|
37470
|
-
sink.abandoned(
|
|
37793
|
+
sink.abandoned(record3, why);
|
|
37471
37794
|
} catch (err2) {
|
|
37472
|
-
opts.warn(`[run-history] abandoned hook failed for ${
|
|
37795
|
+
opts.warn(`[run-history] abandoned hook failed for ${record3.id}: ${describe2(err2)}`);
|
|
37473
37796
|
}
|
|
37474
37797
|
if (sink === opts.store || flag2?.superseded) return;
|
|
37475
37798
|
try {
|
|
37476
|
-
await opts.store.put(
|
|
37477
|
-
if (!flag2) persisted(
|
|
37799
|
+
await opts.store.put(record3, span ? { span } : void 0);
|
|
37800
|
+
if (!flag2) persisted(record3.id);
|
|
37478
37801
|
} catch (err2) {
|
|
37479
|
-
opts.warn(`[run-history] ${
|
|
37802
|
+
opts.warn(`[run-history] ${record3.id} store fallback after give-up failed: ${describe2(err2)}`);
|
|
37480
37803
|
}
|
|
37481
37804
|
};
|
|
37482
37805
|
for (let attempt = 1; ; attempt++) {
|
|
37483
37806
|
if (flag2?.superseded) return;
|
|
37484
37807
|
try {
|
|
37485
|
-
await sink.put(
|
|
37486
|
-
if (!flag2) persisted(
|
|
37808
|
+
await sink.put(record3, span ? { span } : void 0);
|
|
37809
|
+
if (!flag2) persisted(record3.id);
|
|
37487
37810
|
return;
|
|
37488
37811
|
} catch (err2) {
|
|
37489
37812
|
if (err2 instanceof RouteMissingError) {
|
|
@@ -37496,12 +37819,12 @@ function createRunHistoryWriter(opts) {
|
|
|
37496
37819
|
return;
|
|
37497
37820
|
}
|
|
37498
37821
|
if (err2 instanceof PermanentStoreError) {
|
|
37499
|
-
opts.warn(`[run-history] ${
|
|
37822
|
+
opts.warn(`[run-history] ${record3.id} not persisted (permanent, not retried): ${describe2(err2)}`);
|
|
37500
37823
|
await giveUp(describe2(err2));
|
|
37501
37824
|
return;
|
|
37502
37825
|
}
|
|
37503
37826
|
if (attempt >= attempts) {
|
|
37504
|
-
opts.warn(`[run-history] ${
|
|
37827
|
+
opts.warn(`[run-history] ${record3.id} not persisted after ${attempts} attempts: ${describe2(err2)}`);
|
|
37505
37828
|
await giveUp(`not persisted after ${attempts} attempts: ${describe2(err2)}`);
|
|
37506
37829
|
return;
|
|
37507
37830
|
}
|
|
@@ -37510,24 +37833,24 @@ function createRunHistoryWriter(opts) {
|
|
|
37510
37833
|
}
|
|
37511
37834
|
};
|
|
37512
37835
|
return {
|
|
37513
|
-
write(
|
|
37836
|
+
write(record3, writeOpts) {
|
|
37514
37837
|
let flag2;
|
|
37515
37838
|
if (writeOpts?.provisional === true) {
|
|
37516
|
-
if (finals.has(
|
|
37517
|
-
flag2 = { id:
|
|
37839
|
+
if (finals.has(record3.id)) return;
|
|
37840
|
+
flag2 = { id: record3.id, superseded: false };
|
|
37518
37841
|
provisionalFlags.add(flag2);
|
|
37519
37842
|
} else {
|
|
37520
|
-
finals.add(
|
|
37521
|
-
for (const f of provisionalFlags) if (f.id ===
|
|
37843
|
+
finals.add(record3.id);
|
|
37844
|
+
for (const f of provisionalFlags) if (f.id === record3.id) f.superseded = true;
|
|
37522
37845
|
}
|
|
37523
37846
|
const sink = writeOpts?.via ?? opts.store;
|
|
37524
|
-
const p = attemptAll(
|
|
37847
|
+
const p = attemptAll(record3, flag2, sink, writeOpts?.span).catch((err2) => {
|
|
37525
37848
|
failures++;
|
|
37526
|
-
opts.warn(`[run-history] ${
|
|
37849
|
+
opts.warn(`[run-history] ${record3.id} writer failed unexpectedly: ${describe2(err2)}`);
|
|
37527
37850
|
try {
|
|
37528
|
-
sink.abandoned(
|
|
37851
|
+
sink.abandoned(record3, `writer failed unexpectedly: ${describe2(err2)}`);
|
|
37529
37852
|
} catch (hookErr) {
|
|
37530
|
-
opts.warn(`[run-history] abandoned hook failed for ${
|
|
37853
|
+
opts.warn(`[run-history] abandoned hook failed for ${record3.id}: ${describe2(hookErr)}`);
|
|
37531
37854
|
}
|
|
37532
37855
|
}).finally(() => {
|
|
37533
37856
|
if (flag2) provisionalFlags.delete(flag2);
|
|
@@ -37890,12 +38213,12 @@ async function closeRestartRow(adopted, restart, why) {
|
|
|
37890
38213
|
async function closeResumedRow(adopted, resume, why, status3 = "interrupted", opts) {
|
|
37891
38214
|
try {
|
|
37892
38215
|
const finishedAt = (opts?.clock ?? systemClock)();
|
|
37893
|
-
const
|
|
38216
|
+
const record3 = {
|
|
37894
38217
|
...reclaimedRunRecord({ row: resume.row, events: resume.events, status: status3, finishedAt }),
|
|
37895
38218
|
...opts?.restarting === true ? { restarting: true, restartUntil: finishedAt + RESTART_CLAIM_GRACE_MS } : {}
|
|
37896
38219
|
};
|
|
37897
|
-
await putOnce(adopted.sink,
|
|
37898
|
-
return
|
|
38220
|
+
await putOnce(adopted.sink, record3);
|
|
38221
|
+
return record3;
|
|
37899
38222
|
} catch (err2) {
|
|
37900
38223
|
console.warn(
|
|
37901
38224
|
`[resume] ${resume.row.runId} could not be closed (${why}): ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
@@ -38586,6 +38909,8 @@ function summaryOf(run2, now) {
|
|
|
38586
38909
|
...m?.hosted ? { hosted: true } : {},
|
|
38587
38910
|
...run2.instanceId !== void 0 ? { instanceId: run2.instanceId } : {},
|
|
38588
38911
|
...run2.pipeline !== void 0 ? { pipeline: run2.pipeline } : {},
|
|
38912
|
+
...run2.liveState !== void 0 ? { liveState: run2.liveState } : {},
|
|
38913
|
+
...run2.liveStateSeq !== void 0 ? { liveStateSeq: run2.liveStateSeq } : {},
|
|
38589
38914
|
finished: run2.finished,
|
|
38590
38915
|
startedAt: run2.startedAt,
|
|
38591
38916
|
...run2.finishedAt !== void 0 ? { finishedAt: run2.finishedAt } : {},
|
|
@@ -38621,7 +38946,9 @@ function snapshotOf(run2) {
|
|
|
38621
38946
|
...run2.meta?.receivedAt !== void 0 ? { receivedAt: run2.meta.receivedAt } : {},
|
|
38622
38947
|
eventCount: run2.eventCount,
|
|
38623
38948
|
stepCount: run2.stepCount,
|
|
38624
|
-
truncated: run2.eventCount > run2.backlog.length
|
|
38949
|
+
truncated: run2.eventCount > run2.backlog.length,
|
|
38950
|
+
...run2.liveState !== void 0 ? { liveState: run2.liveState } : {},
|
|
38951
|
+
...run2.liveStateSeq !== void 0 ? { liveStateSeq: run2.liveStateSeq } : {}
|
|
38625
38952
|
};
|
|
38626
38953
|
}
|
|
38627
38954
|
function sealResultOf(run2) {
|
|
@@ -38705,6 +39032,7 @@ var init_runRegistry = __esm({
|
|
|
38705
39032
|
init_projections();
|
|
38706
39033
|
init_indexFeed();
|
|
38707
39034
|
init_runPace();
|
|
39035
|
+
init_runLiveState();
|
|
38708
39036
|
PACE_RING_CAP = 1200;
|
|
38709
39037
|
UNSEALED_HOLD_MS = 15 * 6e4;
|
|
38710
39038
|
RUN_LABEL_MAX2 = 200;
|
|
@@ -38778,6 +39106,10 @@ var init_runRegistry = __esm({
|
|
|
38778
39106
|
if (!isSpanRecord(event)) run2.stepCount++;
|
|
38779
39107
|
appendToBacklog(run2, this.bounds, { ...event, seq });
|
|
38780
39108
|
}
|
|
39109
|
+
const replayedLiveState = foldRunLiveState(opts.replay ?? [], opts.liveState);
|
|
39110
|
+
const folded = opts.resetLiveState ? { liveStateSeq: replayedLiveState.liveStateSeq } : replayedLiveState;
|
|
39111
|
+
run2.liveState = folded.liveState;
|
|
39112
|
+
run2.liveStateSeq = folded.liveStateSeq;
|
|
38781
39113
|
this.index.notify({ type: "upsert", run: summaryOf(run2, this.now()) });
|
|
38782
39114
|
return { id, token: token2, control: run2.control, ...stored !== void 0 ? { label: stored } : {} };
|
|
38783
39115
|
}
|
|
@@ -38866,6 +39198,32 @@ var init_runRegistry = __esm({
|
|
|
38866
39198
|
}
|
|
38867
39199
|
if (!span) this.index.notify({ type: "upsert", run: summaryOf(run2, this.now()) });
|
|
38868
39200
|
}
|
|
39201
|
+
/** Apply an assignment only after its durable transaction acknowledged. The
|
|
39202
|
+
* boundary keeps the ledger-assigned stream sequence; subscribers cannot
|
|
39203
|
+
* observe either half before this call. */
|
|
39204
|
+
commitLiveState(id, committed) {
|
|
39205
|
+
const run2 = this.runs.get(id);
|
|
39206
|
+
if (!run2 || run2.finished || run2.sealedAt !== void 0) return false;
|
|
39207
|
+
const event = committed.event;
|
|
39208
|
+
if (event !== void 0) {
|
|
39209
|
+
const seq = event.seq;
|
|
39210
|
+
if (seq === void 0 || seq !== run2.eventCount + 1) return false;
|
|
39211
|
+
run2.eventCount = seq;
|
|
39212
|
+
run2.stepCount++;
|
|
39213
|
+
const stamped = { ...event, seq };
|
|
39214
|
+
appendToBacklog(run2, this.bounds, stamped);
|
|
39215
|
+
for (const sub of run2.subscribers) {
|
|
39216
|
+
try {
|
|
39217
|
+
sub.onEvent(stamped, seq);
|
|
39218
|
+
} catch {
|
|
39219
|
+
}
|
|
39220
|
+
}
|
|
39221
|
+
}
|
|
39222
|
+
run2.liveState = committed.liveState;
|
|
39223
|
+
run2.liveStateSeq = committed.liveStateSeq;
|
|
39224
|
+
this.index.notify({ type: "upsert", run: summaryOf(run2, this.now()) });
|
|
39225
|
+
return true;
|
|
39226
|
+
}
|
|
38869
39227
|
/** Mark a run finished — the agent stopped: stamp `finishedAt`, send every
|
|
38870
39228
|
* attached subscriber the `finished` frame WITHOUT detaching it (span records
|
|
38871
39229
|
* still flow until the seal), and upsert the index. `status` is the terminal
|
|
@@ -40277,11 +40635,13 @@ async function ownerOf2(runs, unitsOf, threadKey) {
|
|
|
40277
40635
|
const units = await unitsOf(instanceId).catch(() => []);
|
|
40278
40636
|
const unit = units.find((u) => u.threadKey === threadKey && u.ending === void 0);
|
|
40279
40637
|
if (unit !== void 0) return { kind: "unit", instanceId, unit };
|
|
40280
|
-
const ended = units.
|
|
40638
|
+
const ended = units.filter(
|
|
40281
40639
|
(u) => u.threadKey === threadKey && u.ending !== void 0 && u.ending.kind !== "merged" && u.ending.kind !== "already_landed"
|
|
40282
40640
|
);
|
|
40283
40641
|
const ship = runs.find((r) => r.instanceId === instanceId && r.finished);
|
|
40284
|
-
if (ended
|
|
40642
|
+
if (ended.length === 1 && ship !== void 0) return { kind: "pipeline", instanceId, run: ship, unit: ended[0] };
|
|
40643
|
+
if (ended.length > 1 && ship !== void 0)
|
|
40644
|
+
return { kind: "pipeline_ambiguous", instanceId, run: ship, units: ended };
|
|
40285
40645
|
}
|
|
40286
40646
|
const agent = stickyAgentOf(runs);
|
|
40287
40647
|
if (agent !== void 0) return { kind: "session", agent };
|
|
@@ -40492,8 +40852,9 @@ function ownedProjection(p) {
|
|
|
40492
40852
|
function ownerNote(owner) {
|
|
40493
40853
|
const who2 = owner.kind === "live" ? `a live run${owner.runId !== void 0 ? ` (\`${owner.runId}\`)` : ""}` : owner.kind === "unit" ? `the unfinished plan unit ${owner.unit}` : `the ended pipeline for unmerged plan unit ${owner.unit}`;
|
|
40494
40854
|
const steer = owner.kind === "live" && owner.runId !== void 0 ? ` bind \`steer run ${owner.runId} <words>\` to deliver it,` : "";
|
|
40495
|
-
|
|
40496
|
-
|
|
40855
|
+
if (owner.kind === "pipeline")
|
|
40856
|
+
return `This thread is owned by ${who2}: the request below is a continuation of that durable task. Read tools may ground the decision, but every action folds into the owner so the current pull request is re-read and the pipeline resumes; an informational command or question is not fulfillment.`;
|
|
40857
|
+
return `This thread is owned by ${who2}: the request below is a follow-up for that owner. To act on it,${steer} bind a read command, or ask a question. Any other decision \u2014 a refusal, a preset, a write \u2014 folds the whole message into the owner unchanged and posts no answer.`;
|
|
40497
40858
|
}
|
|
40498
40859
|
function operatorProjection(input) {
|
|
40499
40860
|
return {
|
|
@@ -40878,14 +41239,13 @@ function runnableProposal(proposal, ctx) {
|
|
|
40878
41239
|
return (ctx.repositories?.length ?? 0) > 0 || /https?:\/\/github\.com\/[\w.-]+\/[\w.-]+|(?:^|\s)[\w.-]+\/[\w.-]+(?:\s|[:#]|$)/i.test(request2);
|
|
40879
41240
|
}
|
|
40880
41241
|
function ownedDecisionRuns(event, owner, commands) {
|
|
40881
|
-
if (event.outcome !== "binds") return false;
|
|
41242
|
+
if (owner.kind === "pipeline" || event.outcome !== "binds") return false;
|
|
40882
41243
|
return (event.binds ?? []).every((bind) => {
|
|
40883
41244
|
const parsed = commands ? parseChatCommand(bind.line, commands) : null;
|
|
40884
41245
|
if (parsed?.kind !== "invoke") return false;
|
|
40885
41246
|
const def = commands.list().find((c) => c.id === parsed.id);
|
|
40886
41247
|
if (!def) return false;
|
|
40887
|
-
if (def.id === "steer.run")
|
|
40888
|
-
return owner.kind !== "pipeline" && !(owner.kind === "live" && owner.runId === void 0);
|
|
41248
|
+
if (def.id === "steer.run") return !(owner.kind === "live" && owner.runId === void 0);
|
|
40889
41249
|
return boundBlastRadius(def, parsed.input) === "read";
|
|
40890
41250
|
});
|
|
40891
41251
|
}
|
|
@@ -41208,6 +41568,7 @@ async function executeOperatorDecision(deps, ctx) {
|
|
|
41208
41568
|
"verbose"
|
|
41209
41569
|
);
|
|
41210
41570
|
const answered = { kind: "answered" };
|
|
41571
|
+
if (ctx.owner?.kind === "pipeline") return { kind: "fold" };
|
|
41211
41572
|
if (event.outcome === "question") {
|
|
41212
41573
|
await io.reply(event.question ?? "");
|
|
41213
41574
|
await recordOperatorDecision(deps, msg, event, ctx.ending, ctx.trace);
|
|
@@ -41567,21 +41928,21 @@ function parseSkillMarkdown(raw) {
|
|
|
41567
41928
|
if (!fm || typeof fm !== "object" || Array.isArray(fm)) {
|
|
41568
41929
|
throw new Error("skill frontmatter is not a YAML mapping");
|
|
41569
41930
|
}
|
|
41570
|
-
const
|
|
41571
|
-
const name =
|
|
41931
|
+
const record3 = fm;
|
|
41932
|
+
const name = record3.name;
|
|
41572
41933
|
if (typeof name !== "string" || name.trim() === "") {
|
|
41573
41934
|
throw new Error("skill frontmatter is missing a non-empty string `name`");
|
|
41574
41935
|
}
|
|
41575
|
-
const description =
|
|
41936
|
+
const description = record3.description;
|
|
41576
41937
|
if (typeof description !== "string" || description.trim() === "") {
|
|
41577
41938
|
throw new Error(`skill "${name}" frontmatter is missing a non-empty string \`description\``);
|
|
41578
41939
|
}
|
|
41579
|
-
const agents =
|
|
41940
|
+
const agents = record3.agents;
|
|
41580
41941
|
if (!Array.isArray(agents) || agents.length === 0 || !agents.every((a) => typeof a === "string" && a.trim() !== "")) {
|
|
41581
41942
|
throw new Error(`skill "${name}" frontmatter needs a non-empty \`agents\` array of strings (e.g. [review])`);
|
|
41582
41943
|
}
|
|
41583
|
-
const source2 = typeof
|
|
41584
|
-
const upstream = parseUpstream(
|
|
41944
|
+
const source2 = typeof record3.source === "string" ? record3.source.trim() : void 0;
|
|
41945
|
+
const upstream = parseUpstream(record3.upstream, name);
|
|
41585
41946
|
return {
|
|
41586
41947
|
name: name.trim(),
|
|
41587
41948
|
description: description.trim(),
|
|
@@ -41867,6 +42228,47 @@ var init_customInstructions = __esm({
|
|
|
41867
42228
|
}
|
|
41868
42229
|
});
|
|
41869
42230
|
|
|
42231
|
+
// ../../src/core/runEventLane.ts
|
|
42232
|
+
var RunEventLane;
|
|
42233
|
+
var init_runEventLane = __esm({
|
|
42234
|
+
"../../src/core/runEventLane.ts"() {
|
|
42235
|
+
"use strict";
|
|
42236
|
+
RunEventLane = class {
|
|
42237
|
+
constructor(publishNow) {
|
|
42238
|
+
this.publishNow = publishNow;
|
|
42239
|
+
}
|
|
42240
|
+
publishNow;
|
|
42241
|
+
tail;
|
|
42242
|
+
/** Publish synchronously while idle; otherwise preserve order behind the active write. */
|
|
42243
|
+
publish(event) {
|
|
42244
|
+
if (!this.tail) {
|
|
42245
|
+
this.publishNow(event);
|
|
42246
|
+
return;
|
|
42247
|
+
}
|
|
42248
|
+
void this.write(() => this.publishNow(event));
|
|
42249
|
+
}
|
|
42250
|
+
/** Queue one operation after every event or operation already accepted. */
|
|
42251
|
+
write(work) {
|
|
42252
|
+
const previous = this.tail ?? Promise.resolve();
|
|
42253
|
+
const next = previous.then(work);
|
|
42254
|
+
const settled = next.then(
|
|
42255
|
+
() => void 0,
|
|
42256
|
+
() => void 0
|
|
42257
|
+
);
|
|
42258
|
+
this.tail = settled;
|
|
42259
|
+
void settled.then(() => {
|
|
42260
|
+
if (this.tail === settled) this.tail = void 0;
|
|
42261
|
+
});
|
|
42262
|
+
return next;
|
|
42263
|
+
}
|
|
42264
|
+
/** Wait until every operation accepted so far has settled. */
|
|
42265
|
+
async drain() {
|
|
42266
|
+
await this.tail;
|
|
42267
|
+
}
|
|
42268
|
+
};
|
|
42269
|
+
}
|
|
42270
|
+
});
|
|
42271
|
+
|
|
41870
42272
|
// ../../src/core/statusCoalescer.ts
|
|
41871
42273
|
function coalesceStatus(inner, minIntervalMs, now = Date.now, schedule = setTimeout) {
|
|
41872
42274
|
let lastSentAt = -Infinity;
|
|
@@ -42039,22 +42441,24 @@ async function registerRun(deps, ctx) {
|
|
|
42039
42441
|
{
|
|
42040
42442
|
id: runId3,
|
|
42041
42443
|
startedAt,
|
|
42042
|
-
...
|
|
42444
|
+
...carriedRow?.liveState !== void 0 ? { liveState: { liveState: carriedRow.liveState, liveStateSeq: carriedRow.liveStateSeq } } : {},
|
|
42445
|
+
...resume ? { replay: resume.events } : ctx.restartCarried ? { replay: ctx.restartCarried.events, token: ctx.restartCarried.token, resetLiveState: true } : {}
|
|
42043
42446
|
}
|
|
42044
42447
|
);
|
|
42448
|
+
const events = new RunEventLane((event) => registry.publish(run2.id, event));
|
|
42045
42449
|
if (ctx.restartCarried)
|
|
42046
|
-
|
|
42450
|
+
events.publish({ type: "run_note", kind: "resumed", summary: ctx.restartCarried.note, at: clock4() });
|
|
42047
42451
|
const liveUrl = liveViewLink(run2.id, run2.token);
|
|
42048
42452
|
shell.setLink(liveUrl ? { url: liveUrl, label: "Live run" } : void 0);
|
|
42049
42453
|
if (liveUrl) admitted.runLink = liveUrl;
|
|
42050
42454
|
io.runStarted?.({ id: run2.id });
|
|
42051
|
-
trace.bindRun(run2.id, (
|
|
42455
|
+
trace.bindRun(run2.id, (event) => events.publish(event));
|
|
42052
42456
|
const publishText = (type, text, source3, raw) => {
|
|
42053
42457
|
const redacted = redactSecrets(text);
|
|
42054
42458
|
const body = { text: redacted, ...source3 ? { source: source3 } : {}, at: clock4() };
|
|
42055
42459
|
const event = type === "input" ? { type, messageId: messageIdOf(msg, run2.id), ...body } : { type, ...body };
|
|
42056
42460
|
const withRaw = raw !== void 0 ? { ...event, raw: redactSecrets(raw) } : event;
|
|
42057
|
-
|
|
42461
|
+
events.publish(utf8ByteLength(JSON.stringify(withRaw)) <= MAX_EVENT_BYTES ? withRaw : event);
|
|
42058
42462
|
console.log(`[event] ${msg.threadKey} type=${type} bytes=${utf8ByteLength(redacted)}`);
|
|
42059
42463
|
};
|
|
42060
42464
|
const humanize = isMrkdwnChannel(msg.channelId);
|
|
@@ -42074,7 +42478,7 @@ async function registerRun(deps, ctx) {
|
|
|
42074
42478
|
if (!resume && ctx.references) {
|
|
42075
42479
|
const { conversations, blocks } = ctx.references;
|
|
42076
42480
|
conversations.forEach((rc, i) => {
|
|
42077
|
-
|
|
42481
|
+
events.publish({
|
|
42078
42482
|
type: "reference",
|
|
42079
42483
|
url: rc.permalink,
|
|
42080
42484
|
channelId: rc.ref.channelId,
|
|
@@ -42086,7 +42490,7 @@ async function registerRun(deps, ctx) {
|
|
|
42086
42490
|
console.log(`[event] ${msg.threadKey} type=reference channel=${rc.ref.channelId} messages=${rc.messages.length}`);
|
|
42087
42491
|
});
|
|
42088
42492
|
}
|
|
42089
|
-
const publishMeta = (repoCtx2) =>
|
|
42493
|
+
const publishMeta = (repoCtx2) => events.publish({
|
|
42090
42494
|
type: "run_meta",
|
|
42091
42495
|
agent: agent.name,
|
|
42092
42496
|
agentSource,
|
|
@@ -42118,7 +42522,7 @@ async function registerRun(deps, ctx) {
|
|
|
42118
42522
|
if (!resume)
|
|
42119
42523
|
for (const d of cardDecisions ?? []) {
|
|
42120
42524
|
if (d.outcome !== "degraded") continue;
|
|
42121
|
-
|
|
42525
|
+
events.publish({
|
|
42122
42526
|
type: "run_note",
|
|
42123
42527
|
kind: "control_degraded",
|
|
42124
42528
|
summary: oneLine(
|
|
@@ -42132,12 +42536,12 @@ async function registerRun(deps, ctx) {
|
|
|
42132
42536
|
at: clock4()
|
|
42133
42537
|
});
|
|
42134
42538
|
}
|
|
42135
|
-
if (!resume && route2)
|
|
42136
|
-
if (!resume && ctx.operator)
|
|
42539
|
+
if (!resume && route2) events.publish({ type: "route", ...route2, at: clock4() });
|
|
42540
|
+
if (!resume && ctx.operator) events.publish({ type: "operator", ...ctx.operator, at: clock4() });
|
|
42137
42541
|
if (!resume && deps.config.config.runHistory?.includeContext !== false) {
|
|
42138
42542
|
for (const text of contextMessageTexts(seedTurns ?? history, humanize)) publishText("context", text);
|
|
42139
42543
|
}
|
|
42140
|
-
return { run: run2, runId: runId3, channelVisibility, liveUrl, publishText, publishMeta };
|
|
42544
|
+
return { run: run2, runId: runId3, channelVisibility, liveUrl, events, publishText, publishMeta };
|
|
42141
42545
|
}
|
|
42142
42546
|
async function reserveRun(deps, ctx) {
|
|
42143
42547
|
const {
|
|
@@ -42213,7 +42617,7 @@ async function reserveRun(deps, ctx) {
|
|
|
42213
42617
|
}
|
|
42214
42618
|
async function attachRound(deps, ctx) {
|
|
42215
42619
|
const { threadKey, agent, profile, repoCtx, root, clock: clock4, reattach, stopSignal, remainingMs, requester } = ctx;
|
|
42216
|
-
const {
|
|
42620
|
+
const { onLiveStateObservation } = ctx;
|
|
42217
42621
|
const ownPr = agent.name === "review" ? void 0 : ownPrOf(repoCtx);
|
|
42218
42622
|
return root.span("dispatch.workspace.attach", async (span) => {
|
|
42219
42623
|
const graft = (steps, residentTotalMs) => graftResidentSteps(steps, {
|
|
@@ -42249,7 +42653,7 @@ async function attachRound(deps, ctx) {
|
|
|
42249
42653
|
...stopSignal !== void 0 ? { stopSignal } : {},
|
|
42250
42654
|
...remainingMs !== void 0 ? { remainingMs } : {},
|
|
42251
42655
|
...requester !== void 0 ? { requester } : {},
|
|
42252
|
-
...
|
|
42656
|
+
...onLiveStateObservation !== void 0 ? { onLiveStateObservation } : {}
|
|
42253
42657
|
},
|
|
42254
42658
|
logKey: threadKey,
|
|
42255
42659
|
span
|
|
@@ -42306,10 +42710,10 @@ async function attachWorkspace(deps, ctx) {
|
|
|
42306
42710
|
clock: clock4,
|
|
42307
42711
|
// The requester whose binding names the author pair (record 0062).
|
|
42308
42712
|
requester: msg.userId,
|
|
42309
|
-
|
|
42310
|
-
|
|
42311
|
-
|
|
42312
|
-
|
|
42713
|
+
onLiveStateObservation: async (observation) => {
|
|
42714
|
+
await ctx.onLiveStateObservation?.(observation);
|
|
42715
|
+
shell.setSetupLabel(`${liveStateWords(observation.state)}\u2026`);
|
|
42716
|
+
},
|
|
42313
42717
|
...reattach !== void 0 ? { reattach } : {},
|
|
42314
42718
|
...stopSignal !== void 0 ? { stopSignal } : {},
|
|
42315
42719
|
...remainingMs !== void 0 ? { remainingMs } : {}
|
|
@@ -42476,7 +42880,6 @@ var init_provision = __esm({
|
|
|
42476
42880
|
init_factory();
|
|
42477
42881
|
init_executor();
|
|
42478
42882
|
init_residentTrace();
|
|
42479
|
-
init_displayNames();
|
|
42480
42883
|
init_resident();
|
|
42481
42884
|
init_memory();
|
|
42482
42885
|
init_budgets();
|
|
@@ -42489,12 +42892,14 @@ var init_provision = __esm({
|
|
|
42489
42892
|
init_reviewRound();
|
|
42490
42893
|
init_repoContext();
|
|
42491
42894
|
init_runEvents();
|
|
42895
|
+
init_runEventLane();
|
|
42492
42896
|
init_redact();
|
|
42493
42897
|
init_runRecord();
|
|
42494
42898
|
init_inboxMessage();
|
|
42495
42899
|
init_statusCardFrame();
|
|
42496
42900
|
init_statusCoalescer();
|
|
42497
42901
|
init_types5();
|
|
42902
|
+
init_decide();
|
|
42498
42903
|
init_record();
|
|
42499
42904
|
init_reply();
|
|
42500
42905
|
init_refusal();
|
|
@@ -44750,9 +45155,13 @@ function mapStringLeaves(value, fn) {
|
|
|
44750
45155
|
}
|
|
44751
45156
|
return value;
|
|
44752
45157
|
}
|
|
45158
|
+
function requesterText(text) {
|
|
45159
|
+
return text.trim().replace(/\s+/g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/[\\`*_{}[\]()#!|~]/g, "\\$&").replace(/@/g, "@");
|
|
45160
|
+
}
|
|
44753
45161
|
function requestedByLine(by) {
|
|
44754
|
-
const steered = by.steeredBy !== void 0 && by.steeredBy.length > 0 ? `; steered by ${by.steeredBy.join(", ")}` : "";
|
|
44755
|
-
|
|
45162
|
+
const steered = by.steeredBy !== void 0 && by.steeredBy.length > 0 ? `; steered by ${by.steeredBy.map(requesterText).join(", ")}` : "";
|
|
45163
|
+
const thread = by.threadUrl ? ` \xB7 [Thread](${by.threadUrl})` : "";
|
|
45164
|
+
return `Requested by **${requesterText(by.name) || "Unknown requester"}**${thread}${steered}`;
|
|
44756
45165
|
}
|
|
44757
45166
|
function encodeGithubPathSegments(path) {
|
|
44758
45167
|
return path.split("/").map(encodeURIComponent).join("/");
|
|
@@ -44775,6 +45184,7 @@ function renderPrDescriptionMarkdown(desc, ctx) {
|
|
|
44775
45184
|
if (!SHA_RE2.test(ctx.headSha))
|
|
44776
45185
|
throw new Error(`renderPrDescriptionMarkdown: headSha must be a full 40-char lowercase sha, got "${ctx.headSha}"`);
|
|
44777
45186
|
const out = [];
|
|
45187
|
+
if (ctx.requestedBy) out.push(requestedByLine(ctx.requestedBy), "");
|
|
44778
45188
|
out.push(desc.tldr, "");
|
|
44779
45189
|
out.push(`${MAP_LABELS.why} ${desc.why}`, "");
|
|
44780
45190
|
out.push(MAP_LABELS.whereToLook, "");
|
|
@@ -44801,10 +45211,7 @@ function renderPrDescriptionMarkdown(desc, ctx) {
|
|
|
44801
45211
|
...desc.validation.criteria.map((c) => `| ${cell2(c.criterion)} | ${cell2(c.proof)} |`)
|
|
44802
45212
|
])
|
|
44803
45213
|
);
|
|
44804
|
-
const agentLines = [
|
|
44805
|
-
...desc.agentNotes ? [desc.agentNotes] : [],
|
|
44806
|
-
...ctx.requestedBy ? [requestedByLine(ctx.requestedBy)] : []
|
|
44807
|
-
];
|
|
45214
|
+
const agentLines = desc.agentNotes ? [desc.agentNotes] : [];
|
|
44808
45215
|
if (agentLines.length > 0) out.push(...details(FOLD_SUMMARIES.agents, agentLines));
|
|
44809
45216
|
out.push(GENERATED_FOOTER, "");
|
|
44810
45217
|
return out.join("\n");
|
|
@@ -44812,6 +45219,8 @@ function renderPrDescriptionMarkdown(desc, ctx) {
|
|
|
44812
45219
|
function parsePrDescriptionMarkdown(body) {
|
|
44813
45220
|
const problems = [];
|
|
44814
45221
|
const lines = body.replace(/\r\n?/g, "\n").split("\n").filter((l) => l.trim() !== GENERATED_FOOTER);
|
|
45222
|
+
if (/^Requested by \*\*(?:\\.|[^*\\])+\*\*(?: · \[Thread\]\([^\s)]+\))?(?:; steered by .*)?$/.test(lines[0] ?? ""))
|
|
45223
|
+
lines.shift();
|
|
44815
45224
|
const fenced = fenceMask(lines);
|
|
44816
45225
|
const description = { pointers: [] };
|
|
44817
45226
|
if (lines.some((l, i) => !fenced[i] && /^##\s+Tour\s*$/i.test(l))) {
|
|
@@ -46012,12 +46421,12 @@ var init_contract4 = __esm({
|
|
|
46012
46421
|
};
|
|
46013
46422
|
RELAUNCH_CEILING = 2;
|
|
46014
46423
|
HarnessContainerReplacedError = class extends HarnessInterruptedError {
|
|
46015
|
-
constructor(message4, said2, was, now,
|
|
46424
|
+
constructor(message4, said2, was, now, record3, condition = "word") {
|
|
46016
46425
|
super(message4, "container replaced under the run", "container_replaced");
|
|
46017
46426
|
this.said = said2;
|
|
46018
46427
|
this.was = was;
|
|
46019
46428
|
this.now = now;
|
|
46020
|
-
this.record =
|
|
46429
|
+
this.record = record3;
|
|
46021
46430
|
this.condition = condition;
|
|
46022
46431
|
this.name = "HarnessContainerReplacedError";
|
|
46023
46432
|
if (condition !== "identity" !== (said2 !== void 0))
|
|
@@ -46104,11 +46513,11 @@ async function prepareRelaunch(deps, ctx) {
|
|
|
46104
46513
|
} else {
|
|
46105
46514
|
ctx.saveFacts(written);
|
|
46106
46515
|
}
|
|
46107
|
-
const { deadline, ...
|
|
46516
|
+
const { deadline, ...record3 } = replaced.record;
|
|
46108
46517
|
return {
|
|
46109
46518
|
kind: "relaunch",
|
|
46110
46519
|
resume: {
|
|
46111
|
-
...
|
|
46520
|
+
...record3,
|
|
46112
46521
|
remainingMs: Math.max(0, deadline - ctx.clock()),
|
|
46113
46522
|
facts: written,
|
|
46114
46523
|
relaunch: {
|
|
@@ -47271,7 +47680,7 @@ var init_runBearers = __esm({
|
|
|
47271
47680
|
* after `record` returned would carry the old hash ahead of the new one.
|
|
47272
47681
|
* Refuses by name the runs `issue` mints nothing for, and hands `record`
|
|
47273
47682
|
* nothing then. */
|
|
47274
|
-
rotate(runId3,
|
|
47683
|
+
rotate(runId3, record3) {
|
|
47275
47684
|
const entry = this.entries.get(runId3);
|
|
47276
47685
|
if (!entry) return { ok: false, reason: "unknown_run" };
|
|
47277
47686
|
if (entry.revoked) return { ok: false, reason: "revoked" };
|
|
@@ -47279,7 +47688,7 @@ var init_runBearers = __esm({
|
|
|
47279
47688
|
const secret2 = randomBytes4(SECRET_BYTES);
|
|
47280
47689
|
const hash = hashOf(secret2);
|
|
47281
47690
|
entry.hashes.push(hash);
|
|
47282
|
-
|
|
47691
|
+
record3(hash.toString("hex"));
|
|
47283
47692
|
entry.hashes = [hash];
|
|
47284
47693
|
return { ok: true, token: token(runId3, secret2), expiresAt: entry.grant.expiresAt };
|
|
47285
47694
|
}
|
|
@@ -48715,6 +49124,11 @@ var init_mirror = __esm({
|
|
|
48715
49124
|
seedEchoPending = false;
|
|
48716
49125
|
mirroredTail;
|
|
48717
49126
|
iteration = 0;
|
|
49127
|
+
/** The loop counters on the last transcript-bearing step. A cursor-only
|
|
49128
|
+
* checkpoint repeats them so a post-loop turn cannot become part of the
|
|
49129
|
+
* resumable model loop merely by consuming a control row. */
|
|
49130
|
+
lastTurn = 0;
|
|
49131
|
+
lastIteration = 0;
|
|
48718
49132
|
/** The rows written since the mirror started, and the compaction entries
|
|
48719
49133
|
* among them by position — kept whether or not the ledger is wired, so
|
|
48720
49134
|
* the harness holds this generation's copy of the record it wrote
|
|
@@ -48824,6 +49238,8 @@ var init_mirror = __esm({
|
|
|
48824
49238
|
inboxConsumedSeq: this.inboxConsumedSeq,
|
|
48825
49239
|
...this.inboxDeferred()
|
|
48826
49240
|
};
|
|
49241
|
+
this.lastTurn = report2.turn;
|
|
49242
|
+
this.lastIteration = report2.iteration;
|
|
48827
49243
|
this.idx += turns.length;
|
|
48828
49244
|
this.lastAssistantIdx = this.idx - 1;
|
|
48829
49245
|
this.rows.push(...turns);
|
|
@@ -48852,6 +49268,8 @@ var init_mirror = __esm({
|
|
|
48852
49268
|
inboxConsumedSeq: this.inboxConsumedSeq,
|
|
48853
49269
|
...this.inboxDeferred()
|
|
48854
49270
|
};
|
|
49271
|
+
this.lastTurn = report2.turn;
|
|
49272
|
+
this.lastIteration = report2.iteration;
|
|
48855
49273
|
this.idx += turns.length + 1;
|
|
48856
49274
|
this.rows.push(...turns);
|
|
48857
49275
|
this.compactionRows.push({ before: this.rows.length, entry });
|
|
@@ -48859,6 +49277,22 @@ var init_mirror = __esm({
|
|
|
48859
49277
|
await this.deps.onStep(report2);
|
|
48860
49278
|
return true;
|
|
48861
49279
|
}
|
|
49280
|
+
/** Persist only the inbox cursor and its deferred exceptions. Post-loop
|
|
49281
|
+
* turns deliberately stay out of the resumable transcript, but a control
|
|
49282
|
+
* row they consume must survive a bot restart just as a loop step does. */
|
|
49283
|
+
async checkpointInbox() {
|
|
49284
|
+
if (!this.deps.onStep) return;
|
|
49285
|
+
await this.deps.onStep({
|
|
49286
|
+
turns: [],
|
|
49287
|
+
firstIdx: this.idx,
|
|
49288
|
+
inFlight: [],
|
|
49289
|
+
turn: this.lastTurn,
|
|
49290
|
+
iteration: this.lastIteration,
|
|
49291
|
+
remainingMs: Math.max(0, this.deps.remainingMs()),
|
|
49292
|
+
inboxConsumedSeq: this.inboxConsumedSeq,
|
|
49293
|
+
...this.inboxDeferred()
|
|
49294
|
+
});
|
|
49295
|
+
}
|
|
48862
49296
|
};
|
|
48863
49297
|
}
|
|
48864
49298
|
});
|
|
@@ -49057,6 +49491,82 @@ var init_process = __esm({
|
|
|
49057
49491
|
}
|
|
49058
49492
|
});
|
|
49059
49493
|
|
|
49494
|
+
// ../../src/core/providerToolSchemas.ts
|
|
49495
|
+
function responsesRejectsPattern(pattern) {
|
|
49496
|
+
return /\(\?(?:[=!]|<[=!])/.test(pattern);
|
|
49497
|
+
}
|
|
49498
|
+
function shapeResponsesSchema(value, tool, degradations) {
|
|
49499
|
+
const schema = record(value);
|
|
49500
|
+
if (!schema) {
|
|
49501
|
+
if (!Array.isArray(value)) return { value, changed: false };
|
|
49502
|
+
let changed2 = false;
|
|
49503
|
+
const items = value.map((item) => {
|
|
49504
|
+
const shaped = shapeResponsesSchema(item, tool, degradations);
|
|
49505
|
+
changed2 ||= shaped.changed;
|
|
49506
|
+
return shaped.value;
|
|
49507
|
+
});
|
|
49508
|
+
return { value: changed2 ? items : value, changed: changed2 };
|
|
49509
|
+
}
|
|
49510
|
+
let changed = false;
|
|
49511
|
+
const out = {};
|
|
49512
|
+
for (const [keyword, item] of Object.entries(schema)) {
|
|
49513
|
+
if (keyword === "pattern" && typeof item === "string" && responsesRejectsPattern(item)) {
|
|
49514
|
+
degradations.push({
|
|
49515
|
+
tool,
|
|
49516
|
+
keyword,
|
|
49517
|
+
why: "the Responses wire does not accept regular-expression lookaround"
|
|
49518
|
+
});
|
|
49519
|
+
changed = true;
|
|
49520
|
+
continue;
|
|
49521
|
+
}
|
|
49522
|
+
if ((keyword === "properties" || keyword === "$defs" || keyword === "definitions") && record(item)) {
|
|
49523
|
+
let mapChanged = false;
|
|
49524
|
+
const mapped = {};
|
|
49525
|
+
for (const [name, child] of Object.entries(record(item))) {
|
|
49526
|
+
const shaped = shapeResponsesSchema(child, tool, degradations);
|
|
49527
|
+
mapChanged ||= shaped.changed;
|
|
49528
|
+
mapped[name] = shaped.value;
|
|
49529
|
+
}
|
|
49530
|
+
out[keyword] = mapChanged ? mapped : item;
|
|
49531
|
+
changed ||= mapChanged;
|
|
49532
|
+
continue;
|
|
49533
|
+
}
|
|
49534
|
+
if (["additionalProperties", "allOf", "anyOf", "if", "items", "not", "oneOf", "then", "else"].includes(keyword) && typeof item === "object" && item !== null) {
|
|
49535
|
+
const shaped = shapeResponsesSchema(item, tool, degradations);
|
|
49536
|
+
out[keyword] = shaped.value;
|
|
49537
|
+
changed ||= shaped.changed;
|
|
49538
|
+
continue;
|
|
49539
|
+
}
|
|
49540
|
+
out[keyword] = item;
|
|
49541
|
+
}
|
|
49542
|
+
return { value: changed ? out : value, changed };
|
|
49543
|
+
}
|
|
49544
|
+
function shapeToolSchemasForWire(shape, body) {
|
|
49545
|
+
if (shape !== "openai-responses" || !Array.isArray(body.tools)) return { body, degradations: [] };
|
|
49546
|
+
const degradations = [];
|
|
49547
|
+
let changed = false;
|
|
49548
|
+
const tools = body.tools.map((item) => {
|
|
49549
|
+
const tool = record(item);
|
|
49550
|
+
if (!tool) return item;
|
|
49551
|
+
const name = typeof tool.name === "string" ? tool.name : "unnamed";
|
|
49552
|
+
const shaped = shapeResponsesSchema(tool.parameters, name, degradations);
|
|
49553
|
+
if (!shaped.changed) return item;
|
|
49554
|
+
changed = true;
|
|
49555
|
+
return { ...tool, parameters: shaped.value };
|
|
49556
|
+
});
|
|
49557
|
+
const unique = degradations.filter(
|
|
49558
|
+
(candidate, index, all) => all.findIndex((other) => other.tool === candidate.tool && other.keyword === candidate.keyword) === index
|
|
49559
|
+
);
|
|
49560
|
+
return { body: changed ? { ...body, tools } : body, degradations: unique };
|
|
49561
|
+
}
|
|
49562
|
+
var record;
|
|
49563
|
+
var init_providerToolSchemas = __esm({
|
|
49564
|
+
"../../src/core/providerToolSchemas.ts"() {
|
|
49565
|
+
"use strict";
|
|
49566
|
+
record = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
49567
|
+
}
|
|
49568
|
+
});
|
|
49569
|
+
|
|
49060
49570
|
// ../../src/core/harness/piAi.ts
|
|
49061
49571
|
import { anthropicMessagesApi } from "@earendil-works/pi-ai/api/anthropic-messages.lazy";
|
|
49062
49572
|
import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completions.lazy";
|
|
@@ -49224,6 +49734,7 @@ var init_piAi = __esm({
|
|
|
49224
49734
|
"../../src/core/harness/piAi.ts"() {
|
|
49225
49735
|
"use strict";
|
|
49226
49736
|
init_provider();
|
|
49737
|
+
init_providerToolSchemas();
|
|
49227
49738
|
init_secrets2();
|
|
49228
49739
|
init_clock();
|
|
49229
49740
|
ANTHROPIC_BASE_URL = "https://api.anthropic.com";
|
|
@@ -49311,7 +49822,10 @@ var init_piAi = __esm({
|
|
|
49311
49822
|
...this.fetchImpl ? { fetch: this.fetchImpl } : {}
|
|
49312
49823
|
};
|
|
49313
49824
|
try {
|
|
49314
|
-
const
|
|
49825
|
+
const context = toPiContext(req, model, this.clock);
|
|
49826
|
+
const wire = this.api === "openai-completions" ? "openai-chat" : this.api;
|
|
49827
|
+
const shaped = shapeToolSchemasForWire(wire, context);
|
|
49828
|
+
const message4 = await this.api$().stream(model, shaped.body, options).result();
|
|
49315
49829
|
return fromPiMessage(message4, this.name, req.tools);
|
|
49316
49830
|
} catch (err2) {
|
|
49317
49831
|
const failure2 = providerFailureOf(err2);
|
|
@@ -50388,6 +50902,7 @@ async function runPiHarnessOpen(deps, run2) {
|
|
|
50388
50902
|
let parkSettled = false;
|
|
50389
50903
|
let pendingReissue = [];
|
|
50390
50904
|
let reissueInFlight;
|
|
50905
|
+
let reissueInFlightRows = [];
|
|
50391
50906
|
let reissues = 0;
|
|
50392
50907
|
let providerRetryReady = false;
|
|
50393
50908
|
let providerRetryWait;
|
|
@@ -50400,20 +50915,21 @@ async function runPiHarnessOpen(deps, run2) {
|
|
|
50400
50915
|
providerRetryWait = void 0;
|
|
50401
50916
|
providerRetryGeneration += 1;
|
|
50402
50917
|
pendingReissue = [];
|
|
50918
|
+
reissueInFlightRows = [];
|
|
50403
50919
|
};
|
|
50404
50920
|
const maybeReissue = () => {
|
|
50405
50921
|
if (heldTurn === void 0 || !parkSettled || reissueInFlight !== void 0 || retryInFlight !== void 0)
|
|
50406
50922
|
return;
|
|
50407
50923
|
if (pendingReissue.length === 0) return;
|
|
50408
50924
|
if (loopEnded || hardStopped || writeUp !== void 0 || finaleAborted) return;
|
|
50409
|
-
|
|
50925
|
+
reissueInFlightRows = pendingReissue.splice(0);
|
|
50410
50926
|
reissues += 1;
|
|
50411
50927
|
const id = reissues === 1 ? `${ids.prompt}:reissue` : `${ids.prompt}:reissue:${reissues}`;
|
|
50412
50928
|
reissueInFlight = id;
|
|
50413
50929
|
unechoed.push({
|
|
50414
50930
|
message: REISSUE_PROMPT,
|
|
50415
|
-
seq: Math.max(0, ...
|
|
50416
|
-
inputs:
|
|
50931
|
+
seq: Math.max(0, ...reissueInFlightRows.map((i) => i.ledgerSeq ?? 0)),
|
|
50932
|
+
inputs: reissueInFlightRows
|
|
50417
50933
|
});
|
|
50418
50934
|
sends.send({ id, type: "prompt", message: REISSUE_PROMPT });
|
|
50419
50935
|
};
|
|
@@ -50674,16 +51190,29 @@ ${stagedLine}` : prompt;
|
|
|
50674
51190
|
save();
|
|
50675
51191
|
}
|
|
50676
51192
|
if (reissueInFlight !== void 0 && r.id === reissueInFlight) {
|
|
50677
|
-
reissueInFlight = void 0;
|
|
50678
51193
|
if (r.success === false) {
|
|
51194
|
+
reissueInFlight = void 0;
|
|
50679
51195
|
parkSettled = false;
|
|
50680
51196
|
const at = unechoed.findIndex((u) => u.message === REISSUE_PROMPT);
|
|
50681
|
-
if (at >= 0)
|
|
51197
|
+
if (at >= 0) unechoed.splice(at, 1);
|
|
51198
|
+
pendingReissue.push(...reissueInFlightRows);
|
|
51199
|
+
reissueInFlightRows = [];
|
|
50682
51200
|
note(
|
|
50683
51201
|
"harness_error",
|
|
50684
51202
|
`the reissue prompt was refused (${String(r.error ?? "no reason")}); the turn stays held for the next settle`
|
|
50685
51203
|
);
|
|
50686
51204
|
} else {
|
|
51205
|
+
drainFollowUps2();
|
|
51206
|
+
await steers;
|
|
51207
|
+
const at = unechoed.findIndex((u) => u.message === REISSUE_PROMPT);
|
|
51208
|
+
if (at >= 0) unechoed.splice(at, 1);
|
|
51209
|
+
mirror.inboxConsumedSeq = Math.max(
|
|
51210
|
+
mirror.inboxConsumedSeq,
|
|
51211
|
+
...reissueInFlightRows.map((item) => item.ledgerSeq ?? 0),
|
|
51212
|
+
...pendingReissue.map((item) => item.ledgerSeq ?? 0)
|
|
51213
|
+
);
|
|
51214
|
+
await mirror.checkpointInbox();
|
|
51215
|
+
reissueInFlight = void 0;
|
|
50687
51216
|
clearProviderHold();
|
|
50688
51217
|
}
|
|
50689
51218
|
}
|
|
@@ -50692,7 +51221,16 @@ ${stagedLine}` : prompt;
|
|
|
50692
51221
|
if (r.success === false) {
|
|
50693
51222
|
parkSettled = false;
|
|
50694
51223
|
note("harness_error", "the model retry prompt was refused; the transport failure remains held");
|
|
50695
|
-
} else
|
|
51224
|
+
} else {
|
|
51225
|
+
drainFollowUps2();
|
|
51226
|
+
await steers;
|
|
51227
|
+
mirror.inboxConsumedSeq = Math.max(
|
|
51228
|
+
mirror.inboxConsumedSeq,
|
|
51229
|
+
...pendingReissue.map((item) => item.ledgerSeq ?? 0)
|
|
51230
|
+
);
|
|
51231
|
+
await mirror.checkpointInbox();
|
|
51232
|
+
clearProviderHold();
|
|
51233
|
+
}
|
|
50696
51234
|
}
|
|
50697
51235
|
if (r.id === ids.prompt) {
|
|
50698
51236
|
catchingUp = false;
|
|
@@ -50926,8 +51464,8 @@ ${stagedLine}` : prompt;
|
|
|
50926
51464
|
return;
|
|
50927
51465
|
}
|
|
50928
51466
|
const reissued = inputs.filter((item) => item.userId === PLANE_ACTOR_ID && isReissueSteerText(item.text));
|
|
50929
|
-
const
|
|
50930
|
-
if (
|
|
51467
|
+
const waiting3 = reissued.length === 0 ? inputs : inputs.filter((item) => !reissued.includes(item));
|
|
51468
|
+
if (waiting3.length > 0) run2.inbox?.requeue(waiting3);
|
|
50931
51469
|
for (const item of reissued) {
|
|
50932
51470
|
emit({
|
|
50933
51471
|
type: "input",
|
|
@@ -51049,10 +51587,13 @@ ${stagedLine}` : prompt;
|
|
|
51049
51587
|
`the follow-up turn's reissue prompt was refused (${String(obs.response.error ?? "no reason")}); the turn stays held for the next settle`
|
|
51050
51588
|
);
|
|
51051
51589
|
} else {
|
|
51590
|
+
drainTurnReissues();
|
|
51052
51591
|
mirror.inboxConsumedSeq = Math.max(
|
|
51053
51592
|
mirror.inboxConsumedSeq,
|
|
51054
|
-
...turnReissueInFlightRows.map((item) => item.ledgerSeq ?? 0)
|
|
51593
|
+
...turnReissueInFlightRows.map((item) => item.ledgerSeq ?? 0),
|
|
51594
|
+
...turnReissueRows.map((item) => item.ledgerSeq ?? 0)
|
|
51055
51595
|
);
|
|
51596
|
+
await mirror.checkpointInbox();
|
|
51056
51597
|
clearTurnProviderHold();
|
|
51057
51598
|
}
|
|
51058
51599
|
}
|
|
@@ -51067,6 +51608,7 @@ ${stagedLine}` : prompt;
|
|
|
51067
51608
|
mirror.inboxConsumedSeq,
|
|
51068
51609
|
...turnReissueRows.map((item) => item.ledgerSeq ?? 0)
|
|
51069
51610
|
);
|
|
51611
|
+
await mirror.checkpointInbox();
|
|
51070
51612
|
clearTurnProviderHold();
|
|
51071
51613
|
}
|
|
51072
51614
|
}
|
|
@@ -51234,13 +51776,13 @@ var init_harness = __esm({
|
|
|
51234
51776
|
}
|
|
51235
51777
|
};
|
|
51236
51778
|
PiContainerReplacedError = class extends HarnessContainerReplacedError {
|
|
51237
|
-
constructor(said2, was, now,
|
|
51779
|
+
constructor(said2, was, now, record3, condition = "word") {
|
|
51238
51780
|
super(
|
|
51239
51781
|
condition === "transport" ? `the container running pi stopped answering (${was ?? "unknown"}; ${replacedBecause(condition, said2)})` : `the container running pi was replaced (${was ?? "unknown"} \u2192 ${now ?? "unknown"}; ${replacedBecause(condition, said2)})`,
|
|
51240
51782
|
said2,
|
|
51241
51783
|
was,
|
|
51242
51784
|
now,
|
|
51243
|
-
|
|
51785
|
+
record3,
|
|
51244
51786
|
condition
|
|
51245
51787
|
);
|
|
51246
51788
|
this.name = "PiContainerReplacedError";
|
|
@@ -51451,14 +51993,17 @@ var init_resume = __esm({
|
|
|
51451
51993
|
|
|
51452
51994
|
// ../../src/execution/githubComments.ts
|
|
51453
51995
|
async function postReviewComment(target, body) {
|
|
51996
|
+
const codePoints = [...body].length;
|
|
51997
|
+
if (codePoints > MAX_REVIEW_POST_CODE_POINTS) {
|
|
51998
|
+
throw new Error(
|
|
51999
|
+
`PR review body is ${codePoints} Unicode code points, over the ${MAX_REVIEW_POST_CODE_POINTS} limit; refusing to clip the structured verdict`
|
|
52000
|
+
);
|
|
52001
|
+
}
|
|
51454
52002
|
const token2 = await resolveGithubToken();
|
|
51455
52003
|
if (!token2) {
|
|
51456
52004
|
throw new Error("no GitHub credential available to post the PR review comment");
|
|
51457
52005
|
}
|
|
51458
|
-
const
|
|
51459
|
-
|
|
51460
|
-
_(review truncated to fit GitHub's comment size limit)_` : body;
|
|
51461
|
-
const payload2 = { event: "COMMENT", body: clipped };
|
|
52006
|
+
const payload2 = { event: "COMMENT", body };
|
|
51462
52007
|
if (target.commitId) payload2.commit_id = target.commitId;
|
|
51463
52008
|
const res = await fetch(`https://api.github.com/repos/${target.repo}/pulls/${target.number}/reviews`, {
|
|
51464
52009
|
method: "POST",
|
|
@@ -51476,13 +52021,12 @@ _(review truncated to fit GitHub's comment size limit)_` : body;
|
|
|
51476
52021
|
throw new Error(`PR comment post failed: HTTP ${res.status} ${redactAndCap(text, 300)}`);
|
|
51477
52022
|
}
|
|
51478
52023
|
}
|
|
51479
|
-
var MAX_COMMENT_CHARS;
|
|
51480
52024
|
var init_githubComments = __esm({
|
|
51481
52025
|
"../../src/execution/githubComments.ts"() {
|
|
51482
52026
|
"use strict";
|
|
51483
52027
|
init_githubApp();
|
|
51484
52028
|
init_redact();
|
|
51485
|
-
|
|
52029
|
+
init_reviewVerdict();
|
|
51486
52030
|
}
|
|
51487
52031
|
});
|
|
51488
52032
|
|
|
@@ -51534,13 +52078,13 @@ function parsedPrDescriptionArtifact(facts2, ctx) {
|
|
|
51534
52078
|
async function findSubmittedPrDescription(store, key, limit = SUBMITTED_LOOKUP_LIMIT) {
|
|
51535
52079
|
const rows = await store.list({ limit, visibleTo: { kind: "repos-in", repos: [key.repo] } });
|
|
51536
52080
|
for (const row2 of rows) {
|
|
51537
|
-
const
|
|
51538
|
-
if (!
|
|
51539
|
-
for (let i =
|
|
51540
|
-
const ev =
|
|
52081
|
+
const record3 = await store.get(row2.id);
|
|
52082
|
+
if (!record3) continue;
|
|
52083
|
+
for (let i = record3.events.length - 1; i >= 0; i--) {
|
|
52084
|
+
const ev = record3.events[i];
|
|
51541
52085
|
if (ev.type === "review_artifact" && ev.artifact === "pr_description" && ev.origin === "submitted" && ev.repo === key.repo && ev.pr === key.pr && ev.headSha === key.headSha) {
|
|
51542
52086
|
const { type: _type, seq: _seq, at: _at, ...artifact } = ev;
|
|
51543
|
-
return { artifact: { ...artifact, fromRunId: artifact.fromRunId ??
|
|
52087
|
+
return { artifact: { ...artifact, fromRunId: artifact.fromRunId ?? record3.id }, runId: record3.id };
|
|
51544
52088
|
}
|
|
51545
52089
|
}
|
|
51546
52090
|
}
|
|
@@ -51803,7 +52347,7 @@ async function runCodingPrPostStep(input) {
|
|
|
51803
52347
|
});
|
|
51804
52348
|
}
|
|
51805
52349
|
const ownPr = target.ownPr;
|
|
51806
|
-
const requestedBy = input.
|
|
52350
|
+
const requestedBy = input.requestedBy;
|
|
51807
52351
|
const onOwnPrBranch = ownPr?.headBranch !== void 0 && branch2 === ownPr.headBranch;
|
|
51808
52352
|
const pushedPastOwnPr = ownPr !== void 0 && onOwnPrBranch && pushed && headSha !== void 0 && !sameCommit(headSha, ownPr.headSha) ? headSha : void 0;
|
|
51809
52353
|
if (prDescription && ownPr !== void 0 && ownPr.state !== "open" && pushedPastOwnPr !== void 0 && branch2 !== void 0) {
|
|
@@ -52014,16 +52558,17 @@ async function runCodingPrPostStep(input) {
|
|
|
52014
52558
|
);
|
|
52015
52559
|
}
|
|
52016
52560
|
}
|
|
52017
|
-
|
|
52018
|
-
|
|
52561
|
+
const requestedLogin = input.identity.requestedLogin;
|
|
52562
|
+
if (requestedLogin !== void 0) {
|
|
52563
|
+
const assignable = await input.identity.isAssignable(repo, requestedLogin).catch(() => void 0);
|
|
52019
52564
|
if (assignable === true)
|
|
52020
|
-
await input.identity.addAssignee(repo, opened.number,
|
|
52565
|
+
await input.identity.addAssignee(repo, opened.number, requestedLogin).catch(
|
|
52021
52566
|
(err2) => console.error(
|
|
52022
|
-
`[pr-post] ${logKey} assignee add failed for ${
|
|
52567
|
+
`[pr-post] ${logKey} assignee add failed for ${requestedLogin} on ${repo}#${opened.number}: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
52023
52568
|
)
|
|
52024
52569
|
);
|
|
52025
52570
|
else if (assignable === false)
|
|
52026
|
-
console.log(`[identity] ${logKey} ${
|
|
52571
|
+
console.log(`[identity] ${logKey} ${requestedLogin} is not assignable on ${repo}; skipped`);
|
|
52027
52572
|
}
|
|
52028
52573
|
}
|
|
52029
52574
|
console.log(
|
|
@@ -52399,6 +52944,7 @@ async function runLoop(deps, ctx) {
|
|
|
52399
52944
|
coordinator,
|
|
52400
52945
|
seed
|
|
52401
52946
|
} = ctx;
|
|
52947
|
+
const events = ctx.events ?? new RunEventLane((event) => registry.publish(run2.id, event));
|
|
52402
52948
|
const agent = budgetedAgent(ctx.agent, profile);
|
|
52403
52949
|
const { round: round2 } = ctx;
|
|
52404
52950
|
let { executor } = round2.selection;
|
|
@@ -52472,13 +53018,11 @@ async function runLoop(deps, ctx) {
|
|
|
52472
53018
|
const pushes = trackPushedBranch(typeof restored.pushedBranch === "string" ? restored.pushedBranch : void 0);
|
|
52473
53019
|
let budgetEnded = false;
|
|
52474
53020
|
let recordedPushedBranch;
|
|
52475
|
-
|
|
53021
|
+
let modelBudgetEndsAt;
|
|
53022
|
+
const publishEvent = (e, startsRunBudget) => {
|
|
52476
53023
|
registry.publish(run2.id, e);
|
|
52477
53024
|
if (isSpanRecord(e)) return;
|
|
52478
|
-
if (
|
|
52479
|
-
run2.control.startLease(() => e.endsAt - clock4());
|
|
52480
|
-
return;
|
|
52481
|
-
}
|
|
53025
|
+
if (startsRunBudget) return;
|
|
52482
53026
|
if (e.type === "tool_call") toolCalls++;
|
|
52483
53027
|
if (e.type === "run_note" && e.kind === "time_budget_exhausted") budgetEnded = true;
|
|
52484
53028
|
if (isCodingPrRun) {
|
|
@@ -52498,6 +53042,47 @@ async function runLoop(deps, ctx) {
|
|
|
52498
53042
|
lastActivity = bookkeeping && !showBookkeeping ? void 0 : cardActivity(e);
|
|
52499
53043
|
card.update(currentFrame());
|
|
52500
53044
|
};
|
|
53045
|
+
const onEvent = (e) => {
|
|
53046
|
+
const startsRunBudget = e.type === "lease";
|
|
53047
|
+
if (startsRunBudget) {
|
|
53048
|
+
modelBudgetEndsAt = e.endsAt;
|
|
53049
|
+
run2.control.startLease(() => e.endsAt - clock4());
|
|
53050
|
+
}
|
|
53051
|
+
void events.write(async () => {
|
|
53052
|
+
if ((e.type === "tool_call" || e.type === "tool_result") && typeof registry.commitLiveState === "function") {
|
|
53053
|
+
const summary = registry.getById(run2.id);
|
|
53054
|
+
if (summary?.liveState?.state === "working") {
|
|
53055
|
+
const at = e.at ?? clock4();
|
|
53056
|
+
const bound = e.type === "tool_call" && e.boundMs !== void 0 ? at + e.boundMs : modelBudgetEndsAt ?? summary.liveState.bound;
|
|
53057
|
+
if (bound !== void 0) {
|
|
53058
|
+
const sourceSeq = summary.eventCount + 1;
|
|
53059
|
+
const assignment = {
|
|
53060
|
+
expectedSeq: summary.liveStateSeq ?? 0,
|
|
53061
|
+
at,
|
|
53062
|
+
state: "working",
|
|
53063
|
+
bound,
|
|
53064
|
+
detail: e.type === "tool_call" ? "running a tool" : "model turn",
|
|
53065
|
+
sourceEvents: [{ ...e, seq: sourceSeq }]
|
|
53066
|
+
};
|
|
53067
|
+
try {
|
|
53068
|
+
if (ledgerRun?.tracked()) {
|
|
53069
|
+
const committed = await ledgerRun.assignLiveState(assignment);
|
|
53070
|
+
if (committed.ok) registry.commitLiveState(run2.id, committed);
|
|
53071
|
+
} else {
|
|
53072
|
+
const local = assignRunLiveState(summary.liveState, summary.liveStateSeq ?? 0, assignment);
|
|
53073
|
+
if (local.ok) registry.commitLiveState(run2.id, { ...local, liveStateSeq: sourceSeq });
|
|
53074
|
+
}
|
|
53075
|
+
} catch (err2) {
|
|
53076
|
+
console.warn(
|
|
53077
|
+
`[run] ${msg.threadKey} live-state projection failed: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
53078
|
+
);
|
|
53079
|
+
}
|
|
53080
|
+
}
|
|
53081
|
+
}
|
|
53082
|
+
}
|
|
53083
|
+
publishEvent(e, startsRunBudget);
|
|
53084
|
+
});
|
|
53085
|
+
};
|
|
52501
53086
|
for (const s of mcpForRun?.servers ?? []) {
|
|
52502
53087
|
if (s.unavailable !== void 0)
|
|
52503
53088
|
onEvent({
|
|
@@ -52520,14 +53105,14 @@ async function runLoop(deps, ctx) {
|
|
|
52520
53105
|
descriptionArtifact = startReviewDescription({
|
|
52521
53106
|
store: deps.runStore,
|
|
52522
53107
|
repoCtx,
|
|
52523
|
-
publish: (
|
|
53108
|
+
publish: (event) => events.publish(event)
|
|
52524
53109
|
});
|
|
52525
53110
|
readingDiffBaseline = startReviewReadingDiff({
|
|
52526
53111
|
executor,
|
|
52527
53112
|
cfg: deps.config.config.review?.readingDiff,
|
|
52528
53113
|
env: publicEnv(),
|
|
52529
53114
|
baseRef: repoCtx.baseRef,
|
|
52530
|
-
publish: (
|
|
53115
|
+
publish: (event) => events.publish(event),
|
|
52531
53116
|
parent: root
|
|
52532
53117
|
}).baseline.then((published) => {
|
|
52533
53118
|
console.log(`[reading-diff] ${msg.threadKey} baseline ${published ? "published" : "none"}`);
|
|
@@ -52599,10 +53184,11 @@ async function runLoop(deps, ctx) {
|
|
|
52599
53184
|
if (interrupted === void 0) runFailed = true;
|
|
52600
53185
|
throw err2;
|
|
52601
53186
|
} finally {
|
|
53187
|
+
await events.drain();
|
|
52602
53188
|
const calls = callsInFlight(recordEvents(), statusNow());
|
|
52603
53189
|
commandInFlight = calls.length > 0;
|
|
52604
53190
|
if (commandInFlight)
|
|
52605
|
-
|
|
53191
|
+
events.publish({
|
|
52606
53192
|
type: "run_note",
|
|
52607
53193
|
kind: "workspace_torn_down",
|
|
52608
53194
|
summary: redactAndCap(
|
|
@@ -52676,12 +53262,12 @@ async function runLoop(deps, ctx) {
|
|
|
52676
53262
|
let reviewStoppedBeforeStart = false;
|
|
52677
53263
|
const latchReviewStoppedBeforeStart = () => {
|
|
52678
53264
|
if (reviewStoppedBeforeStart || agent.name !== "review") return reviewStoppedBeforeStart;
|
|
52679
|
-
const
|
|
52680
|
-
const stopAt =
|
|
53265
|
+
const events2 = recordEvents();
|
|
53266
|
+
const stopAt = events2.findIndex(
|
|
52681
53267
|
(event) => event.type === "run_note" && (event.kind === "stop_requested" || event.kind === "stopped")
|
|
52682
53268
|
);
|
|
52683
53269
|
if (stopAt < 0) return false;
|
|
52684
|
-
reviewStoppedBeforeStart = !
|
|
53270
|
+
reviewStoppedBeforeStart = !events2.slice(0, stopAt).some((event) => event.type === "tool_call" && event.tool !== "update_status");
|
|
52685
53271
|
return reviewStoppedBeforeStart;
|
|
52686
53272
|
};
|
|
52687
53273
|
const clearStoppedReviewTail = () => {
|
|
@@ -52696,8 +53282,8 @@ async function runLoop(deps, ctx) {
|
|
|
52696
53282
|
};
|
|
52697
53283
|
const tailSkipped = () => run2.control.requested === "hard" || relaunchEndedRun || latchReviewStoppedBeforeStart();
|
|
52698
53284
|
const releaseWorkspace = (span) => {
|
|
52699
|
-
const
|
|
52700
|
-
const pushed = pushedBranchesOf(
|
|
53285
|
+
const events2 = recordEvents();
|
|
53286
|
+
const pushed = pushedBranchesOf(events2);
|
|
52701
53287
|
return round2.release({
|
|
52702
53288
|
hardStopped: run2.control.requested === "hard",
|
|
52703
53289
|
commandInFlight,
|
|
@@ -52715,7 +53301,7 @@ async function runLoop(deps, ctx) {
|
|
|
52715
53301
|
const staged = await stageIntoWorkspace(files, {
|
|
52716
53302
|
store: deps.artifacts,
|
|
52717
53303
|
threadKey: msg.threadKey,
|
|
52718
|
-
publish: (
|
|
53304
|
+
publish: (event) => events.publish(event),
|
|
52719
53305
|
nextIndex: nextStagedIndex,
|
|
52720
53306
|
executor,
|
|
52721
53307
|
resident: round2.selection.resident !== void 0
|
|
@@ -52793,9 +53379,9 @@ async function runLoop(deps, ctx) {
|
|
|
52793
53379
|
throw new Error(
|
|
52794
53380
|
`the ${agent.name} preset's run left ${facts2.harness} harness facts on its row, but this process has no harness roster to end that process with`
|
|
52795
53381
|
);
|
|
52796
|
-
const
|
|
53382
|
+
const judge5 = harnessOf(deps.harness);
|
|
52797
53383
|
const container = deps.harness.containerFor?.(executor, profile.machine) ?? harnessContainerFor(executor, profile.machine);
|
|
52798
|
-
const found = await
|
|
53384
|
+
const found = await judge5.find(facts2, container).catch((err2) => {
|
|
52799
53385
|
if (!isContainerGone(err2)) throw err2;
|
|
52800
53386
|
return "gone";
|
|
52801
53387
|
});
|
|
@@ -52820,11 +53406,11 @@ async function runLoop(deps, ctx) {
|
|
|
52820
53406
|
onEvent({
|
|
52821
53407
|
type: "run_note",
|
|
52822
53408
|
kind: "resumed",
|
|
52823
|
-
summary: `the run's row carries ${facts2.harness} harness facts (pid ${facts2.pid}) that the ${
|
|
53409
|
+
summary: `the run's row carries ${facts2.harness} harness facts (pid ${facts2.pid}) that the ${judge5.name} harness does not own: that process was neither judged nor ended here`
|
|
52824
53410
|
});
|
|
52825
53411
|
break;
|
|
52826
53412
|
default:
|
|
52827
|
-
await
|
|
53413
|
+
await judge5.end(facts2, container);
|
|
52828
53414
|
}
|
|
52829
53415
|
} else noteUnknownWord("the run finished on the answer it already had");
|
|
52830
53416
|
windDownEnding = windDownEndingUnder(finish2.answer, loopEnding);
|
|
@@ -53161,7 +53747,7 @@ async function runLoop(deps, ctx) {
|
|
|
53161
53747
|
return { workspace, description: prDescription !== void 0 ? "submitted" : "not_submitted" };
|
|
53162
53748
|
};
|
|
53163
53749
|
if (leftBehind) {
|
|
53164
|
-
|
|
53750
|
+
events.publish({
|
|
53165
53751
|
type: "run_note",
|
|
53166
53752
|
kind: "work_left_behind",
|
|
53167
53753
|
summary: oneLine(workLeftBehindSummary(leftBehind)),
|
|
@@ -53170,14 +53756,16 @@ async function runLoop(deps, ctx) {
|
|
|
53170
53756
|
shell.note("quiet", workLeftBehindLabel(leftBehind));
|
|
53171
53757
|
}
|
|
53172
53758
|
if (prDescription) {
|
|
53173
|
-
|
|
53759
|
+
events.publish({
|
|
53174
53760
|
type: "pr_description",
|
|
53175
53761
|
description: redactPrDescription(prDescription),
|
|
53176
53762
|
at: clock4()
|
|
53177
53763
|
});
|
|
53178
53764
|
}
|
|
53179
53765
|
if (isCodingPrRun && !tailSkipped() && !endingSalvageAttempted) {
|
|
53180
|
-
const
|
|
53766
|
+
const instance = coordinator && deps.coordinatorInstances ? await deps.coordinatorInstances.get(coordinator.parentInstanceId).catch(() => void 0) : void 0;
|
|
53767
|
+
const requester = instance?.userId === msg.userId ? instance : msg;
|
|
53768
|
+
const requestedLogin = identitySeam !== void 0 ? await identitySeam.requestedLogin(requester.userId).catch(() => void 0) : void 0;
|
|
53181
53769
|
prNote = await root.span(
|
|
53182
53770
|
"run.pr_post_step",
|
|
53183
53771
|
() => runCodingPrPostStep({
|
|
@@ -53190,6 +53778,10 @@ async function runLoop(deps, ctx) {
|
|
|
53190
53778
|
remoteRepo: observedRemoteRepo
|
|
53191
53779
|
},
|
|
53192
53780
|
description: prDescription,
|
|
53781
|
+
requestedBy: {
|
|
53782
|
+
name: requester.userName?.trim() || requestedLogin || requester.userId,
|
|
53783
|
+
threadUrl: threadPageLink(requester.threadKey)
|
|
53784
|
+
},
|
|
53193
53785
|
target: prTarget,
|
|
53194
53786
|
openPullRequest: deps.openPullRequest ?? openPullRequest,
|
|
53195
53787
|
findOpenPr: deps.findOpenPrByHead ?? findOpenPrByHead,
|
|
@@ -53202,11 +53794,11 @@ async function runLoop(deps, ctx) {
|
|
|
53202
53794
|
pullRequestHead: identitySeam.pullRequestHead,
|
|
53203
53795
|
isAssignable: identitySeam.isAssignable,
|
|
53204
53796
|
addAssignee: identitySeam.addAssignee,
|
|
53205
|
-
...requestedLogin !== void 0 ? {
|
|
53797
|
+
...requestedLogin !== void 0 ? { requestedLogin } : {}
|
|
53206
53798
|
}
|
|
53207
53799
|
} : {},
|
|
53208
53800
|
descriptionTurnRan,
|
|
53209
|
-
publish: (
|
|
53801
|
+
publish: (event) => events.publish(event),
|
|
53210
53802
|
logKey: msg.threadKey
|
|
53211
53803
|
})
|
|
53212
53804
|
);
|
|
@@ -53244,7 +53836,7 @@ async function runLoop(deps, ctx) {
|
|
|
53244
53836
|
fetchPrHead: deps.fetchPrHead ?? currentPrHeadSha,
|
|
53245
53837
|
reply: (text) => io.reply(text),
|
|
53246
53838
|
ack: (text) => replyAck(io, resolved.verbosity, text),
|
|
53247
|
-
publish: (
|
|
53839
|
+
publish: (event) => events.publish(event),
|
|
53248
53840
|
logKey: msg.threadKey
|
|
53249
53841
|
})
|
|
53250
53842
|
);
|
|
@@ -53255,7 +53847,7 @@ async function runLoop(deps, ctx) {
|
|
|
53255
53847
|
gateBypassed = err2 instanceof HarnessGateBypassedError;
|
|
53256
53848
|
if (err2 instanceof ModelPolicyRefusedError) failure2 = { kind: "policy_refusal" };
|
|
53257
53849
|
else if (err2 instanceof ModelTransientFailureError) failure2 = { kind: "provider_transient" };
|
|
53258
|
-
|
|
53850
|
+
events.publish({
|
|
53259
53851
|
type: "run_note",
|
|
53260
53852
|
kind: "run_failed",
|
|
53261
53853
|
summary: redactAndCap(err2 instanceof Error ? err2.message : String(err2), ENDING_NOTE_MAX)
|
|
@@ -53264,7 +53856,7 @@ async function runLoop(deps, ctx) {
|
|
|
53264
53856
|
await endHarness().catch((endErr) => {
|
|
53265
53857
|
const detail = `the harness session's end failed after the loop's own error: ${endErr instanceof Error ? endErr.message : String(endErr)}`;
|
|
53266
53858
|
console.warn(`[run] ${msg.threadKey} ${detail}`);
|
|
53267
|
-
|
|
53859
|
+
events.publish({
|
|
53268
53860
|
type: "run_note",
|
|
53269
53861
|
kind: "harness_error",
|
|
53270
53862
|
summary: redactAndCap(detail, ENDING_NOTE_MAX),
|
|
@@ -53273,13 +53865,13 @@ async function runLoop(deps, ctx) {
|
|
|
53273
53865
|
});
|
|
53274
53866
|
await preserveCodingChildWork("ending").catch((salvageErr) => {
|
|
53275
53867
|
const summary = `the interrupted-work checkpoint failed before teardown: ${salvageErr instanceof Error ? salvageErr.message : String(salvageErr)}`;
|
|
53276
|
-
|
|
53868
|
+
events.publish({ type: "run_note", kind: "work_salvage", summary, at: clock4() });
|
|
53277
53869
|
shell.note("quiet", summary);
|
|
53278
53870
|
});
|
|
53279
53871
|
await root.span("post.workspace_release", (span) => releaseWorkspace(span));
|
|
53280
53872
|
if (!interrupted) throw err2;
|
|
53281
53873
|
if (coordinator !== void 0)
|
|
53282
|
-
|
|
53874
|
+
events.publish({
|
|
53283
53875
|
type: "child_interrupted",
|
|
53284
53876
|
parentInstanceId: coordinator.parentInstanceId,
|
|
53285
53877
|
reason: redactAndCap(interrupted.message, ENDING_NOTE_MAX),
|
|
@@ -53294,12 +53886,49 @@ async function runLoop(deps, ctx) {
|
|
|
53294
53886
|
};
|
|
53295
53887
|
} finally {
|
|
53296
53888
|
clearInterval(heartbeat);
|
|
53889
|
+
await events.drain();
|
|
53297
53890
|
const status3 = statusNow();
|
|
53891
|
+
if (typeof registry.commitLiveState === "function") {
|
|
53892
|
+
const commitBoundary = async (state, at2) => {
|
|
53893
|
+
const summary = registry.getById(run2.id);
|
|
53894
|
+
if (!summary) return;
|
|
53895
|
+
const eventSeq = summary.eventCount + 1;
|
|
53896
|
+
const assignment = state === "ended" ? {
|
|
53897
|
+
expectedSeq: summary.liveStateSeq ?? 0,
|
|
53898
|
+
eventSeq,
|
|
53899
|
+
at: at2,
|
|
53900
|
+
state,
|
|
53901
|
+
cause: causeOfClose(status3, interrupted !== void 0)
|
|
53902
|
+
} : {
|
|
53903
|
+
expectedSeq: summary.liveStateSeq ?? 0,
|
|
53904
|
+
eventSeq,
|
|
53905
|
+
at: at2,
|
|
53906
|
+
state,
|
|
53907
|
+
bound: summary.liveState?.bound ?? at2,
|
|
53908
|
+
detail: "writing the final answer"
|
|
53909
|
+
};
|
|
53910
|
+
if (ledgerRun?.tracked()) {
|
|
53911
|
+
const committed = await ledgerRun.assignLiveState(assignment);
|
|
53912
|
+
if (committed.ok) registry.commitLiveState(run2.id, committed);
|
|
53913
|
+
return;
|
|
53914
|
+
}
|
|
53915
|
+
const local = assignRunLiveState(summary.liveState, summary.liveStateSeq ?? 0, assignment);
|
|
53916
|
+
if (!local.ok || !local.event) return;
|
|
53917
|
+
registry.commitLiveState(run2.id, {
|
|
53918
|
+
...local,
|
|
53919
|
+
event: { ...local.event, seq: eventSeq },
|
|
53920
|
+
liveStateSeq: eventSeq
|
|
53921
|
+
});
|
|
53922
|
+
};
|
|
53923
|
+
const at = clock4();
|
|
53924
|
+
await commitBoundary("wrapping_up", at);
|
|
53925
|
+
await commitBoundary("ended", clock4());
|
|
53926
|
+
}
|
|
53298
53927
|
registry.finish(run2.id, status3);
|
|
53299
53928
|
const snap = registry.snapshot(run2.id, run2.token);
|
|
53300
|
-
const
|
|
53929
|
+
const recordEventList = snap?.events ?? [];
|
|
53301
53930
|
const finishedAt = snap?.finishedAt ?? clock4();
|
|
53302
|
-
const diagnosis = analyzeRunFriction(
|
|
53931
|
+
const diagnosis = analyzeRunFriction(recordEventList, {
|
|
53303
53932
|
finished: true,
|
|
53304
53933
|
truncated: snap?.truncated ?? false,
|
|
53305
53934
|
window: { start: snap?.receivedAt ?? startedAt, end: finishedAt }
|
|
@@ -53432,10 +54061,13 @@ var init_runLoop = __esm({
|
|
|
53432
54061
|
init_readingDiff();
|
|
53433
54062
|
init_reviewDescription();
|
|
53434
54063
|
init_runEvents();
|
|
54064
|
+
init_runEventLane();
|
|
53435
54065
|
init_redact();
|
|
53436
54066
|
init_runFriction();
|
|
53437
54067
|
init_llmOutput();
|
|
53438
54068
|
init_runRecord();
|
|
54069
|
+
init_runLiveState();
|
|
54070
|
+
init_decide();
|
|
53439
54071
|
init_statusCardLabel();
|
|
53440
54072
|
init_runPace();
|
|
53441
54073
|
init_statusCardFrame();
|
|
@@ -53799,7 +54431,7 @@ async function rowsFor(deps, p, selected, instanceId, carried) {
|
|
|
53799
54431
|
p.graph.units.filter((u) => selected.includes(u.id)).map(async (u) => {
|
|
53800
54432
|
const previous = carried?.get(u.id);
|
|
53801
54433
|
const taskKey = p.recordTasks?.[u.id];
|
|
53802
|
-
const
|
|
54434
|
+
const record3 = taskKey !== void 0 ? await reserve(p.identity.repo, taskKey, previous?.record) : previous?.record;
|
|
53803
54435
|
return {
|
|
53804
54436
|
instanceId,
|
|
53805
54437
|
unit: u.id,
|
|
@@ -53810,7 +54442,7 @@ async function rowsFor(deps, p, selected, instanceId, carried) {
|
|
|
53810
54442
|
rounds: [],
|
|
53811
54443
|
...p.resume !== void 0 ? { resume: p.resume } : {},
|
|
53812
54444
|
...previous?.lastPush !== void 0 ? { lastPush: previous.lastPush } : {},
|
|
53813
|
-
...
|
|
54445
|
+
...record3 !== void 0 ? { record: record3 } : {}
|
|
53814
54446
|
};
|
|
53815
54447
|
})
|
|
53816
54448
|
);
|
|
@@ -54226,7 +54858,11 @@ async function runShipBranch(deps, msg, io, ctx) {
|
|
|
54226
54858
|
return { hostedLive: false };
|
|
54227
54859
|
}
|
|
54228
54860
|
const entry = pre.entry;
|
|
54229
|
-
const
|
|
54861
|
+
const configuredCaps = resolveShipCaps(deps.config.config.ship);
|
|
54862
|
+
const caps = {
|
|
54863
|
+
maxRounds: Math.min(configuredCaps.maxRounds, ctx.reissueCaps?.maxRounds ?? configuredCaps.maxRounds),
|
|
54864
|
+
maxMinutes: Math.min(profile.minutes, ctx.reissueCaps?.maxMinutes ?? profile.minutes)
|
|
54865
|
+
};
|
|
54230
54866
|
const held2 = fit(caps);
|
|
54231
54867
|
if (!held2.ok) {
|
|
54232
54868
|
const reason2 = `budget ${caps.maxMinutes} min cannot hold the ship loop (${caps.maxRounds} review rounds need ${held2.need} min)`;
|
|
@@ -54387,6 +55023,34 @@ async function runShipBranch(deps, msg, io, ctx) {
|
|
|
54387
55023
|
...REPLAY_EVERYTHING
|
|
54388
55024
|
});
|
|
54389
55025
|
}
|
|
55026
|
+
const admittedAt = clock4();
|
|
55027
|
+
const admittedEventSeq = (registry.getById(run2.id)?.eventCount ?? 0) + 1;
|
|
55028
|
+
const admittedAssignment = {
|
|
55029
|
+
expectedSeq: 0,
|
|
55030
|
+
eventSeq: admittedEventSeq,
|
|
55031
|
+
at: admittedAt,
|
|
55032
|
+
state: "admitted",
|
|
55033
|
+
bound: admittedAt + minutesToMs(profile.minutes),
|
|
55034
|
+
detail: "waiting for the pipeline to start"
|
|
55035
|
+
};
|
|
55036
|
+
if (ledgerRun) {
|
|
55037
|
+
const committed = await ledgerRun.assignLiveState(admittedAssignment);
|
|
55038
|
+
if (!committed.ok || !registry.commitLiveState(run2.id, committed))
|
|
55039
|
+
throw new RefusalError(
|
|
55040
|
+
refusalOf(
|
|
55041
|
+
"setup_failed",
|
|
55042
|
+
`hosted live state start was not committed (${committed.ok ? "registry sequence" : committed.reason})`
|
|
55043
|
+
)
|
|
55044
|
+
);
|
|
55045
|
+
} else {
|
|
55046
|
+
const local = assignRunLiveState(void 0, 0, admittedAssignment);
|
|
55047
|
+
if (local.ok && local.event)
|
|
55048
|
+
registry.commitLiveState(run2.id, {
|
|
55049
|
+
...local,
|
|
55050
|
+
event: { ...local.event, seq: admittedEventSeq },
|
|
55051
|
+
liveStateSeq: admittedEventSeq
|
|
55052
|
+
});
|
|
55053
|
+
}
|
|
54390
55054
|
const hostRefused = opened.kind === "untracked" && opened.why === "thread-live";
|
|
54391
55055
|
const liveUrl = liveViewLink(run2.id, run2.token);
|
|
54392
55056
|
ctx.live.runId = run2.id;
|
|
@@ -54457,7 +55121,23 @@ async function runShipBranch(deps, msg, io, ctx) {
|
|
|
54457
55121
|
instanceId: outcome.instanceId,
|
|
54458
55122
|
until: clock4() + minutesToMs(caps.maxMinutes + HOSTED_DEADLINE_MARGIN_MINUTES)
|
|
54459
55123
|
};
|
|
54460
|
-
|
|
55124
|
+
const summary = registry.getById(run2.id);
|
|
55125
|
+
const committed = await ledgerRun.assignLiveState({
|
|
55126
|
+
expectedSeq: summary?.liveStateSeq ?? 0,
|
|
55127
|
+
eventSeq: (summary?.eventCount ?? 0) + 1,
|
|
55128
|
+
at: clock4(),
|
|
55129
|
+
state: "working",
|
|
55130
|
+
bound: hosting.until,
|
|
55131
|
+
detail: HOSTED_PIPELINE_STARTING_DETAIL,
|
|
55132
|
+
statePatch: { hosting }
|
|
55133
|
+
});
|
|
55134
|
+
if (!committed.ok || !registry.commitLiveState(run2.id, committed))
|
|
55135
|
+
throw new RefusalError(
|
|
55136
|
+
refusalOf(
|
|
55137
|
+
"setup_failed",
|
|
55138
|
+
`hosted live state transition was not committed (${committed.ok ? "registry sequence" : committed.reason})`
|
|
55139
|
+
)
|
|
55140
|
+
);
|
|
54461
55141
|
registry.publish(run2.id, {
|
|
54462
55142
|
type: "run_meta",
|
|
54463
55143
|
agent: agent.name,
|
|
@@ -54565,6 +55245,8 @@ var init_ship = __esm({
|
|
|
54565
55245
|
init_runFriction();
|
|
54566
55246
|
init_run2();
|
|
54567
55247
|
init_runRegistry();
|
|
55248
|
+
init_runLiveState();
|
|
55249
|
+
init_pipelineStanding();
|
|
54568
55250
|
init_statusCardFrame();
|
|
54569
55251
|
init_types5();
|
|
54570
55252
|
init_refusal();
|
|
@@ -54891,41 +55573,41 @@ function prName(pr) {
|
|
|
54891
55573
|
const m = GITHUB_PULL_URL.exec(pr.url);
|
|
54892
55574
|
return m ? `${m[1]}#${pr.number} (${pr.url})` : `pull request ${pr.number} at ${pr.url}`;
|
|
54893
55575
|
}
|
|
54894
|
-
function runArtifacts(
|
|
55576
|
+
function runArtifacts(record3) {
|
|
54895
55577
|
const lines = [];
|
|
54896
|
-
if (
|
|
54897
|
-
const head =
|
|
54898
|
-
lines.push(`- pull request opened or edited: ${prName(
|
|
55578
|
+
if (record3.pr) {
|
|
55579
|
+
const head = record3.pr.head ? `, head branch ${record3.pr.head}` : "";
|
|
55580
|
+
lines.push(`- pull request opened or edited: ${prName(record3.pr)}${head}`);
|
|
54899
55581
|
}
|
|
54900
|
-
if (
|
|
54901
|
-
lines.push(`- verdict: ${
|
|
54902
|
-
const findings =
|
|
55582
|
+
if (record3.verdict) {
|
|
55583
|
+
lines.push(`- verdict: ${record3.verdict.verdict} \u2014 ${record3.verdict.summary}`);
|
|
55584
|
+
const findings = record3.verdict.findings ?? [];
|
|
54903
55585
|
lines.push(findings.length ? `- findings:
|
|
54904
55586
|
${indent(findings.map(formatFinding))}` : "- findings: none recorded");
|
|
54905
55587
|
}
|
|
54906
|
-
if (
|
|
55588
|
+
if (record3.dispositions) {
|
|
54907
55589
|
lines.push(
|
|
54908
|
-
|
|
54909
|
-
${indent(
|
|
55590
|
+
record3.dispositions.length ? `- dispositions:
|
|
55591
|
+
${indent(record3.dispositions.map(formatDisposition))}` : "- dispositions: none recorded"
|
|
54910
55592
|
);
|
|
54911
55593
|
}
|
|
54912
|
-
if (
|
|
54913
|
-
const entries = handoffLines(
|
|
55594
|
+
if (record3.handoff) {
|
|
55595
|
+
const entries = handoffLines(record3.handoff);
|
|
54914
55596
|
lines.push(
|
|
54915
55597
|
entries.length ? `- handoff:
|
|
54916
55598
|
${indent(entries)}` : "- handoff: nothing to hand off (three empty lists)"
|
|
54917
55599
|
);
|
|
54918
55600
|
}
|
|
54919
|
-
const tldr =
|
|
55601
|
+
const tldr = record3.pr ? tldrOf(record3.events) : void 0;
|
|
54920
55602
|
if (tldr !== void 0) lines.push(`- description TL;DR: ${tldr}`);
|
|
54921
|
-
if (
|
|
54922
|
-
const post =
|
|
55603
|
+
if (record3.reviewPost) {
|
|
55604
|
+
const post = record3.reviewPost;
|
|
54923
55605
|
lines.push(
|
|
54924
55606
|
post.posted ? `- review post: posted to ${post.target.repo}#${post.target.number} at ${post.head}${post.verdict ? ` (${post.verdict})` : ""}` : `- review post: not posted \u2014 ${post.reason}`
|
|
54925
55607
|
);
|
|
54926
55608
|
}
|
|
54927
55609
|
if (lines.length === 0) return void 0;
|
|
54928
|
-
return [`### run ${
|
|
55610
|
+
return [`### run ${record3.id} (${record3.agent ?? "agent unknown"})`, ...lines].join("\n");
|
|
54929
55611
|
}
|
|
54930
55612
|
function threadArtifactsBlock(records, opts) {
|
|
54931
55613
|
const maxRuns = opts.maxRuns ?? THREAD_ARTIFACTS_MAX_RUNS;
|
|
@@ -55186,6 +55868,23 @@ async function answerUnitOwnedThread(deps, ctx) {
|
|
|
55186
55868
|
function activeRunCount() {
|
|
55187
55869
|
return activeRuns;
|
|
55188
55870
|
}
|
|
55871
|
+
function continuationBudgetOf(instance, unit) {
|
|
55872
|
+
if (unit.ending?.kind === "wall_clock_cap" || unit.ending?.kind === "review_pending")
|
|
55873
|
+
return { kind: "exhausted", budget: "wall-clock" };
|
|
55874
|
+
if (unit.ending?.kind === "round_cap") return { kind: "exhausted", budget: "review-round" };
|
|
55875
|
+
const caps = instance.caps;
|
|
55876
|
+
if (caps === void 0 || unit.startedAt === void 0 || unit.ending === void 0 || caps.maxMinutes <= 0 || caps.maxRounds <= 0 || unit.ending.at < unit.startedAt)
|
|
55877
|
+
return { kind: "unavailable" };
|
|
55878
|
+
const remainingMinutes = caps.maxMinutes - (unit.ending.at - unit.startedAt) / MINUTE_MS;
|
|
55879
|
+
if (remainingMinutes <= 0) return { kind: "exhausted", budget: "wall-clock" };
|
|
55880
|
+
const reviewRounds = unit.rounds.reduce(
|
|
55881
|
+
(highest, round2) => round2.agent === "review" ? Math.max(highest, round2.index) : highest,
|
|
55882
|
+
0
|
|
55883
|
+
);
|
|
55884
|
+
const remainingRounds = caps.maxRounds - reviewRounds;
|
|
55885
|
+
if (remainingRounds <= 0) return { kind: "exhausted", budget: "review-round" };
|
|
55886
|
+
return { kind: "remaining", caps: { maxRounds: remainingRounds, maxMinutes: remainingMinutes } };
|
|
55887
|
+
}
|
|
55189
55888
|
async function dispatch(deps, msg, io, opts = {}) {
|
|
55190
55889
|
const ended = { status: "completed" };
|
|
55191
55890
|
const resume = opts.resume;
|
|
@@ -55280,22 +55979,46 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
55280
55979
|
try {
|
|
55281
55980
|
const configuredOperator = !resume && !restart && !opts.parent && !opts.coordinator ? operatorModeOf(deps.config.config) : "off";
|
|
55282
55981
|
const typedDecision = parseDirectives(msg.text).agent !== void 0 || deps.commands !== void 0 && parseChatCommand(msg.text, deps.commands) !== null;
|
|
55283
|
-
|
|
55982
|
+
let operatorMode = configuredOperator === "on" && typedDecision ? "off" : configuredOperator;
|
|
55284
55983
|
let operatorEvent;
|
|
55285
55984
|
let operatorPreset;
|
|
55286
55985
|
let operatorRequest;
|
|
55287
55986
|
let operatorModel;
|
|
55288
55987
|
let operatorRepo;
|
|
55289
55988
|
let reissuePlanId;
|
|
55989
|
+
let reissueCaps;
|
|
55290
55990
|
let operatorThread;
|
|
55291
55991
|
let pageOwner;
|
|
55292
55992
|
if (operatorMode !== "off") {
|
|
55293
55993
|
const runsService2 = deps.runs ?? createRunsService({ registry, store: deps.runStore });
|
|
55294
55994
|
operatorThread = opts.thread ?? await readThread(runsService2, msg.threadKey);
|
|
55995
|
+
if (operatorThread !== void 0 && deps.coordinatorInstances !== void 0) {
|
|
55996
|
+
const unitReads = /* @__PURE__ */ new Map();
|
|
55997
|
+
const unitsOf = (id) => {
|
|
55998
|
+
let read = unitReads.get(id);
|
|
55999
|
+
if (read === void 0) {
|
|
56000
|
+
read = deps.coordinatorInstances.listUnits(id);
|
|
56001
|
+
unitReads.set(id, read);
|
|
56002
|
+
}
|
|
56003
|
+
return read;
|
|
56004
|
+
};
|
|
56005
|
+
pageOwner = await ownerOf2(operatorThread, unitsOf, msg.threadKey);
|
|
56006
|
+
if (operatorMode === "on" && parseDirectives(msg.text).agent === void 0) {
|
|
56007
|
+
const continuationOwner = pageOwner.kind === "pipeline" || pageOwner.kind === "pipeline_ambiguous" ? pageOwner : await ownerOf2(
|
|
56008
|
+
operatorThread.filter((run3) => run3.finished),
|
|
56009
|
+
unitsOf,
|
|
56010
|
+
msg.threadKey
|
|
56011
|
+
);
|
|
56012
|
+
if (continuationOwner.kind === "pipeline" || continuationOwner.kind === "pipeline_ambiguous") {
|
|
56013
|
+
pageOwner = continuationOwner;
|
|
56014
|
+
operatorMode = "off";
|
|
56015
|
+
}
|
|
56016
|
+
}
|
|
56017
|
+
}
|
|
56018
|
+
}
|
|
56019
|
+
if (operatorMode !== "off") {
|
|
55295
56020
|
const slot = admission.get(msg.threadKey);
|
|
55296
56021
|
const liveElsewhere = deps.threadsElsewhere.get(msg.threadKey) !== void 0;
|
|
55297
|
-
if (slot === void 0 && !liveElsewhere && operatorThread !== void 0 && deps.coordinatorInstances !== void 0)
|
|
55298
|
-
pageOwner = await ownerOf2(operatorThread, (id) => deps.coordinatorInstances.listUnits(id), msg.threadKey);
|
|
55299
56022
|
const pendingQuestion = operatorMode === "on" ? pendingQuestionOf(operatorThread) : void 0;
|
|
55300
56023
|
const joinedAnswer = pendingQuestion !== void 0 && !(pendingQuestion.proposal !== void 0 && isYesAnswer(msg.text)) ? joinedAnswerRequest(pendingQuestion, msg.text) : void 0;
|
|
55301
56024
|
const doorMsg = joinedAnswer !== void 0 ? { ...msg, text: joinedAnswer } : msg;
|
|
@@ -55307,7 +56030,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
55307
56030
|
// other, and the fold runs on to the seed refusal below, which
|
|
55308
56031
|
// names the unit threads to reply in.
|
|
55309
56032
|
pageOwner.run.instanceId !== void 0 ? { kind: "live" } : { kind: "live", runId: pageOwner.run.id }
|
|
55310
|
-
) : pageOwner?.kind === "unit" ? { kind: "unit", unit: pageOwner.unit.unit } : pageOwner?.kind === "pipeline" ? { kind: "pipeline", unit: pageOwner.unit.unit } : void 0;
|
|
56033
|
+
) : pageOwner?.kind === "unit" ? { kind: "unit", unit: pageOwner.unit.unit } : pageOwner?.kind === "pipeline" ? { kind: "pipeline", unit: pageOwner.unit.unit } : pageOwner?.kind === "pipeline_ambiguous" ? { kind: "pipeline", unit: pageOwner.units.map((unit) => unit.unit).join(", ") } : void 0;
|
|
55311
56034
|
operatorEvent = await root.span(
|
|
55312
56035
|
"dispatch.operator",
|
|
55313
56036
|
() => operatorStage(deps, {
|
|
@@ -55411,20 +56134,120 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
55411
56134
|
await recordPendingOperator();
|
|
55412
56135
|
return ended;
|
|
55413
56136
|
}
|
|
56137
|
+
if (owner.kind === "pipeline_ambiguous" && directives.agent === void 0) {
|
|
56138
|
+
await io.reply(
|
|
56139
|
+
`This thread matches multiple ended plan units (${owner.units.map((unit) => unit.unit).join(", ")}), so continuation is ambiguous. Nothing started.`
|
|
56140
|
+
);
|
|
56141
|
+
await recordPendingOperator();
|
|
56142
|
+
return ended;
|
|
56143
|
+
}
|
|
55414
56144
|
if (owner.kind === "pipeline" && directives.agent === void 0) {
|
|
56145
|
+
const instance = await deps.coordinatorInstances.get(owner.instanceId).catch(() => null);
|
|
56146
|
+
if (instance === null) {
|
|
56147
|
+
await io.reply(
|
|
56148
|
+
`The ended pipeline's record \`${owner.instanceId}\` is unavailable, so continuation did not start.`
|
|
56149
|
+
);
|
|
56150
|
+
await recordPendingOperator();
|
|
56151
|
+
return ended;
|
|
56152
|
+
}
|
|
56153
|
+
const actor = chatActorOf(deps.config, msg);
|
|
56154
|
+
if (authorizeSteerOwner({
|
|
56155
|
+
caller: { ids: actorIdsOf(actor), grants: effectiveGrants(actor) },
|
|
56156
|
+
target: { runId: owner.run.id, requesterId: instance.userId }
|
|
56157
|
+
}).kind === "refused") {
|
|
56158
|
+
await io.reply(STEER_OWNER_REFUSED);
|
|
56159
|
+
await recordPendingOperator();
|
|
56160
|
+
return ended;
|
|
56161
|
+
}
|
|
56162
|
+
if (instance.threadKey !== msg.threadKey || instance.plan === void 0 || instance.plan.path !== void 0) {
|
|
56163
|
+
await io.reply(
|
|
56164
|
+
`The ended pipeline's durable generated-task identity does not match this thread, so continuation did not start.`
|
|
56165
|
+
);
|
|
56166
|
+
await recordPendingOperator();
|
|
56167
|
+
return ended;
|
|
56168
|
+
}
|
|
56169
|
+
if (instance.repo !== owner.run.repo || instance.branch !== owner.unit.branch) {
|
|
56170
|
+
await io.reply(
|
|
56171
|
+
`The ended pipeline's repository or branch identity no longer matches unit ${owner.unit.unit}, so continuation did not start.`
|
|
56172
|
+
);
|
|
56173
|
+
await recordPendingOperator();
|
|
56174
|
+
return ended;
|
|
56175
|
+
}
|
|
56176
|
+
const continuationBudget = continuationBudgetOf(instance, owner.unit);
|
|
56177
|
+
if (continuationBudget.kind === "unavailable") {
|
|
56178
|
+
await io.reply(
|
|
56179
|
+
`Unit ${owner.unit.unit} does not retain a complete durable wall-clock and review-round budget, so continuation did not start. Nothing else ran.`
|
|
56180
|
+
);
|
|
56181
|
+
await recordPendingOperator();
|
|
56182
|
+
return ended;
|
|
56183
|
+
}
|
|
56184
|
+
if (continuationBudget.kind === "exhausted") {
|
|
56185
|
+
await io.reply(
|
|
56186
|
+
`Unit ${owner.unit.unit} exhausted the ended pipeline's ${continuationBudget.budget} budget, so continuation did not start. Nothing else ran.`
|
|
56187
|
+
);
|
|
56188
|
+
await recordPendingOperator();
|
|
56189
|
+
return ended;
|
|
56190
|
+
}
|
|
55415
56191
|
const original = await shipRequestOf(runsService, owner.run.id);
|
|
55416
56192
|
if (original === void 0) {
|
|
55417
56193
|
await io.reply(
|
|
55418
|
-
|
|
56194
|
+
`The ended pipeline's original task is unavailable from run \`${owner.run.id}\`, so continuation did not start.`
|
|
55419
56195
|
);
|
|
55420
56196
|
await recordPendingOperator();
|
|
55421
56197
|
return ended;
|
|
55422
56198
|
}
|
|
55423
|
-
const
|
|
55424
|
-
if (
|
|
55425
|
-
|
|
56199
|
+
const recordedPr = owner.unit.pr;
|
|
56200
|
+
if (recordedPr === void 0) {
|
|
56201
|
+
await io.reply(
|
|
56202
|
+
`Unit ${owner.unit.unit} does not retain a durable pull request identity, so continuation did not start. Nothing else ran.`
|
|
56203
|
+
);
|
|
56204
|
+
await recordPendingOperator();
|
|
56205
|
+
return ended;
|
|
56206
|
+
}
|
|
56207
|
+
const expectedHead = owner.unit.lastPush;
|
|
56208
|
+
if (expectedHead === void 0) {
|
|
56209
|
+
await io.reply(
|
|
56210
|
+
`Unit ${owner.unit.unit} does not retain the pull request's durable expected head, so continuation did not start. Nothing else ran.`
|
|
56211
|
+
);
|
|
56212
|
+
await recordPendingOperator();
|
|
56213
|
+
return ended;
|
|
56214
|
+
}
|
|
56215
|
+
const target = { repo: instance.repo, number: recordedPr.number };
|
|
56216
|
+
const facts2 = await (deps.fetchPrFacts ?? fetchPullRequestFacts)(target).catch(() => void 0);
|
|
56217
|
+
if (facts2 === void 0) {
|
|
56218
|
+
await io.reply(
|
|
56219
|
+
`GitHub did not return current facts for ${instance.repo}#${recordedPr.number}, so continuation did not start.`
|
|
56220
|
+
);
|
|
56221
|
+
await recordPendingOperator();
|
|
56222
|
+
return ended;
|
|
56223
|
+
}
|
|
56224
|
+
if (facts2.state !== "open") {
|
|
56225
|
+
await io.reply(
|
|
56226
|
+
`${instance.repo}#${recordedPr.number} is closed, so this ended pipeline has no open pull request to continue. Nothing started.`
|
|
56227
|
+
);
|
|
56228
|
+
await recordPendingOperator();
|
|
56229
|
+
return ended;
|
|
56230
|
+
}
|
|
56231
|
+
const verifiedHead = facts2.verifiedHead;
|
|
56232
|
+
if (!facts2.sameRepoHead || facts2.headBranchExists !== true || facts2.headRef !== owner.unit.branch || verifiedHead === void 0 || verifiedHead.repo.toLowerCase() !== instance.repo.toLowerCase() || verifiedHead.ref !== owner.unit.branch || facts2.headSha !== verifiedHead.sha) {
|
|
56233
|
+
await io.reply(
|
|
56234
|
+
`${instance.repo}#${recordedPr.number} no longer has the pipeline's verifiable \`${owner.unit.branch}\` head, so continuation did not start.`
|
|
56235
|
+
);
|
|
56236
|
+
await recordPendingOperator();
|
|
56237
|
+
return ended;
|
|
56238
|
+
}
|
|
56239
|
+
if (verifiedHead.sha !== expectedHead) {
|
|
56240
|
+
await io.reply(
|
|
56241
|
+
`${instance.repo}#${recordedPr.number} moved from the pipeline's expected head \`${expectedHead}\` to \`${verifiedHead.sha}\`, so continuation did not start. Nothing else ran.`
|
|
56242
|
+
);
|
|
56243
|
+
await recordPendingOperator();
|
|
56244
|
+
return ended;
|
|
56245
|
+
}
|
|
56246
|
+
reissuePlanId = instance.plan.id;
|
|
56247
|
+
reissueCaps = continuationBudget.caps;
|
|
56248
|
+
const durableRequest = parseDirectives(original);
|
|
56249
|
+
Object.assign(directives, durableRequest, { agent: void 0, budget: reissueCaps.maxMinutes });
|
|
55426
56250
|
operatorPreset = "ship";
|
|
55427
|
-
operatorRequest = original;
|
|
55428
56251
|
settled = resolveCurrent();
|
|
55429
56252
|
({ sticky, resolved, agentSource } = settled);
|
|
55430
56253
|
agentSource = "sticky";
|
|
@@ -55650,6 +56473,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
55650
56473
|
card,
|
|
55651
56474
|
directives,
|
|
55652
56475
|
...reissuePlanId !== void 0 ? { reissuePlanId } : {},
|
|
56476
|
+
...reissueCaps !== void 0 ? { reissueCaps: { ...reissueCaps, maxMinutes: Math.min(reissueCaps.maxMinutes, profile.minutes) } } : {},
|
|
55653
56477
|
sticky,
|
|
55654
56478
|
history,
|
|
55655
56479
|
repoCtx,
|
|
@@ -55744,12 +56568,12 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
55744
56568
|
...operatorEvent ? { operator: operatorEvent } : {},
|
|
55745
56569
|
...references.conversations.length > 0 ? { references } : {}
|
|
55746
56570
|
});
|
|
55747
|
-
const { run: run2, runId: runId3, channelVisibility, liveUrl, publishText, publishMeta } = registration;
|
|
56571
|
+
const { run: run2, runId: runId3, channelVisibility, liveUrl, events, publishText, publishMeta } = registration;
|
|
55748
56572
|
registered = run2;
|
|
55749
56573
|
for (const summary of seedNotes)
|
|
55750
|
-
|
|
56574
|
+
events.publish({ type: "run_note", kind: "seed", summary: oneLine(summary), at: clock4() });
|
|
55751
56575
|
if (opts.redispatch)
|
|
55752
|
-
|
|
56576
|
+
events.publish({
|
|
55753
56577
|
type: "run_note",
|
|
55754
56578
|
kind: "redispatch",
|
|
55755
56579
|
summary: `confirmed after question ${opts.redispatch.code}`,
|
|
@@ -55764,7 +56588,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
55764
56588
|
threadKey: msg.threadKey,
|
|
55765
56589
|
nextIndex: nextStagedIndex,
|
|
55766
56590
|
preserveWorkspaceIndexes: true,
|
|
55767
|
-
publish: (
|
|
56591
|
+
publish: (event) => events.publish(event)
|
|
55768
56592
|
}) : void 0;
|
|
55769
56593
|
const threadAssets = !resume && deps.artifacts && thread && thread.length > 0 ? readThreadAssets({ runs: runsService, store: deps.artifacts }, msg.threadKey).then(
|
|
55770
56594
|
(assets) => assets.filter((a) => a.runId !== runId3)
|
|
@@ -55775,7 +56599,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
55775
56599
|
{
|
|
55776
56600
|
nextIndex: nextStagedIndex,
|
|
55777
56601
|
messageId: messageIdOf(msg, runId3),
|
|
55778
|
-
publish: (
|
|
56602
|
+
publish: (event) => events.publish(event)
|
|
55779
56603
|
}
|
|
55780
56604
|
)
|
|
55781
56605
|
) : void 0;
|
|
@@ -55807,7 +56631,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
55807
56631
|
reserved = reservation.reserved;
|
|
55808
56632
|
requestRow = reservation.requestRow;
|
|
55809
56633
|
if (reservation.untrackedWhy !== void 0) {
|
|
55810
|
-
|
|
56634
|
+
events.publish({
|
|
55811
56635
|
type: "run_note",
|
|
55812
56636
|
kind: "ledger_untracked",
|
|
55813
56637
|
summary: redactAndCap(
|
|
@@ -55821,6 +56645,100 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
55821
56645
|
shell.note("debug", "untracked by the ledger");
|
|
55822
56646
|
}
|
|
55823
56647
|
}
|
|
56648
|
+
if (typeof registry.commitLiveState === "function") {
|
|
56649
|
+
await events.write(async () => {
|
|
56650
|
+
const current = registry.getById(runId3);
|
|
56651
|
+
if (current && current.liveState === void 0) {
|
|
56652
|
+
const at = clock4();
|
|
56653
|
+
const eventSeq = current.eventCount + 1;
|
|
56654
|
+
const assignment = {
|
|
56655
|
+
expectedSeq: 0,
|
|
56656
|
+
eventSeq,
|
|
56657
|
+
at,
|
|
56658
|
+
state: "admitted",
|
|
56659
|
+
bound: resume ? at + resume.plan.remainingMs : Math.max(startedAt + minutesToMs(profile.minutes), at + minutesToMs(profile.minutes)),
|
|
56660
|
+
detail: "waiting to attach the workspace",
|
|
56661
|
+
// A reservation is not subscribed to the registry until promotion.
|
|
56662
|
+
// Commit the setup stream that already exists with admission, or
|
|
56663
|
+
// advancing its ledger cursor here would make promotion skip it.
|
|
56664
|
+
...reserved ? {
|
|
56665
|
+
sourceEvents: (registry.snapshotById(runId3)?.events ?? []).map((event) => ({
|
|
56666
|
+
...event,
|
|
56667
|
+
seq: event.seq
|
|
56668
|
+
}))
|
|
56669
|
+
} : {},
|
|
56670
|
+
...(current.liveStateSeq ?? 0) > 0 ? { restart: true } : {}
|
|
56671
|
+
};
|
|
56672
|
+
const tracked = reserved ?? ledgerRun;
|
|
56673
|
+
if (tracked?.tracked()) {
|
|
56674
|
+
let committed = await tracked.assignLiveState(assignment);
|
|
56675
|
+
if (!committed.ok && committed.reason === "stale-sequence" && (current.liveStateSeq ?? 0) > 0)
|
|
56676
|
+
committed = await tracked.assignLiveState({
|
|
56677
|
+
...assignment,
|
|
56678
|
+
expectedSeq: current.liveStateSeq ?? 0,
|
|
56679
|
+
sourceEvents: void 0,
|
|
56680
|
+
restart: true
|
|
56681
|
+
});
|
|
56682
|
+
if (!committed.ok || !registry.commitLiveState(runId3, committed))
|
|
56683
|
+
throw new Error(
|
|
56684
|
+
`live state admission was not committed (${committed.ok ? "registry sequence" : committed.reason})`
|
|
56685
|
+
);
|
|
56686
|
+
} else {
|
|
56687
|
+
const expectedSeq = current.liveStateSeq ?? 0;
|
|
56688
|
+
const local = assignRunLiveState(void 0, expectedSeq, { ...assignment, expectedSeq });
|
|
56689
|
+
if (!local.ok || !local.event) throw new Error("live state admission was invalid");
|
|
56690
|
+
registry.commitLiveState(runId3, {
|
|
56691
|
+
...local,
|
|
56692
|
+
event: { ...local.event, seq: eventSeq },
|
|
56693
|
+
liveStateSeq: eventSeq
|
|
56694
|
+
});
|
|
56695
|
+
}
|
|
56696
|
+
}
|
|
56697
|
+
});
|
|
56698
|
+
}
|
|
56699
|
+
const assignLive = async (next, at, detail) => {
|
|
56700
|
+
if (typeof registry.commitLiveState !== "function") return true;
|
|
56701
|
+
let accepted = false;
|
|
56702
|
+
await events.write(async () => {
|
|
56703
|
+
const summary = registry.getById(runId3);
|
|
56704
|
+
if (!summary) return;
|
|
56705
|
+
const eventSeq = summary.eventCount + 1;
|
|
56706
|
+
const assignment = {
|
|
56707
|
+
expectedSeq: summary.liveStateSeq ?? 0,
|
|
56708
|
+
eventSeq,
|
|
56709
|
+
at,
|
|
56710
|
+
state: next.state,
|
|
56711
|
+
bound: next.bound,
|
|
56712
|
+
...detail !== void 0 ? { detail } : {}
|
|
56713
|
+
};
|
|
56714
|
+
const tracked = ledgerRun ?? reserved;
|
|
56715
|
+
if (tracked) {
|
|
56716
|
+
const committed = await tracked.assignLiveState(assignment);
|
|
56717
|
+
accepted = committed.ok && (registry.commitLiveState?.(runId3, committed) ?? true);
|
|
56718
|
+
return;
|
|
56719
|
+
}
|
|
56720
|
+
const local = assignRunLiveState(summary.liveState, summary.liveStateSeq ?? 0, assignment);
|
|
56721
|
+
if (!local.ok) return;
|
|
56722
|
+
accepted = registry.commitLiveState?.(runId3, {
|
|
56723
|
+
...local,
|
|
56724
|
+
...local.event ? { event: { ...local.event, seq: eventSeq } } : {},
|
|
56725
|
+
liveStateSeq: local.event ? eventSeq : summary.liveStateSeq ?? 0
|
|
56726
|
+
}) ?? true;
|
|
56727
|
+
});
|
|
56728
|
+
return accepted;
|
|
56729
|
+
};
|
|
56730
|
+
let residentAttachAttempt = 0;
|
|
56731
|
+
const observeResidentLiveState = async (observation) => {
|
|
56732
|
+
if (observation.attempt < residentAttachAttempt) return;
|
|
56733
|
+
residentAttachAttempt = observation.attempt;
|
|
56734
|
+
const accepted = await assignLive(
|
|
56735
|
+
{ state: observation.state, bound: observation.bound },
|
|
56736
|
+
clock4(),
|
|
56737
|
+
liveStateWords(observation.state)
|
|
56738
|
+
);
|
|
56739
|
+
if (!accepted) throw new Error("resident live-state observation was stale or could not be committed");
|
|
56740
|
+
shell.setSetupLabel(`${liveStateWords(observation.state)}\u2026`);
|
|
56741
|
+
};
|
|
55824
56742
|
const reattach = resume ? carriedWorkspaceBinding(resume.row) : void 0;
|
|
55825
56743
|
const control = registered?.control;
|
|
55826
56744
|
const attach = await attachWorkspace(deps, {
|
|
@@ -55840,7 +56758,8 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
55840
56758
|
// during the attach ends its wake wait at once, and once the harness
|
|
55841
56759
|
// starts the lease every attach the executor opens is clipped to the
|
|
55842
56760
|
// run's remaining clock (execution.md item 9).
|
|
55843
|
-
...control ? { stopSignal: control.hardSignal, remainingMs: () => control.remainingMs() } : {}
|
|
56761
|
+
...control ? { stopSignal: control.hardSignal, remainingMs: () => control.remainingMs() } : {},
|
|
56762
|
+
onLiveStateObservation: observeResidentLiveState
|
|
55844
56763
|
});
|
|
55845
56764
|
if (attach.kind === "refused") return ended;
|
|
55846
56765
|
if (attach.kind === "stopped") {
|
|
@@ -55892,6 +56811,17 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
55892
56811
|
return ended;
|
|
55893
56812
|
}
|
|
55894
56813
|
const { round: round2 } = attach;
|
|
56814
|
+
if (typeof registry.commitLiveState === "function") {
|
|
56815
|
+
const summary = registry.getById(runId3);
|
|
56816
|
+
const bound2 = summary?.liveState?.bound ?? startedAt + minutesToMs(profile.minutes);
|
|
56817
|
+
if (summary?.liveState && (summary.liveState.state === "waiting_deploy" || summary.liveState.state === "waiting_repository") && round2.selection.backend !== "resident") {
|
|
56818
|
+
if (!await assignLive({ state: "falling_back", bound: bound2 }, clock4(), "switching to a fallback workspace"))
|
|
56819
|
+
throw new Error("fallback live state could not be committed");
|
|
56820
|
+
}
|
|
56821
|
+
if (!await assignLive({ state: "preparing", bound: bound2 }, clock4(), "preparing the workspace"))
|
|
56822
|
+
throw new Error("preparation live state could not be committed");
|
|
56823
|
+
shell.setSetupLabel(`${liveStateWords("preparing")}\u2026`);
|
|
56824
|
+
}
|
|
55895
56825
|
if (resume && ledgerRun) {
|
|
55896
56826
|
const rebound = workspaceBindingFor(round2.selection, profile.machine);
|
|
55897
56827
|
if (rebound !== void 0) ledgerRun.setState({ binding: rebound });
|
|
@@ -56073,6 +57003,12 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
56073
57003
|
markUntracked: () => shell.note("debug", "untracked by the ledger"),
|
|
56074
57004
|
...seedActors !== void 0 ? { seedActors } : {}
|
|
56075
57005
|
});
|
|
57006
|
+
if (typeof registry.commitLiveState === "function") {
|
|
57007
|
+
const summary = registry.getById(runId3);
|
|
57008
|
+
const bound2 = summary?.liveState?.bound ?? startedAt + minutesToMs(profile.minutes);
|
|
57009
|
+
if (!await assignLive({ state: "working", bound: bound2 }, clock4(), "model turn"))
|
|
57010
|
+
throw new Error("working live state could not be committed");
|
|
57011
|
+
}
|
|
56076
57012
|
const sessionTools = sessionCapabilityFor(
|
|
56077
57013
|
ledgerRun,
|
|
56078
57014
|
deps.runLedger,
|
|
@@ -56114,6 +57050,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
56114
57050
|
mcpForRun,
|
|
56115
57051
|
run: run2,
|
|
56116
57052
|
registry,
|
|
57053
|
+
events,
|
|
56117
57054
|
round: round2,
|
|
56118
57055
|
admitted,
|
|
56119
57056
|
ledgerRun,
|
|
@@ -56442,6 +57379,8 @@ var init_dispatcher = __esm({
|
|
|
56442
57379
|
init_registry();
|
|
56443
57380
|
init_budgets();
|
|
56444
57381
|
init_trace();
|
|
57382
|
+
init_runLiveState();
|
|
57383
|
+
init_decide();
|
|
56445
57384
|
init_requestTrace();
|
|
56446
57385
|
init_runShape();
|
|
56447
57386
|
init_runEvents();
|
|
@@ -56463,6 +57402,7 @@ var init_dispatcher = __esm({
|
|
|
56463
57402
|
init_route();
|
|
56464
57403
|
init_operator();
|
|
56465
57404
|
init_authorize2();
|
|
57405
|
+
init_authorize();
|
|
56466
57406
|
init_messages();
|
|
56467
57407
|
init_staging();
|
|
56468
57408
|
init_runRecord();
|
|
@@ -56481,6 +57421,7 @@ var init_dispatcher = __esm({
|
|
|
56481
57421
|
init_settle();
|
|
56482
57422
|
init_reattach2();
|
|
56483
57423
|
init_factory();
|
|
57424
|
+
init_githubPulls();
|
|
56484
57425
|
init_sandboxErrors();
|
|
56485
57426
|
init_lineage();
|
|
56486
57427
|
init_seed();
|
|
@@ -56841,8 +57782,8 @@ function createLedgerWriteThrough(opts) {
|
|
|
56841
57782
|
settleLanding(this.runId, entry, outcome);
|
|
56842
57783
|
return value;
|
|
56843
57784
|
},
|
|
56844
|
-
abandoned: (
|
|
56845
|
-
if (
|
|
57785
|
+
abandoned: (record3, why) => {
|
|
57786
|
+
if (record3.id !== this.runId) return;
|
|
56846
57787
|
const entry = landing.get(this.runId);
|
|
56847
57788
|
if (entry !== void 0) settleLanding(this.runId, entry, { kind: "failed", why });
|
|
56848
57789
|
}
|
|
@@ -56852,18 +57793,18 @@ function createLedgerWriteThrough(opts) {
|
|
|
56852
57793
|
async land(plain7) {
|
|
56853
57794
|
await this.close();
|
|
56854
57795
|
const session = this.sessionOnRecord();
|
|
56855
|
-
const
|
|
57796
|
+
const record3 = session ? { ...plain7, session } : plain7;
|
|
56856
57797
|
let result;
|
|
56857
57798
|
try {
|
|
56858
|
-
result = await ledger.finish(this.runId, gen,
|
|
57799
|
+
result = await ledger.finish(this.runId, gen, record3);
|
|
56859
57800
|
} catch (err2) {
|
|
56860
57801
|
if (!(err2 instanceof RouteMissingError)) throw err2;
|
|
56861
57802
|
routeMissing();
|
|
56862
|
-
return { value: await fallback.put(
|
|
57803
|
+
return { value: await fallback.put(record3), outcome: { kind: "refused" } };
|
|
56863
57804
|
}
|
|
56864
57805
|
if (result.ok) return { value: result, outcome: { kind: "landed" } };
|
|
56865
57806
|
warn(`[ledger] ${this.threadKey} finish refused (${result.reason}) \u2014 record written to the store directly`);
|
|
56866
|
-
return { value: await fallback.put(
|
|
57807
|
+
return { value: await fallback.put(record3), outcome: { kind: "refused" } };
|
|
56867
57808
|
}
|
|
56868
57809
|
tracked() {
|
|
56869
57810
|
return !this.detached;
|
|
@@ -56933,7 +57874,7 @@ function createLedgerWriteThrough(opts) {
|
|
|
56933
57874
|
}));
|
|
56934
57875
|
if (report2.compaction)
|
|
56935
57876
|
turns.push({ idx: this.rowIndex(report2.firstIdx + report2.turns.length), compaction: report2.compaction });
|
|
56936
|
-
const
|
|
57877
|
+
const record3 = {
|
|
56937
57878
|
step: ++this.stepNo,
|
|
56938
57879
|
seq: this.lastSeq,
|
|
56939
57880
|
turnIndex: report2.firstIdx + turns.length,
|
|
@@ -56944,10 +57885,10 @@ function createLedgerWriteThrough(opts) {
|
|
|
56944
57885
|
turn: report2.turn,
|
|
56945
57886
|
iteration: report2.iteration
|
|
56946
57887
|
};
|
|
56947
|
-
this.factRound =
|
|
56948
|
-
const kept = new Set(
|
|
57888
|
+
this.factRound = record3.step;
|
|
57889
|
+
const kept = new Set(record3.inFlight.map((c) => c.callId));
|
|
56949
57890
|
for (const id of this.factCallStarts.keys()) if (!kept.has(id)) this.factCallStarts.delete(id);
|
|
56950
|
-
const call2 =
|
|
57891
|
+
const call2 = record3.inFlight[0];
|
|
56951
57892
|
this.factInFlight = call2 ? {
|
|
56952
57893
|
callId: call2.callId,
|
|
56953
57894
|
tool: call2.tool,
|
|
@@ -56959,13 +57900,13 @@ function createLedgerWriteThrough(opts) {
|
|
|
56959
57900
|
} : void 0;
|
|
56960
57901
|
for (let attempt = 1; ; attempt++) {
|
|
56961
57902
|
try {
|
|
56962
|
-
const result = await ledger.step(this.runId, gen,
|
|
56963
|
-
if (!result.ok) this.detach(`step ${
|
|
56964
|
-
else this.turnsWritten =
|
|
57903
|
+
const result = await ledger.step(this.runId, gen, record3, turns, this.sessionRow?.key);
|
|
57904
|
+
if (!result.ok) this.detach(`step ${record3.step} refused (${result.reason})`);
|
|
57905
|
+
else this.turnsWritten = record3.turnIndex;
|
|
56965
57906
|
return;
|
|
56966
57907
|
} catch (err2) {
|
|
56967
57908
|
if (err2 instanceof RouteMissingError || err2 instanceof PermanentStoreError || attempt >= 2) {
|
|
56968
|
-
this.detach(`step ${
|
|
57909
|
+
this.detach(`step ${record3.step} failed: ${describe9(err2)}`);
|
|
56969
57910
|
return;
|
|
56970
57911
|
}
|
|
56971
57912
|
await sleep2(RETRY_MS[0]);
|
|
@@ -56973,7 +57914,7 @@ function createLedgerWriteThrough(opts) {
|
|
|
56973
57914
|
}
|
|
56974
57915
|
}
|
|
56975
57916
|
event(event, seq) {
|
|
56976
|
-
if (this.detached || this.finished) return;
|
|
57917
|
+
if (this.detached || this.finished || seq <= this.lastSeq) return;
|
|
56977
57918
|
this.lastSeq = seq;
|
|
56978
57919
|
const e = event;
|
|
56979
57920
|
if (typeof e.at === "number") this.factLastEventAt = e.at;
|
|
@@ -56994,6 +57935,30 @@ function createLedgerWriteThrough(opts) {
|
|
|
56994
57935
|
};
|
|
56995
57936
|
this.flusher.push({ ...event, seq });
|
|
56996
57937
|
}
|
|
57938
|
+
async assignLiveState(assignment) {
|
|
57939
|
+
if (this.detached || this.finished) return { ok: false, reason: "unknown-run" };
|
|
57940
|
+
await this.flusher.flush();
|
|
57941
|
+
await this.stateSending;
|
|
57942
|
+
try {
|
|
57943
|
+
const result = await ledger.assignLiveState(this.runId, gen, assignment);
|
|
57944
|
+
if (!result.ok) {
|
|
57945
|
+
if (result.reason === "fenced" || result.reason === "unknown-run")
|
|
57946
|
+
this.detach(`live state refused (${result.reason})`);
|
|
57947
|
+
return result;
|
|
57948
|
+
}
|
|
57949
|
+
this.state = {
|
|
57950
|
+
...this.state,
|
|
57951
|
+
...assignment.statePatch,
|
|
57952
|
+
liveState: result.liveState,
|
|
57953
|
+
liveStateSeq: result.liveStateSeq
|
|
57954
|
+
};
|
|
57955
|
+
this.lastSeq = Math.max(this.lastSeq, result.liveStateSeq);
|
|
57956
|
+
return result;
|
|
57957
|
+
} catch (err2) {
|
|
57958
|
+
warn(`[ledger] ${this.threadKey} live state not written: ${describe9(err2)}`);
|
|
57959
|
+
return { ok: false, reason: "unknown-run" };
|
|
57960
|
+
}
|
|
57961
|
+
}
|
|
56997
57962
|
setState(patch) {
|
|
56998
57963
|
if (this.detached) return;
|
|
56999
57964
|
this.state = { ...this.state, ...patch };
|
|
@@ -57378,6 +58343,9 @@ var init_writeThrough = __esm({
|
|
|
57378
58343
|
}
|
|
57379
58344
|
event(_event, _seq) {
|
|
57380
58345
|
}
|
|
58346
|
+
async assignLiveState(_assignment) {
|
|
58347
|
+
return { ok: false, reason: "unknown-run" };
|
|
58348
|
+
}
|
|
57381
58349
|
setState(_patch) {
|
|
57382
58350
|
}
|
|
57383
58351
|
async finishing() {
|
|
@@ -58766,8 +59734,8 @@ async function launchOpenCode(deps, spec, bearer) {
|
|
|
58766
59734
|
let consumed = 0;
|
|
58767
59735
|
for (const line4 of text.split("\n").slice(0, -1)) {
|
|
58768
59736
|
consumed += Buffer.byteLength(line4, "utf8") + 1;
|
|
58769
|
-
const
|
|
58770
|
-
if (
|
|
59737
|
+
const record3 = parseFeedRecord(line4);
|
|
59738
|
+
if (record3?.feed === "tailer" && record3.note === "connected") {
|
|
58771
59739
|
feedOffset = consumed;
|
|
58772
59740
|
break;
|
|
58773
59741
|
}
|
|
@@ -58847,9 +59815,9 @@ var init_process2 = __esm({
|
|
|
58847
59815
|
});
|
|
58848
59816
|
|
|
58849
59817
|
// ../../src/core/harness/opencode/bridge.ts
|
|
58850
|
-
function executionStartedFor(
|
|
58851
|
-
if (
|
|
58852
|
-
const data =
|
|
59818
|
+
function executionStartedFor(record3, sessionID) {
|
|
59819
|
+
if (record3.feed !== "event" || record3.event.type !== "session.execution.started") return false;
|
|
59820
|
+
const data = record3.event.data;
|
|
58853
59821
|
return data?.sessionID === sessionID;
|
|
58854
59822
|
}
|
|
58855
59823
|
function openCodeToolNameWord(name) {
|
|
@@ -59521,18 +60489,18 @@ async function driveOpenCode(deps, run2, conn, kind = "loop") {
|
|
|
59521
60489
|
const after = transport.consumedOffset;
|
|
59522
60490
|
const reattachCatchUp = conn.reattach !== void 0 && after <= conn.reattach.catchUpTo;
|
|
59523
60491
|
lastRecord = next.value;
|
|
59524
|
-
const
|
|
59525
|
-
if (!
|
|
59526
|
-
if (!reattachCatchUp && executionStartedFor(
|
|
60492
|
+
const record3 = parseFeedRecord(next.value);
|
|
60493
|
+
if (!record3) continue;
|
|
60494
|
+
if (!reattachCatchUp && executionStartedFor(record3, conn.sessionID)) {
|
|
59527
60495
|
executionOwned = true;
|
|
59528
60496
|
awaiting = void 0;
|
|
59529
60497
|
}
|
|
59530
60498
|
bridge.observing = reattachCatchUp ? "catching-up" : executionOwned ? "own" : "earlier";
|
|
59531
|
-
const obs = bridge.observe(
|
|
60499
|
+
const obs = bridge.observe(record3);
|
|
59532
60500
|
if (!reattachCatchUp && obs.boundary === true) conn.boundaries?.reached();
|
|
59533
60501
|
if (!reattachCatchUp && obs.inboxDelivered !== void 0) conn.inboxFate?.deliver(obs.inboxDelivered);
|
|
59534
60502
|
if (!reattachCatchUp && obs.inboxDropped === true) conn.inboxFate?.interruptAll();
|
|
59535
|
-
if (
|
|
60503
|
+
if (record3.feed === "messages" && conn.saveOffset !== void 0) {
|
|
59536
60504
|
const save = conn.saveOffset;
|
|
59537
60505
|
void bridge.flush().then(() => save(after));
|
|
59538
60506
|
}
|
|
@@ -59619,14 +60587,14 @@ async function driveOpenCode(deps, run2, conn, kind = "loop") {
|
|
|
59619
60587
|
);
|
|
59620
60588
|
}
|
|
59621
60589
|
if (replacedBy !== void 0) {
|
|
59622
|
-
const
|
|
60590
|
+
const record3 = bridge.record(recordBase, deadline);
|
|
59623
60591
|
bridge.closeOpenSpans((open2) => openCodeReplacedCallNote(open2.tool));
|
|
59624
60592
|
const replaced = replacedBy.condition === "word" ? new OpenCodeContainerReplacedError(
|
|
59625
60593
|
replacedBy.said.message,
|
|
59626
60594
|
conn.containerWord,
|
|
59627
60595
|
await conn.container.identity().catch(() => void 0),
|
|
59628
|
-
|
|
59629
|
-
) : new OpenCodeContainerReplacedError(void 0, replacedBy.was, replacedBy.now,
|
|
60596
|
+
record3
|
|
60597
|
+
) : new OpenCodeContainerReplacedError(void 0, replacedBy.was, replacedBy.now, record3, "identity");
|
|
59630
60598
|
note("sandbox_restarted", replaced.message);
|
|
59631
60599
|
throw replaced;
|
|
59632
60600
|
}
|
|
@@ -59766,13 +60734,13 @@ var init_bridge3 = __esm({
|
|
|
59766
60734
|
diagnostics;
|
|
59767
60735
|
};
|
|
59768
60736
|
OpenCodeContainerReplacedError = class extends HarnessContainerReplacedError {
|
|
59769
|
-
constructor(said2, was, now,
|
|
60737
|
+
constructor(said2, was, now, record3, condition = "word") {
|
|
59770
60738
|
super(
|
|
59771
60739
|
`the container running OpenCode was replaced (${was ?? "unknown"} \u2192 ${now ?? "unknown"}; ${replacedBecause(condition, said2)})`,
|
|
59772
60740
|
said2,
|
|
59773
60741
|
was,
|
|
59774
60742
|
now,
|
|
59775
|
-
|
|
60743
|
+
record3,
|
|
59776
60744
|
condition
|
|
59777
60745
|
);
|
|
59778
60746
|
this.name = "OpenCodeContainerReplacedError";
|
|
@@ -60221,25 +61189,25 @@ var init_bridge3 = __esm({
|
|
|
60221
61189
|
emit(event) {
|
|
60222
61190
|
this.deps.emit(event.at === void 0 ? { ...event, at: this.deps.clock() } : event);
|
|
60223
61191
|
}
|
|
60224
|
-
observe(
|
|
60225
|
-
switch (
|
|
61192
|
+
observe(record3) {
|
|
61193
|
+
switch (record3.feed) {
|
|
60226
61194
|
case "event":
|
|
60227
|
-
return this.onEvent(
|
|
61195
|
+
return this.onEvent(record3.event);
|
|
60228
61196
|
case "permissions":
|
|
60229
61197
|
if (this.observing === "earlier") return { replies: [], settled: false };
|
|
60230
|
-
return this.onPermissionsRefill(
|
|
61198
|
+
return this.onPermissionsRefill(record3.data);
|
|
60231
61199
|
case "messages": {
|
|
60232
|
-
const out = this.onMessagesRefill(
|
|
60233
|
-
if (this.settleOwedTo !== void 0 &&
|
|
61200
|
+
const out = this.onMessagesRefill(record3.data);
|
|
61201
|
+
if (this.settleOwedTo !== void 0 && record3.reason === this.settleOwedTo) {
|
|
60234
61202
|
this.settleOwedTo = void 0;
|
|
60235
61203
|
out.settled = true;
|
|
60236
61204
|
}
|
|
60237
61205
|
return out;
|
|
60238
61206
|
}
|
|
60239
61207
|
case "tailer":
|
|
60240
|
-
if (
|
|
60241
|
-
this.deps.onProgress?.(`opencode feed: ${redactAndCap(
|
|
60242
|
-
if (this.settleOwedTo !== void 0 && (
|
|
61208
|
+
if (record3.note === "stream closed" || record3.note.includes("failed"))
|
|
61209
|
+
this.deps.onProgress?.(`opencode feed: ${redactAndCap(record3.note, 120)}`);
|
|
61210
|
+
if (this.settleOwedTo !== void 0 && (record3.note === "message refill failed" || record3.note === "refill failed") && record3.reason === this.settleOwedTo) {
|
|
60243
61211
|
this.settleOwedTo = void 0;
|
|
60244
61212
|
return { replies: [], settled: true };
|
|
60245
61213
|
}
|
|
@@ -61199,7 +62167,7 @@ ${stagedLine}` : prompt;
|
|
|
61199
62167
|
return "lost";
|
|
61200
62168
|
return "running";
|
|
61201
62169
|
};
|
|
61202
|
-
const resolve13 = async (steerSeq, knownAtSteer, seen,
|
|
62170
|
+
const resolve13 = async (steerSeq, knownAtSteer, seen, waiting3) => {
|
|
61203
62171
|
let left = false;
|
|
61204
62172
|
for (; ; ) {
|
|
61205
62173
|
const verdict = await learnRow(steerSeq, knownAtSteer);
|
|
@@ -61214,7 +62182,7 @@ ${stagedLine}` : prompt;
|
|
|
61214
62182
|
"the follow-up's steer",
|
|
61215
62183
|
"the loop left the feed with no row of the steer and the store still showing its execution under way, so the store cannot say whether the server took it"
|
|
61216
62184
|
);
|
|
61217
|
-
|
|
62185
|
+
waiting3();
|
|
61218
62186
|
if (await conn.boundaries.wait(seen) === "left") left = true;
|
|
61219
62187
|
seen = conn.boundaries.count;
|
|
61220
62188
|
}
|
|
@@ -61526,6 +62494,14 @@ var init_requester = __esm({
|
|
|
61526
62494
|
|
|
61527
62495
|
// ../../src/channels/http.ts
|
|
61528
62496
|
import { timingSafeEqual as timingSafeEqual4 } from "node:crypto";
|
|
62497
|
+
function ingressComponentError(name, value) {
|
|
62498
|
+
if (value.length === 0) return `\`${name}\` must be a non-empty string`;
|
|
62499
|
+
if (value.length > INGRESS_COMPONENT_MAX_LENGTH) {
|
|
62500
|
+
return `\`${name}\` must be at most ${INGRESS_COMPONENT_MAX_LENGTH} characters`;
|
|
62501
|
+
}
|
|
62502
|
+
if (/[:#]/.test(value)) return `\`${name}\` must not contain ':' or '#'`;
|
|
62503
|
+
return void 0;
|
|
62504
|
+
}
|
|
61529
62505
|
function safeEqual2(a, b) {
|
|
61530
62506
|
const ab = Buffer.from(a, "utf8");
|
|
61531
62507
|
const bb = Buffer.from(b, "utf8");
|
|
@@ -61569,11 +62545,15 @@ function parseBody3(raw) {
|
|
|
61569
62545
|
if (typeof obj2.text !== "string" || obj2.text.trim() === "") {
|
|
61570
62546
|
return { error: "`text` is required and must be a non-empty string" };
|
|
61571
62547
|
}
|
|
61572
|
-
if (obj2.channel !== void 0
|
|
61573
|
-
return { error: "`channel` must be a string" };
|
|
62548
|
+
if (obj2.channel !== void 0) {
|
|
62549
|
+
if (typeof obj2.channel !== "string") return { error: "`channel` must be a string" };
|
|
62550
|
+
const error = ingressComponentError("channel", obj2.channel);
|
|
62551
|
+
if (error) return { error };
|
|
61574
62552
|
}
|
|
61575
|
-
if (obj2.thread !== void 0
|
|
61576
|
-
return { error: "`thread` must be a string" };
|
|
62553
|
+
if (obj2.thread !== void 0) {
|
|
62554
|
+
if (typeof obj2.thread !== "string") return { error: "`thread` must be a string" };
|
|
62555
|
+
const error = ingressComponentError("thread", obj2.thread);
|
|
62556
|
+
if (error) return { error };
|
|
61577
62557
|
}
|
|
61578
62558
|
if (obj2.async !== void 0 && typeof obj2.async !== "boolean") {
|
|
61579
62559
|
return { error: "`async` must be a boolean" };
|
|
@@ -61626,6 +62606,10 @@ async function handleAuthorized(identity2, body, deps, options) {
|
|
|
61626
62606
|
if ("error" in parsed) {
|
|
61627
62607
|
return { status: 400, body: { error: parsed.error } };
|
|
61628
62608
|
}
|
|
62609
|
+
if (identity2.channel !== void 0) {
|
|
62610
|
+
const error = ingressComponentError("channel", identity2.channel);
|
|
62611
|
+
if (error) return { status: 400, body: { error } };
|
|
62612
|
+
}
|
|
61629
62613
|
const receivedAt = systemClock();
|
|
61630
62614
|
const trace = startRequestRoot(deps, { channel: "http", receivedAt });
|
|
61631
62615
|
const msg = {
|
|
@@ -61706,7 +62690,7 @@ function parseIngressTokens(secrets) {
|
|
|
61706
62690
|
if (!parsed.ok) console.error(`[ingress] SWITCHBOARD_INGRESS_TOKENS is ${parsed.reason} \u2014 ingress disabled`);
|
|
61707
62691
|
return { tokens: parsed.tokens };
|
|
61708
62692
|
}
|
|
61709
|
-
var PLATFORM, DEFAULT_CHANNEL, DEFAULT_THREAD, MAX_BODY_BYTES2, HttpIO, DISPATCH_ACTION;
|
|
62693
|
+
var PLATFORM, DEFAULT_CHANNEL, DEFAULT_THREAD, INGRESS_COMPONENT_MAX_LENGTH, MAX_BODY_BYTES2, HttpIO, DISPATCH_ACTION;
|
|
61710
62694
|
var init_http = __esm({
|
|
61711
62695
|
"../../src/channels/http.ts"() {
|
|
61712
62696
|
"use strict";
|
|
@@ -61719,6 +62703,7 @@ var init_http = __esm({
|
|
|
61719
62703
|
PLATFORM = "http";
|
|
61720
62704
|
DEFAULT_CHANNEL = "default";
|
|
61721
62705
|
DEFAULT_THREAD = "default";
|
|
62706
|
+
INGRESS_COMPONENT_MAX_LENGTH = 128;
|
|
61722
62707
|
MAX_BODY_BYTES2 = 1e6;
|
|
61723
62708
|
HttpIO = class {
|
|
61724
62709
|
constructor(priorTurns = []) {
|
|
@@ -61915,7 +62900,7 @@ function openAiStopReason(raw) {
|
|
|
61915
62900
|
}
|
|
61916
62901
|
}
|
|
61917
62902
|
function meterAnthropicMessage(json4) {
|
|
61918
|
-
const msg =
|
|
62903
|
+
const msg = record2(json4);
|
|
61919
62904
|
if (!msg) return {};
|
|
61920
62905
|
const usage = usageFromAnthropic(msg.usage);
|
|
61921
62906
|
return {
|
|
@@ -61924,11 +62909,11 @@ function meterAnthropicMessage(json4) {
|
|
|
61924
62909
|
};
|
|
61925
62910
|
}
|
|
61926
62911
|
function meterOpenAiCompletion(json4) {
|
|
61927
|
-
const body =
|
|
62912
|
+
const body = record2(json4);
|
|
61928
62913
|
if (!body) return {};
|
|
61929
62914
|
const usage = usageFromOpenAI(body.usage);
|
|
61930
62915
|
const reported = reportedCostOf(body.usage);
|
|
61931
|
-
const choice = Array.isArray(body.choices) ?
|
|
62916
|
+
const choice = Array.isArray(body.choices) ? record2(body.choices[0]) : void 0;
|
|
61932
62917
|
return {
|
|
61933
62918
|
...usage ? { usage } : {},
|
|
61934
62919
|
...reported ? { reported } : {},
|
|
@@ -61938,15 +62923,15 @@ function meterOpenAiCompletion(json4) {
|
|
|
61938
62923
|
function responsesStopReason(response) {
|
|
61939
62924
|
const output = Array.isArray(response.output) ? response.output : [];
|
|
61940
62925
|
if (response.status === "completed") {
|
|
61941
|
-
return output.some((item) =>
|
|
62926
|
+
return output.some((item) => record2(item)?.type === "function_call") ? "tool_use" : "end_turn";
|
|
61942
62927
|
}
|
|
61943
62928
|
if (response.status === "incomplete") {
|
|
61944
|
-
return
|
|
62929
|
+
return record2(response.incomplete_details)?.reason === "max_output_tokens" ? "max_tokens" : "other";
|
|
61945
62930
|
}
|
|
61946
62931
|
return "other";
|
|
61947
62932
|
}
|
|
61948
62933
|
function meterResponses(json4) {
|
|
61949
|
-
const body =
|
|
62934
|
+
const body = record2(json4);
|
|
61950
62935
|
if (!body) return {};
|
|
61951
62936
|
const usage = usageFromResponses(body.usage);
|
|
61952
62937
|
const reported = reportedCostOf(body.usage);
|
|
@@ -61968,87 +62953,20 @@ function shapeTools(shape, body, marks) {
|
|
|
61968
62953
|
const allowed2 = new Set(marks.turn.tools);
|
|
61969
62954
|
const table = Array.isArray(body.tools) ? body.tools : [];
|
|
61970
62955
|
const kept = table.filter((t) => {
|
|
61971
|
-
const name = toolNameOf(shape,
|
|
62956
|
+
const name = toolNameOf(shape, record2(t));
|
|
61972
62957
|
return typeof name === "string" && allowed2.has(name);
|
|
61973
62958
|
});
|
|
61974
62959
|
const { tool_choice: _choice, ...rest } = body;
|
|
61975
62960
|
const shaped = { ...rest, tools: kept };
|
|
61976
62961
|
return { body: shaped, toolChoice: toolChoiceWord(shape, void 0, kept.length) };
|
|
61977
62962
|
}
|
|
61978
|
-
function responsesRejectsPattern(pattern) {
|
|
61979
|
-
return /\(\?(?:[=!]|<[=!])/.test(pattern);
|
|
61980
|
-
}
|
|
61981
|
-
function shapeResponsesSchema(value, tool, degradations) {
|
|
61982
|
-
const schema = record(value);
|
|
61983
|
-
if (!schema) {
|
|
61984
|
-
if (!Array.isArray(value)) return { value, changed: false };
|
|
61985
|
-
let changed2 = false;
|
|
61986
|
-
const items = value.map((item) => {
|
|
61987
|
-
const shaped = shapeResponsesSchema(item, tool, degradations);
|
|
61988
|
-
changed2 ||= shaped.changed;
|
|
61989
|
-
return shaped.value;
|
|
61990
|
-
});
|
|
61991
|
-
return { value: changed2 ? items : value, changed: changed2 };
|
|
61992
|
-
}
|
|
61993
|
-
let changed = false;
|
|
61994
|
-
const out = {};
|
|
61995
|
-
for (const [keyword, item] of Object.entries(schema)) {
|
|
61996
|
-
if (keyword === "pattern" && typeof item === "string" && responsesRejectsPattern(item)) {
|
|
61997
|
-
degradations.push({
|
|
61998
|
-
tool,
|
|
61999
|
-
keyword,
|
|
62000
|
-
why: "the Responses wire does not accept regular-expression lookaround"
|
|
62001
|
-
});
|
|
62002
|
-
changed = true;
|
|
62003
|
-
continue;
|
|
62004
|
-
}
|
|
62005
|
-
if ((keyword === "properties" || keyword === "$defs" || keyword === "definitions") && record(item)) {
|
|
62006
|
-
let mapChanged = false;
|
|
62007
|
-
const mapped = {};
|
|
62008
|
-
for (const [name, child] of Object.entries(record(item))) {
|
|
62009
|
-
const shaped = shapeResponsesSchema(child, tool, degradations);
|
|
62010
|
-
mapChanged ||= shaped.changed;
|
|
62011
|
-
mapped[name] = shaped.value;
|
|
62012
|
-
}
|
|
62013
|
-
out[keyword] = mapChanged ? mapped : item;
|
|
62014
|
-
changed ||= mapChanged;
|
|
62015
|
-
continue;
|
|
62016
|
-
}
|
|
62017
|
-
if (["additionalProperties", "allOf", "anyOf", "if", "items", "not", "oneOf", "then", "else"].includes(keyword) && typeof item === "object" && item !== null) {
|
|
62018
|
-
const shaped = shapeResponsesSchema(item, tool, degradations);
|
|
62019
|
-
out[keyword] = shaped.value;
|
|
62020
|
-
changed ||= shaped.changed;
|
|
62021
|
-
continue;
|
|
62022
|
-
}
|
|
62023
|
-
out[keyword] = item;
|
|
62024
|
-
}
|
|
62025
|
-
return { value: changed ? out : value, changed };
|
|
62026
|
-
}
|
|
62027
|
-
function shapeToolSchemasForWire(shape, body) {
|
|
62028
|
-
if (shape !== "openai-responses" || !Array.isArray(body.tools)) return { body, degradations: [] };
|
|
62029
|
-
const degradations = [];
|
|
62030
|
-
let changed = false;
|
|
62031
|
-
const tools = body.tools.map((item) => {
|
|
62032
|
-
const tool = record(item);
|
|
62033
|
-
if (!tool) return item;
|
|
62034
|
-
const name = typeof tool.name === "string" ? tool.name : "unnamed";
|
|
62035
|
-
const shaped = shapeResponsesSchema(tool.parameters, name, degradations);
|
|
62036
|
-
if (!shaped.changed) return item;
|
|
62037
|
-
changed = true;
|
|
62038
|
-
return { ...tool, parameters: shaped.value };
|
|
62039
|
-
});
|
|
62040
|
-
const unique = degradations.filter(
|
|
62041
|
-
(candidate, index, all) => all.findIndex((other) => other.tool === candidate.tool && other.keyword === candidate.keyword) === index
|
|
62042
|
-
);
|
|
62043
|
-
return { body: changed ? { ...body, tools } : body, degradations: unique };
|
|
62044
|
-
}
|
|
62045
62963
|
function toolNameOf(shape, tool) {
|
|
62046
62964
|
if (tool === void 0) return void 0;
|
|
62047
|
-
return shape === "openai-chat" ?
|
|
62965
|
+
return shape === "openai-chat" ? record2(tool.function)?.name : tool.name;
|
|
62048
62966
|
}
|
|
62049
62967
|
function toolSchemaOf(shape, tool) {
|
|
62050
62968
|
if (shape === "anthropic-messages") return tool.input_schema;
|
|
62051
|
-
if (shape === "openai-chat") return
|
|
62969
|
+
if (shape === "openai-chat") return record2(tool.function)?.parameters;
|
|
62052
62970
|
return tool.parameters;
|
|
62053
62971
|
}
|
|
62054
62972
|
function schemaKeywords(value, into = /* @__PURE__ */ new Set()) {
|
|
@@ -62056,12 +62974,12 @@ function schemaKeywords(value, into = /* @__PURE__ */ new Set()) {
|
|
|
62056
62974
|
for (const item of value) schemaKeywords(item, into);
|
|
62057
62975
|
return into;
|
|
62058
62976
|
}
|
|
62059
|
-
const schema =
|
|
62977
|
+
const schema = record2(value);
|
|
62060
62978
|
if (!schema) return into;
|
|
62061
62979
|
for (const [keyword, item] of Object.entries(schema)) {
|
|
62062
62980
|
into.add(keyword);
|
|
62063
|
-
if ((keyword === "properties" || keyword === "$defs" || keyword === "definitions") &&
|
|
62064
|
-
for (const child of Object.values(
|
|
62981
|
+
if ((keyword === "properties" || keyword === "$defs" || keyword === "definitions") && record2(item)) {
|
|
62982
|
+
for (const child of Object.values(record2(item))) schemaKeywords(child, into);
|
|
62065
62983
|
} else {
|
|
62066
62984
|
schemaKeywords(item, into);
|
|
62067
62985
|
}
|
|
@@ -62072,7 +62990,7 @@ function providerErrorProse(body) {
|
|
|
62072
62990
|
const strings2 = (value, into = []) => {
|
|
62073
62991
|
if (typeof value === "string") into.push(value);
|
|
62074
62992
|
else if (Array.isArray(value)) for (const item of value) strings2(item, into);
|
|
62075
|
-
else if (
|
|
62993
|
+
else if (record2(value)) for (const item of Object.values(record2(value))) strings2(item, into);
|
|
62076
62994
|
return into;
|
|
62077
62995
|
};
|
|
62078
62996
|
try {
|
|
@@ -62090,7 +63008,7 @@ function providerSchemaRejectionOf2(shape, body, errorBody) {
|
|
|
62090
63008
|
prose2
|
|
62091
63009
|
))
|
|
62092
63010
|
return void 0;
|
|
62093
|
-
const candidates2 = (Array.isArray(body.tools) ? body.tools : []).map((item) =>
|
|
63011
|
+
const candidates2 = (Array.isArray(body.tools) ? body.tools : []).map((item) => record2(item)).filter((item) => item !== void 0).map((tool) => ({ name: toolNameOf(shape, tool), schema: toolSchemaOf(shape, tool) })).filter(
|
|
62094
63012
|
(tool) => typeof tool.name === "string" && quoted(prose2, tool.name)
|
|
62095
63013
|
);
|
|
62096
63014
|
if (candidates2.length !== 1) return void 0;
|
|
@@ -62113,7 +63031,7 @@ function toolsOffered(shape, body) {
|
|
|
62113
63031
|
const table = Array.isArray(body.tools) ? body.tools : [];
|
|
62114
63032
|
const names = [];
|
|
62115
63033
|
for (const t of table) {
|
|
62116
|
-
const name = toolNameOf(shape,
|
|
63034
|
+
const name = toolNameOf(shape, record2(t));
|
|
62117
63035
|
if (typeof name === "string") names.push(name);
|
|
62118
63036
|
}
|
|
62119
63037
|
names.sort();
|
|
@@ -62126,7 +63044,7 @@ function toolsOffered(shape, body) {
|
|
|
62126
63044
|
function toolChoiceWord(shape, choice, tools) {
|
|
62127
63045
|
if (choice === void 0 || choice === null) return tools > 0 ? "auto" : "none";
|
|
62128
63046
|
if (shape === "anthropic-messages") {
|
|
62129
|
-
const type =
|
|
63047
|
+
const type = record2(choice)?.type;
|
|
62130
63048
|
if (type === "none" || type === "any" || type === "tool") return type;
|
|
62131
63049
|
if (type === "auto") return tools > 0 ? "auto" : "none";
|
|
62132
63050
|
return tools > 0 ? "auto" : "none";
|
|
@@ -62134,7 +63052,7 @@ function toolChoiceWord(shape, choice, tools) {
|
|
|
62134
63052
|
if (choice === "none") return "none";
|
|
62135
63053
|
if (choice === "required") return "any";
|
|
62136
63054
|
if (choice === "auto") return tools > 0 ? "auto" : "none";
|
|
62137
|
-
return
|
|
63055
|
+
return record2(choice) ? "tool" : tools > 0 ? "auto" : "none";
|
|
62138
63056
|
}
|
|
62139
63057
|
function turnAttrs(grant2, meter, ttftMs, offered, price) {
|
|
62140
63058
|
const u = meter.usage;
|
|
@@ -62243,7 +63161,7 @@ async function handleAdmitted(door, req, deps) {
|
|
|
62243
63161
|
} catch {
|
|
62244
63162
|
return refusalResponse(shape, 400, "invalid_body", "the body is not JSON");
|
|
62245
63163
|
}
|
|
62246
|
-
const body =
|
|
63164
|
+
const body = record2(parsed);
|
|
62247
63165
|
if (!body) return refusalResponse(shape, 400, "invalid_body", "the body must be a JSON object");
|
|
62248
63166
|
const upstream = upstreamFor(
|
|
62249
63167
|
shape,
|
|
@@ -62514,7 +63432,7 @@ function createModelProxyHandler(deps) {
|
|
|
62514
63432
|
})();
|
|
62515
63433
|
};
|
|
62516
63434
|
}
|
|
62517
|
-
var ANTHROPIC_MESSAGES_PATH, OPENAI_CHAT_COMPLETIONS_PATH, OPENAI_RESPONSES_PATH, PROXY_PATHS, RESPONSES_MIN_OUTPUT_TOKENS, MAX_PROXY_BODY_BYTES, DEFAULT_ANTHROPIC_BASE_URL, DEFAULT_ANTHROPIC_VERSION, FORWARDED_REQUEST_HEADERS, FORWARDED_RESPONSE_HEADERS,
|
|
63435
|
+
var ANTHROPIC_MESSAGES_PATH, OPENAI_CHAT_COMPLETIONS_PATH, OPENAI_RESPONSES_PATH, PROXY_PATHS, RESPONSES_MIN_OUTPUT_TOKENS, MAX_PROXY_BODY_BYTES, DEFAULT_ANTHROPIC_BASE_URL, DEFAULT_ANTHROPIC_VERSION, FORWARDED_REQUEST_HEADERS, FORWARDED_RESPONSE_HEADERS, record2, SseMeter, MODEL_STREAM_HEARTBEAT;
|
|
62518
63436
|
var init_modelProxy = __esm({
|
|
62519
63437
|
"../../src/channels/modelProxy.ts"() {
|
|
62520
63438
|
"use strict";
|
|
@@ -62522,6 +63440,7 @@ var init_modelProxy = __esm({
|
|
|
62522
63440
|
init_providerFailureAuth();
|
|
62523
63441
|
init_usage();
|
|
62524
63442
|
init_modelPricing();
|
|
63443
|
+
init_providerToolSchemas();
|
|
62525
63444
|
init_provider();
|
|
62526
63445
|
init_http();
|
|
62527
63446
|
ANTHROPIC_MESSAGES_PATH = "/v1/messages";
|
|
@@ -62538,7 +63457,7 @@ var init_modelProxy = __esm({
|
|
|
62538
63457
|
DEFAULT_ANTHROPIC_VERSION = "2023-06-01";
|
|
62539
63458
|
FORWARDED_REQUEST_HEADERS = ["accept", "anthropic-version", "anthropic-beta"];
|
|
62540
63459
|
FORWARDED_RESPONSE_HEADERS = ["content-type", "request-id", "x-request-id"];
|
|
62541
|
-
|
|
63460
|
+
record2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v) ? v : void 0;
|
|
62542
63461
|
SseMeter = class {
|
|
62543
63462
|
constructor(shape) {
|
|
62544
63463
|
this.shape = shape;
|
|
@@ -62582,7 +63501,7 @@ var init_modelProxy = __esm({
|
|
|
62582
63501
|
};
|
|
62583
63502
|
}
|
|
62584
63503
|
apply(json4) {
|
|
62585
|
-
const event =
|
|
63504
|
+
const event = record2(json4);
|
|
62586
63505
|
if (!event) return;
|
|
62587
63506
|
if (this.shape === "openai-responses") {
|
|
62588
63507
|
if (event.type !== "response.completed" && event.type !== "response.incomplete" && event.type !== "response.failed")
|
|
@@ -62595,12 +63514,12 @@ var init_modelProxy = __esm({
|
|
|
62595
63514
|
}
|
|
62596
63515
|
if (this.shape === "anthropic-messages") {
|
|
62597
63516
|
if (event.type === "message_start") {
|
|
62598
|
-
const usage2 = usageFromAnthropic(
|
|
63517
|
+
const usage2 = usageFromAnthropic(record2(event.message)?.usage);
|
|
62599
63518
|
if (usage2) this.usage = { ...this.usage, ...usage2 };
|
|
62600
63519
|
} else if (event.type === "message_delta") {
|
|
62601
|
-
const stop =
|
|
63520
|
+
const stop = record2(event.delta)?.stop_reason;
|
|
62602
63521
|
if (typeof stop === "string") this.stopReason = anthropicStopReason(stop);
|
|
62603
|
-
const usage2 =
|
|
63522
|
+
const usage2 = record2(event.usage);
|
|
62604
63523
|
if (usage2) {
|
|
62605
63524
|
if (typeof usage2.output_tokens === "number") this.usage.outputTokens = usage2.output_tokens;
|
|
62606
63525
|
if (typeof usage2.input_tokens === "number") this.usage.inputTokens = usage2.input_tokens;
|
|
@@ -62613,7 +63532,7 @@ var init_modelProxy = __esm({
|
|
|
62613
63532
|
}
|
|
62614
63533
|
return;
|
|
62615
63534
|
}
|
|
62616
|
-
const choice = Array.isArray(event.choices) ?
|
|
63535
|
+
const choice = Array.isArray(event.choices) ? record2(event.choices[0]) : void 0;
|
|
62617
63536
|
if (typeof choice?.finish_reason === "string") this.stopReason = openAiStopReason(choice.finish_reason);
|
|
62618
63537
|
const usage = usageFromOpenAI(event.usage);
|
|
62619
63538
|
if (usage) this.usage = { ...this.usage, ...usage };
|
|
@@ -62635,7 +63554,7 @@ function bearerOf(headers) {
|
|
|
62635
63554
|
const m = value ? /^Bearer\s+(\S+)$/i.exec(value.trim()) : null;
|
|
62636
63555
|
return m ? m[1] : void 0;
|
|
62637
63556
|
}
|
|
62638
|
-
function
|
|
63557
|
+
function judge4(deps, presented) {
|
|
62639
63558
|
const verdict = deps.bearers.verify(presented);
|
|
62640
63559
|
if (!verdict.ok) {
|
|
62641
63560
|
const status3 = verdict.reason === "unknown_run" ? 404 : verdict.reason === "malformed" ? 401 : verdict.reason === "unknown_bearer" ? 401 : 403;
|
|
@@ -62657,12 +63576,12 @@ function held(path, reason2, runId3) {
|
|
|
62657
63576
|
async function admitHarnessRequest(deps, headers, path) {
|
|
62658
63577
|
const presented = bearerOf(headers);
|
|
62659
63578
|
if (!presented) return { ok: false, response: { status: 401, body: { error: "missing_bearer" } } };
|
|
62660
|
-
let verdict =
|
|
63579
|
+
let verdict = judge4(deps, presented);
|
|
62661
63580
|
if (verdict.ok) return verdict;
|
|
62662
63581
|
if (!RESUME_CAN_OPEN.has(verdict.reason)) return refused6(verdict);
|
|
62663
63582
|
if (!deps.takeover.settled) {
|
|
62664
63583
|
await deps.takeover.whenSettled(DOOR_HOLD_MS);
|
|
62665
|
-
verdict =
|
|
63584
|
+
verdict = judge4(deps, presented);
|
|
62666
63585
|
if (verdict.ok) return verdict;
|
|
62667
63586
|
if (!RESUME_CAN_OPEN.has(verdict.reason)) return refused6(verdict);
|
|
62668
63587
|
if (!deps.takeover.settled) return held(path, "reclaim_pending", verdict.runId);
|
|
@@ -63998,13 +64917,13 @@ async function catchUpMissedMentions(opts) {
|
|
|
63998
64917
|
const orphanCutoffMs = now - (opts.orphanWindowMs ?? ORPHAN_CARD_WINDOW_MS);
|
|
63999
64918
|
const threadCutoffMs = sweep ? Math.min(cutoffMs, orphanCutoffMs) : cutoffMs;
|
|
64000
64919
|
const { client, botUserId } = opts;
|
|
64001
|
-
const
|
|
64920
|
+
const record3 = opts.record ?? recordCatchUpOutcome;
|
|
64002
64921
|
let channels;
|
|
64003
64922
|
try {
|
|
64004
64923
|
channels = await listChannels(client);
|
|
64005
64924
|
} catch (err2) {
|
|
64006
64925
|
log(`[catch-up] cannot list channels: ${errMsg(err2)}`);
|
|
64007
|
-
|
|
64926
|
+
record3({ at: now, channels: 0, missed: 0, skippedChannels: 0, error: errMsg(err2) });
|
|
64008
64927
|
return { channels: 0, missed: 0, orphans: 0, skippedChannels: 0 };
|
|
64009
64928
|
}
|
|
64010
64929
|
const scans = await mapLimit(channels, CATCH_UP_CHANNEL_CONCURRENCY, async (channel) => {
|
|
@@ -64073,7 +64992,7 @@ async function catchUpMissedMentions(opts) {
|
|
|
64073
64992
|
log(
|
|
64074
64993
|
`[catch-up] scanned ${channels.length} channel(s): ${missed} missed message(s), ${orphans} orphaned card(s), ${skippedChannels} skipped`
|
|
64075
64994
|
);
|
|
64076
|
-
|
|
64995
|
+
record3({ at: now, channels: channels.length, missed, skippedChannels });
|
|
64077
64996
|
return { channels: channels.length, missed, orphans, skippedChannels };
|
|
64078
64997
|
}
|
|
64079
64998
|
async function listChannels(client) {
|
|
@@ -65961,11 +66880,19 @@ ${JSON.stringify(result.value)}` }] });
|
|
|
65961
66880
|
if (typeof args.text !== "string" || args.text.trim() === "") {
|
|
65962
66881
|
return err(id, INVALID_PARAMS, "`text` is required and must be a non-empty string");
|
|
65963
66882
|
}
|
|
65964
|
-
if (args.channel !== void 0
|
|
65965
|
-
return err(id, INVALID_PARAMS, "`channel` must be a string");
|
|
66883
|
+
if (args.channel !== void 0) {
|
|
66884
|
+
if (typeof args.channel !== "string") return err(id, INVALID_PARAMS, "`channel` must be a string");
|
|
66885
|
+
const error = ingressComponentError("channel", args.channel);
|
|
66886
|
+
if (error) return err(id, INVALID_PARAMS, error);
|
|
66887
|
+
}
|
|
66888
|
+
if (args.thread !== void 0) {
|
|
66889
|
+
if (typeof args.thread !== "string") return err(id, INVALID_PARAMS, "`thread` must be a string");
|
|
66890
|
+
const error = ingressComponentError("thread", args.thread);
|
|
66891
|
+
if (error) return err(id, INVALID_PARAMS, error);
|
|
65966
66892
|
}
|
|
65967
|
-
if (
|
|
65968
|
-
|
|
66893
|
+
if (identity2.channel !== void 0) {
|
|
66894
|
+
const error = ingressComponentError("channel", identity2.channel);
|
|
66895
|
+
if (error) return err(id, INVALID_PARAMS, error);
|
|
65969
66896
|
}
|
|
65970
66897
|
const receivedAt = systemClock();
|
|
65971
66898
|
const trace = startRequestRoot(deps, { channel: "mcp", receivedAt });
|
|
@@ -67601,16 +68528,16 @@ function residentStateTone(state) {
|
|
|
67601
68528
|
}
|
|
67602
68529
|
function residentsFleetTone(records) {
|
|
67603
68530
|
if (records.length === 0) return "grey";
|
|
67604
|
-
const tones = new Set(records.map((
|
|
68531
|
+
const tones = new Set(records.map((record3) => residentStateTone(residentLive(rec(record3)).state)));
|
|
67605
68532
|
if (tones.has("red")) return "red";
|
|
67606
68533
|
if (tones.has("amber")) return "amber";
|
|
67607
68534
|
return tones.size === 1 && tones.has("green") ? "green" : "grey";
|
|
67608
68535
|
}
|
|
67609
|
-
function residentSlug(
|
|
67610
|
-
return str8(
|
|
68536
|
+
function residentSlug(record3) {
|
|
68537
|
+
return str8(record3.resource).replace(/^repo:/, "");
|
|
67611
68538
|
}
|
|
67612
|
-
function residentLive(
|
|
67613
|
-
const live = rec(
|
|
68539
|
+
function residentLive(record3) {
|
|
68540
|
+
const live = rec(record3.live);
|
|
67614
68541
|
if (typeof live.error === "string") return { ...live, state: "unreachable", reason: live.error };
|
|
67615
68542
|
return { ...live, state: str8(live.state) || "unknown", reason: str8(live.reason) };
|
|
67616
68543
|
}
|
|
@@ -67910,12 +68837,12 @@ function createResidentsViewHandler(deps) {
|
|
|
67910
68837
|
finish2(200);
|
|
67911
68838
|
return;
|
|
67912
68839
|
}
|
|
67913
|
-
const
|
|
67914
|
-
if (!
|
|
68840
|
+
const record3 = listing.residents.find((x) => residentSlug(x) === route2.slug);
|
|
68841
|
+
if (!record3) {
|
|
67915
68842
|
plainEnd(404, `${route2.slug} is not onboarded as a resident`);
|
|
67916
68843
|
return;
|
|
67917
68844
|
}
|
|
67918
|
-
page2(req, res, 200, ctx.actor, route2.slug, { page: "resident", slug: route2.slug, record:
|
|
68845
|
+
page2(req, res, 200, ctx.actor, route2.slug, { page: "resident", slug: route2.slug, record: record3 });
|
|
67919
68846
|
finish2(200);
|
|
67920
68847
|
});
|
|
67921
68848
|
return true;
|
|
@@ -70057,9 +70984,9 @@ function startReclaimSweep(opts) {
|
|
|
70057
70984
|
return { stop: () => stop(timer) };
|
|
70058
70985
|
}
|
|
70059
70986
|
async function closeReclaimed(ledger, gen, input) {
|
|
70060
|
-
const
|
|
70061
|
-
const result = await ledger.finish(input.row.runId, gen,
|
|
70062
|
-
return result.ok ? { ok: true, record:
|
|
70987
|
+
const record3 = reclaimedRunRecord(input);
|
|
70988
|
+
const result = await ledger.finish(input.row.runId, gen, record3);
|
|
70989
|
+
return result.ok ? { ok: true, record: record3 } : { ok: false, reason: result.reason ?? "refused" };
|
|
70063
70990
|
}
|
|
70064
70991
|
async function completenessVerdict(ledger, row2, lastStep) {
|
|
70065
70992
|
if (!lastStep) return { resumable: false, why: "no step record: killed before its conversation was stored" };
|
|
@@ -70226,7 +71153,13 @@ async function launchResumes(deps, resumable, opts) {
|
|
|
70226
71153
|
const handle2 = registry.create(row2.meta.label, rehostMeta(row2), {
|
|
70227
71154
|
id: row2.runId,
|
|
70228
71155
|
startedAt: row2.startedAt,
|
|
70229
|
-
replay: run2.events
|
|
71156
|
+
replay: run2.events,
|
|
71157
|
+
...row2.liveState !== void 0 ? {
|
|
71158
|
+
liveState: {
|
|
71159
|
+
liveState: row2.liveState,
|
|
71160
|
+
...row2.liveStateSeq !== void 0 ? { liveStateSeq: row2.liveStateSeq } : {}
|
|
71161
|
+
}
|
|
71162
|
+
} : {}
|
|
70230
71163
|
});
|
|
70231
71164
|
const adopted = deps.runLedger.adopt({
|
|
70232
71165
|
runId: row2.runId,
|
|
@@ -70667,6 +71600,72 @@ var init_adminModelProxy = __esm({
|
|
|
70667
71600
|
}
|
|
70668
71601
|
});
|
|
70669
71602
|
|
|
71603
|
+
// ../../src/core/providerLiveStateCoordinator.ts
|
|
71604
|
+
function createProviderLiveStateCoordinator(deps) {
|
|
71605
|
+
let tail = Promise.resolve();
|
|
71606
|
+
const enqueue = (label, work) => {
|
|
71607
|
+
const next = tail.then(work).catch((error) => {
|
|
71608
|
+
deps.warn(`${label} failed: ${describe11(error)}`);
|
|
71609
|
+
});
|
|
71610
|
+
tail = next;
|
|
71611
|
+
return next;
|
|
71612
|
+
};
|
|
71613
|
+
return {
|
|
71614
|
+
level: (provider, side, cause) => enqueue(`provider ${side} report for ${provider}`, async () => {
|
|
71615
|
+
await deps.runLedger.planeLevel({
|
|
71616
|
+
provider,
|
|
71617
|
+
name: "provider",
|
|
71618
|
+
side,
|
|
71619
|
+
...side === "down" && cause !== void 0 ? { cause } : {}
|
|
71620
|
+
});
|
|
71621
|
+
if (side !== "up" || !deps.ledger) return;
|
|
71622
|
+
const rows = await deps.ledger.listLive();
|
|
71623
|
+
for (const row2 of rows) {
|
|
71624
|
+
if (row2.state.liveProvider !== provider || row2.liveState?.state !== "waiting_provider") continue;
|
|
71625
|
+
const tracked = deps.runLedger.liveRuns().find((run2) => run2.runId === row2.runId);
|
|
71626
|
+
const summary = deps.registry.getById(row2.runId);
|
|
71627
|
+
if (!tracked || !summary || row2.liveState.bound === void 0) continue;
|
|
71628
|
+
const committed = await tracked.assignLiveState({
|
|
71629
|
+
expectedSeq: summary.liveStateSeq ?? 0,
|
|
71630
|
+
eventSeq: summary.eventCount + 1,
|
|
71631
|
+
at: deps.clock(),
|
|
71632
|
+
state: "working",
|
|
71633
|
+
bound: row2.liveState.bound,
|
|
71634
|
+
detail: "model turn",
|
|
71635
|
+
statePatch: { liveProvider: void 0 }
|
|
71636
|
+
});
|
|
71637
|
+
if (committed.ok) deps.registry.commitLiveState(row2.runId, committed);
|
|
71638
|
+
}
|
|
71639
|
+
}),
|
|
71640
|
+
park: (runId3, provider) => enqueue(`provider park for ${runId3}`, async () => {
|
|
71641
|
+
await deps.runLedger.planePark(runId3, provider);
|
|
71642
|
+
const summary = deps.registry.getById(runId3);
|
|
71643
|
+
const tracked = deps.runLedger.liveRuns().find((run2) => run2.runId === runId3);
|
|
71644
|
+
const events = deps.registry.snapshotById(runId3)?.events ?? [];
|
|
71645
|
+
let leaseEndsAt;
|
|
71646
|
+
for (const event of events) if (event.type === "lease") leaseEndsAt = event.endsAt;
|
|
71647
|
+
if (!summary || !tracked || leaseEndsAt === void 0) return;
|
|
71648
|
+
const committed = await tracked.assignLiveState({
|
|
71649
|
+
expectedSeq: summary.liveStateSeq ?? 0,
|
|
71650
|
+
eventSeq: summary.eventCount + 1,
|
|
71651
|
+
at: deps.clock(),
|
|
71652
|
+
state: "waiting_provider",
|
|
71653
|
+
bound: leaseEndsAt,
|
|
71654
|
+
detail: "waiting for the model provider",
|
|
71655
|
+
statePatch: { liveProvider: provider }
|
|
71656
|
+
});
|
|
71657
|
+
if (committed.ok) deps.registry.commitLiveState(runId3, committed);
|
|
71658
|
+
})
|
|
71659
|
+
};
|
|
71660
|
+
}
|
|
71661
|
+
var describe11;
|
|
71662
|
+
var init_providerLiveStateCoordinator = __esm({
|
|
71663
|
+
"../../src/core/providerLiveStateCoordinator.ts"() {
|
|
71664
|
+
"use strict";
|
|
71665
|
+
describe11 = (error) => error instanceof Error ? error.message : String(error);
|
|
71666
|
+
}
|
|
71667
|
+
});
|
|
71668
|
+
|
|
70670
71669
|
// ../../src/channels/adminTraceLog.ts
|
|
70671
71670
|
function parseTraceLogQuery(search) {
|
|
70672
71671
|
const query = {};
|
|
@@ -71176,7 +72175,7 @@ async function openThreadFromRequester(deps, instance, lead, at) {
|
|
|
71176
72175
|
}
|
|
71177
72176
|
};
|
|
71178
72177
|
} catch (err2) {
|
|
71179
|
-
return { ok: false, response: json3(502, { ok: false, error: "thread_failed", message:
|
|
72178
|
+
return { ok: false, response: json3(502, { ok: false, error: "thread_failed", message: describe12(err2), at }) };
|
|
71180
72179
|
}
|
|
71181
72180
|
}
|
|
71182
72181
|
function authorizeStep(headers, step, deps) {
|
|
@@ -71300,8 +72299,8 @@ async function spawn6(body, deps) {
|
|
|
71300
72299
|
try {
|
|
71301
72300
|
turn = await composeChild(req.brief, instance, row2, briefReaders(deps, instance));
|
|
71302
72301
|
} catch (err2) {
|
|
71303
|
-
log(`[coordinator] ${instance.id} ${req.step}: the brief could not be composed: ${
|
|
71304
|
-
return json3(502, { ok: false, error: "brief_failed", message:
|
|
72302
|
+
log(`[coordinator] ${instance.id} ${req.step}: the brief could not be composed: ${describe12(err2)}`);
|
|
72303
|
+
return json3(502, { ok: false, error: "brief_failed", message: describe12(err2), at });
|
|
71305
72304
|
}
|
|
71306
72305
|
} else {
|
|
71307
72306
|
turn = { prompt: req.prompt };
|
|
@@ -71371,7 +72370,7 @@ ${foldThreadEvents(folded)}` };
|
|
|
71371
72370
|
});
|
|
71372
72371
|
} catch (err2) {
|
|
71373
72372
|
releaseAdmission();
|
|
71374
|
-
return json3(502, { ok: false, error: "spawn_failed", message:
|
|
72373
|
+
return json3(502, { ok: false, error: "spawn_failed", message: describe12(err2), at });
|
|
71375
72374
|
}
|
|
71376
72375
|
const settled = dispatching.then(
|
|
71377
72376
|
(outcome) => ({ kind: "ended", outcome }),
|
|
@@ -71380,7 +72379,7 @@ ${foldThreadEvents(folded)}` };
|
|
|
71380
72379
|
void settled.then((end) => {
|
|
71381
72380
|
releaseAdmission();
|
|
71382
72381
|
if (end.kind === "threw")
|
|
71383
|
-
log(`[coordinator] ${instance.id} ${req.step}: the child's dispatch threw: ${
|
|
72382
|
+
log(`[coordinator] ${instance.id} ${req.step}: the child's dispatch threw: ${describe12(end.err)}`);
|
|
71384
72383
|
});
|
|
71385
72384
|
const first = await Promise.race([started.then((id) => ({ kind: "started", id })), settled]);
|
|
71386
72385
|
if (first.kind === "started" || startedId !== void 0) {
|
|
@@ -71390,7 +72389,7 @@ ${foldThreadEvents(folded)}` };
|
|
|
71390
72389
|
{ instanceId: instance.id, unit: row2.unit },
|
|
71391
72390
|
folded.map((e) => e.seq),
|
|
71392
72391
|
req.step
|
|
71393
|
-
).catch((err2) => log(`[coordinator] ${instance.id} ${req.step}: the consumed marks failed: ${
|
|
72392
|
+
).catch((err2) => log(`[coordinator] ${instance.id} ${req.step}: the consumed marks failed: ${describe12(err2)}`));
|
|
71394
72393
|
log(
|
|
71395
72394
|
`[coordinator] ${instance.id} ${req.step}: folded ${folded.length} thread event(s) into the ${req.preset} child`
|
|
71396
72395
|
);
|
|
@@ -71398,7 +72397,7 @@ ${foldThreadEvents(folded)}` };
|
|
|
71398
72397
|
log(`[coordinator] ${instance.id} ${req.step}: spawned ${req.preset} run ${runId3} in ${threadKey}`);
|
|
71399
72398
|
return json3(200, { ok: true, runId: runId3, threadKey, at });
|
|
71400
72399
|
}
|
|
71401
|
-
if (first.kind === "threw") return json3(502, { ok: false, error: "spawn_failed", message:
|
|
72400
|
+
if (first.kind === "threw") return json3(502, { ok: false, error: "spawn_failed", message: describe12(first.err), at });
|
|
71402
72401
|
const refusal = first.outcome.refusal;
|
|
71403
72402
|
if (refusal === "coordinator_thread_live") {
|
|
71404
72403
|
const now = await liveOnThread(deps.runs, instance, threadKey);
|
|
@@ -71537,11 +72536,11 @@ async function reviewPostedAtPatiently(deps, pr, verdict, head) {
|
|
|
71537
72536
|
}
|
|
71538
72537
|
return answer;
|
|
71539
72538
|
}
|
|
71540
|
-
function reviewPostedByRecord(
|
|
71541
|
-
const post =
|
|
71542
|
-
if (post === void 0 ||
|
|
72539
|
+
function reviewPostedByRecord(record3, pr) {
|
|
72540
|
+
const post = record3.reviewPost;
|
|
72541
|
+
if (post === void 0 || record3.reviewHead === void 0 || record3.verdict === void 0) return void 0;
|
|
71543
72542
|
if (!post.posted) return { reviewPosted: false, reviewPostReason: post.reason };
|
|
71544
|
-
const same = post.target.repo === pr.repo && post.target.number === pr.number && sameCommit(post.head.toLowerCase(),
|
|
72543
|
+
const same = post.target.repo === pr.repo && post.target.number === pr.number && sameCommit(post.head.toLowerCase(), record3.reviewHead) && post.verdict === record3.verdict.verdict;
|
|
71545
72544
|
return same ? { reviewPosted: true } : void 0;
|
|
71546
72545
|
}
|
|
71547
72546
|
function headBranchStateUnknown(facts2) {
|
|
@@ -71558,6 +72557,7 @@ function pullRequestState(number, fallbackUrl, facts2) {
|
|
|
71558
72557
|
state: "merged",
|
|
71559
72558
|
prNumber: number,
|
|
71560
72559
|
url,
|
|
72560
|
+
...facts2.headSha !== void 0 ? { headSha: facts2.headSha } : {},
|
|
71561
72561
|
sha: facts2.mergeCommitSha,
|
|
71562
72562
|
mergedAt: facts2.mergedAt,
|
|
71563
72563
|
...facts2.mergedBy !== void 0 ? { mergedBy: facts2.mergedBy } : {}
|
|
@@ -71618,7 +72618,7 @@ async function readRecord(body, deps) {
|
|
|
71618
72618
|
try {
|
|
71619
72619
|
pullRequest = await childPullRequestState(deps, instanceRow, typeof body.unit === "string" ? body.unit : void 0);
|
|
71620
72620
|
} catch (err2) {
|
|
71621
|
-
return json3(502, { ok: false, error: "github_unavailable", message:
|
|
72621
|
+
return json3(502, { ok: false, error: "github_unavailable", message: describe12(err2), at });
|
|
71622
72622
|
}
|
|
71623
72623
|
if (!view.finished)
|
|
71624
72624
|
return json3(200, {
|
|
@@ -71628,15 +72628,16 @@ async function readRecord(body, deps) {
|
|
|
71628
72628
|
at
|
|
71629
72629
|
});
|
|
71630
72630
|
const full = await deps.runs.getRun(body.runId, { include: "messages" });
|
|
71631
|
-
const
|
|
71632
|
-
const finalReply = finalReplyOf2(
|
|
71633
|
-
const reviewAskedAt = reviewAskedAtOf(
|
|
71634
|
-
const
|
|
72631
|
+
const record3 = full.ok ? full.value : view;
|
|
72632
|
+
const finalReply = finalReplyOf2(record3.events);
|
|
72633
|
+
const reviewAskedAt = reviewAskedAtOf(record3.events);
|
|
72634
|
+
const description = record3.events?.some((event) => event.type === "pr_description") === true;
|
|
72635
|
+
const opened = prOpenedOf(record3.events);
|
|
71635
72636
|
const pr = opened !== void 0 ? { number: opened.number, url: opened.url, created: opened.created } : void 0;
|
|
71636
72637
|
let coordinatorUnit;
|
|
71637
72638
|
if (instanceRow !== null && typeof body.unit === "string") {
|
|
71638
72639
|
coordinatorUnit = (await deps.instances.listUnits(instanceRow.id)).find((u) => u.unit === body.unit);
|
|
71639
|
-
const pushedPrRef = opened?.head !== void 0 &&
|
|
72640
|
+
const pushedPrRef = opened?.head !== void 0 && record3.pushed?.some((pushed) => pushed.ref === opened.head) ? opened.head : void 0;
|
|
71640
72641
|
if (coordinatorUnit !== void 0 && pushedPrRef !== void 0 && coordinatorUnit.branch !== pushedPrRef) {
|
|
71641
72642
|
coordinatorUnit = { ...coordinatorUnit, branch: pushedPrRef };
|
|
71642
72643
|
await deps.instances.putUnits([coordinatorUnit]);
|
|
@@ -71663,13 +72664,13 @@ async function readRecord(body, deps) {
|
|
|
71663
72664
|
});
|
|
71664
72665
|
}
|
|
71665
72666
|
let posted;
|
|
71666
|
-
if (
|
|
72667
|
+
if (record3.verdict !== void 0 && record3.reviewHead !== void 0 && typeof body.unit === "string") {
|
|
71667
72668
|
const instance = instanceRow;
|
|
71668
72669
|
if (instance && coordinatorUnit?.pr !== void 0) {
|
|
71669
72670
|
const unitPr = { repo: instance.repo, number: coordinatorUnit.pr.number };
|
|
71670
|
-
posted = reviewPostedByRecord(
|
|
72671
|
+
posted = reviewPostedByRecord(record3, unitPr);
|
|
71671
72672
|
if (posted === void 0) {
|
|
71672
|
-
const seen = await reviewPostedAtPatiently(deps, unitPr,
|
|
72673
|
+
const seen = await reviewPostedAtPatiently(deps, unitPr, record3.verdict.verdict, record3.reviewHead);
|
|
71673
72674
|
if (seen !== void 0) posted = { reviewPosted: seen };
|
|
71674
72675
|
}
|
|
71675
72676
|
}
|
|
@@ -71681,27 +72682,31 @@ async function readRecord(body, deps) {
|
|
|
71681
72682
|
run: {
|
|
71682
72683
|
...coordinatorRunView(view, id.value, finalReply),
|
|
71683
72684
|
...pr !== void 0 ? { pr } : {},
|
|
71684
|
-
...
|
|
71685
|
-
...
|
|
72685
|
+
...record3.verdict !== void 0 ? { verdict: record3.verdict } : {},
|
|
72686
|
+
...record3.reviewHead !== void 0 ? { reviewHead: record3.reviewHead } : {},
|
|
71686
72687
|
...reviewAskedAt !== void 0 ? { reviewAskedAt } : {},
|
|
71687
72688
|
...posted !== void 0 ? { reviewPosted: posted.reviewPosted } : {},
|
|
71688
72689
|
...posted?.reviewPostReason !== void 0 ? { reviewPostReason: posted.reviewPostReason } : {},
|
|
71689
|
-
...
|
|
71690
|
-
|
|
72690
|
+
...record3.dispositions !== void 0 ? { dispositions: record3.dispositions } : {},
|
|
72691
|
+
// Findings readiness requires the typed description output. Its event is
|
|
72692
|
+
// durable on the child record, so the runner can verify it without
|
|
72693
|
+
// trusting final-reply prose.
|
|
72694
|
+
...description ? { description: true } : {},
|
|
72695
|
+
...record3.handoff !== void 0 ? { handoff: true } : {},
|
|
71691
72696
|
// The renewal's facts (decision 0046): progress is read off these.
|
|
71692
|
-
...
|
|
71693
|
-
...
|
|
72697
|
+
...record3.pushed !== void 0 ? { pushed: record3.pushed } : {},
|
|
72698
|
+
...record3.lease !== void 0 ? { leaseStartedAt: record3.lease.startedAt } : {},
|
|
71694
72699
|
// What the child cost, as the runs service prices it (costs.md item 4c):
|
|
71695
72700
|
// null when unknown — no usage on the record, or a model without a price
|
|
71696
72701
|
// — so a capped grant never renews on an understated total.
|
|
71697
|
-
costUsd:
|
|
71698
|
-
...
|
|
72702
|
+
costUsd: record3.cost?.usd ?? null,
|
|
72703
|
+
...record3.handoff !== void 0 ? { handoffLists: record3.handoff } : {},
|
|
71699
72704
|
// The failure by name (run-history item 57): a `provider_transient` lets
|
|
71700
72705
|
// the machine re-run a round-0 child that pushed nothing (issue 1932).
|
|
71701
|
-
...
|
|
72706
|
+
...record3.failure !== void 0 ? { failure: record3.failure } : {},
|
|
71702
72707
|
// What ended an interrupted child (issue 1876), off its record's own
|
|
71703
72708
|
// events: the unit's ending names the actual cause in the user's nouns.
|
|
71704
|
-
...view.status === "interrupted" ? interruptionOf(
|
|
72709
|
+
...view.status === "interrupted" ? interruptionOf(record3.events) : {}
|
|
71705
72710
|
},
|
|
71706
72711
|
at
|
|
71707
72712
|
});
|
|
@@ -71780,6 +72785,13 @@ async function recoverPushedBranch(deps, instance, row2, branch2, runId3) {
|
|
|
71780
72785
|
if (subject2 !== void 0 && checkPrTitle(subject2, prTitleVocabulary_default).ok) title = subject2;
|
|
71781
72786
|
}
|
|
71782
72787
|
title ??= recoveredFallbackTitle(row2, branch2, instance.plan?.id ?? parsePlanBranch(branch2)?.planId);
|
|
72788
|
+
const header4 = requestedByLine({
|
|
72789
|
+
name: instance.userName?.trim() || instance.userId,
|
|
72790
|
+
threadUrl: threadPageLink(instance.threadKey, deps.runPageBase?.replace(/\/runs\/?$/, "") ?? "")
|
|
72791
|
+
});
|
|
72792
|
+
prBody = `${header4}
|
|
72793
|
+
|
|
72794
|
+
${prBody}`;
|
|
71783
72795
|
if (deps.rewriteIdentities !== void 0) {
|
|
71784
72796
|
const rewritten = await deps.rewriteIdentities({
|
|
71785
72797
|
repo: instance.repo,
|
|
@@ -71934,7 +72946,7 @@ async function prCheck(body, deps) {
|
|
|
71934
72946
|
if (recover === void 0) {
|
|
71935
72947
|
const ahead = instance.base === void 0 ? void 0 : await deps.commitsOverBase(instance.repo, instance.base, branch2).catch((err2) => {
|
|
71936
72948
|
(deps.log ?? console.log)(
|
|
71937
|
-
`[coordinator] ${instance.id} pr-check: the compare of ${branch2} over ${instance.base} could not be read: ${
|
|
72949
|
+
`[coordinator] ${instance.id} pr-check: the compare of ${branch2} over ${instance.base} could not be read: ${describe12(err2)}`
|
|
71938
72950
|
);
|
|
71939
72951
|
return void 0;
|
|
71940
72952
|
});
|
|
@@ -71958,7 +72970,7 @@ async function prCheck(body, deps) {
|
|
|
71958
72970
|
if (state?.state !== "merged") throw new Error(`${instance.repo}#${merged.number} no longer reads merged`);
|
|
71959
72971
|
return json3(200, { ok: true, ...state, at });
|
|
71960
72972
|
} catch (err2) {
|
|
71961
|
-
return json3(502, { ok: false, error: "github_unavailable", message:
|
|
72973
|
+
return json3(502, { ok: false, error: "github_unavailable", message: describe12(err2), at });
|
|
71962
72974
|
}
|
|
71963
72975
|
}
|
|
71964
72976
|
async function hostRunOf(deps, instance) {
|
|
@@ -71971,14 +72983,68 @@ async function hostRunOf(deps, instance) {
|
|
|
71971
72983
|
return { kind: "not_host" };
|
|
71972
72984
|
return { kind: "untracked" };
|
|
71973
72985
|
}
|
|
71974
|
-
function hostPublish(deps, instance, runId3, events, at) {
|
|
71975
|
-
for (const event of events) deps.registry.publish(runId3, event);
|
|
72986
|
+
async function hostPublish(deps, instance, runId3, events, at) {
|
|
71976
72987
|
const caps = instance.caps ?? resolveShipCaps(void 0);
|
|
71977
72988
|
const hosting = {
|
|
71978
72989
|
instanceId: instance.id,
|
|
71979
72990
|
until: at + minutesToMs(caps.maxMinutes + HOSTED_DEADLINE_MARGIN_MINUTES)
|
|
71980
72991
|
};
|
|
71981
|
-
deps.ledgerRuns().find((run2) => run2.runId === runId3)
|
|
72992
|
+
const ledgerRun = deps.ledgerRuns().find((run2) => run2.runId === runId3);
|
|
72993
|
+
let summary = deps.registry.getById(runId3);
|
|
72994
|
+
if (ledgerRun && summary) {
|
|
72995
|
+
if (summary.liveState === void 0) {
|
|
72996
|
+
const admitted = await ledgerRun.assignLiveState({
|
|
72997
|
+
expectedSeq: 0,
|
|
72998
|
+
eventSeq: summary.eventCount + 1,
|
|
72999
|
+
at,
|
|
73000
|
+
state: "admitted",
|
|
73001
|
+
bound: hosting.until,
|
|
73002
|
+
detail: "waiting for the pipeline hand-off"
|
|
73003
|
+
});
|
|
73004
|
+
if (!admitted.ok || !deps.registry.commitLiveState(runId3, admitted))
|
|
73005
|
+
throw new Error(
|
|
73006
|
+
`hosted live state backfill was not committed (${admitted.ok ? "registry sequence" : admitted.reason})`
|
|
73007
|
+
);
|
|
73008
|
+
summary = deps.registry.getById(runId3);
|
|
73009
|
+
if (!summary) throw new Error("hosted run disappeared during live-state backfill");
|
|
73010
|
+
const working = await ledgerRun.assignLiveState({
|
|
73011
|
+
expectedSeq: summary.liveStateSeq ?? 0,
|
|
73012
|
+
eventSeq: summary.eventCount + 1,
|
|
73013
|
+
at,
|
|
73014
|
+
state: "working",
|
|
73015
|
+
bound: hosting.until,
|
|
73016
|
+
detail: "pipeline starting",
|
|
73017
|
+
statePatch: { hosting }
|
|
73018
|
+
});
|
|
73019
|
+
if (!working.ok || !deps.registry.commitLiveState(runId3, working))
|
|
73020
|
+
throw new Error(
|
|
73021
|
+
`hosted working backfill was not committed (${working.ok ? "registry sequence" : working.reason})`
|
|
73022
|
+
);
|
|
73023
|
+
summary = deps.registry.getById(runId3);
|
|
73024
|
+
if (!summary) throw new Error("hosted run disappeared after live-state backfill");
|
|
73025
|
+
}
|
|
73026
|
+
const firstSeq = summary.eventCount + 1;
|
|
73027
|
+
const sourceEvents = events.map((event, index) => ({ ...event, seq: firstSeq + index }));
|
|
73028
|
+
const prior = deps.registry.snapshotById(runId3)?.events.filter((event) => event.type === "ship_round" || event.type === "ship_unit") ?? [];
|
|
73029
|
+
const standing = pipelineStandingOf([...prior, ...events]);
|
|
73030
|
+
const stage = standing.changes.at(-1)?.stage ?? "idle";
|
|
73031
|
+
const committed = await ledgerRun.assignLiveState({
|
|
73032
|
+
expectedSeq: summary.liveStateSeq ?? 0,
|
|
73033
|
+
at,
|
|
73034
|
+
state: "working",
|
|
73035
|
+
bound: hosting.until,
|
|
73036
|
+
detail: hostedStageDetail(stage),
|
|
73037
|
+
statePatch: { hosting },
|
|
73038
|
+
sourceEvents
|
|
73039
|
+
});
|
|
73040
|
+
if (!committed.ok || !deps.registry.commitLiveState(runId3, committed))
|
|
73041
|
+
throw new Error(
|
|
73042
|
+
`hosted live state refresh was not committed (${committed.ok ? "registry sequence" : committed.reason})`
|
|
73043
|
+
);
|
|
73044
|
+
} else {
|
|
73045
|
+
ledgerRun?.setState({ hosting });
|
|
73046
|
+
}
|
|
73047
|
+
for (const event of events) deps.registry.publish(runId3, event);
|
|
71982
73048
|
}
|
|
71983
73049
|
function namesForeignRun(instance, body) {
|
|
71984
73050
|
return typeof body.runId === "string" && body.runId !== instance.runId;
|
|
@@ -72064,7 +73130,7 @@ async function unitStart(body, deps) {
|
|
|
72064
73130
|
row2 = { ...row2, startedAt: row2.startedAt ?? at };
|
|
72065
73131
|
await deps.instances.putUnits([row2]);
|
|
72066
73132
|
if (host.kind === "host")
|
|
72067
|
-
hostPublish(
|
|
73133
|
+
await hostPublish(
|
|
72068
73134
|
deps,
|
|
72069
73135
|
instance,
|
|
72070
73136
|
host.runId,
|
|
@@ -72113,7 +73179,7 @@ async function branch(body, deps) {
|
|
|
72113
73179
|
await deps.createBranchRef(instance.repo, name, base);
|
|
72114
73180
|
return json3(200, { ok: true, branch: name, base, at });
|
|
72115
73181
|
} catch (err2) {
|
|
72116
|
-
return json3(200, { ok: false, reason:
|
|
73182
|
+
return json3(200, { ok: false, reason: describe12(err2), at });
|
|
72117
73183
|
}
|
|
72118
73184
|
}
|
|
72119
73185
|
function unitLines(units, generated, severity) {
|
|
@@ -72194,7 +73260,7 @@ async function round(body, deps) {
|
|
|
72194
73260
|
await deps.instances.putUnits([updated]);
|
|
72195
73261
|
if (host.kind === "host") {
|
|
72196
73262
|
const thread = unitThread(instance, updated, units.length);
|
|
72197
|
-
hostPublish(
|
|
73263
|
+
await hostPublish(
|
|
72198
73264
|
deps,
|
|
72199
73265
|
instance,
|
|
72200
73266
|
host.runId,
|
|
@@ -72228,7 +73294,7 @@ async function round(body, deps) {
|
|
|
72228
73294
|
instance,
|
|
72229
73295
|
units.map((u) => u.unit === updated.unit ? updated : u)
|
|
72230
73296
|
).catch(
|
|
72231
|
-
(err2) => (deps.log ?? console.warn)(`[coordinator] ${instance.id}: the card could not be redrawn: ${
|
|
73297
|
+
(err2) => (deps.log ?? console.warn)(`[coordinator] ${instance.id}: the card could not be redrawn: ${describe12(err2)}`)
|
|
72232
73298
|
);
|
|
72233
73299
|
return json3(200, { ok: true, at });
|
|
72234
73300
|
}
|
|
@@ -72402,7 +73468,7 @@ async function unitWake(body, deps) {
|
|
|
72402
73468
|
instance,
|
|
72403
73469
|
units.map((u) => u.unit === visible.unit ? visible : u)
|
|
72404
73470
|
).catch(
|
|
72405
|
-
(err2) => (deps.log ?? console.warn)(`[coordinator] ${instance.id}: the card could not be redrawn: ${
|
|
73471
|
+
(err2) => (deps.log ?? console.warn)(`[coordinator] ${instance.id}: the card could not be redrawn: ${describe12(err2)}`)
|
|
72406
73472
|
);
|
|
72407
73473
|
return json3(200, { ok: true, answer, at });
|
|
72408
73474
|
}
|
|
@@ -72465,7 +73531,7 @@ async function unitEnd(body, deps) {
|
|
|
72465
73531
|
deps.runnerOwnership?.release(instance.repo, updated.pr.number);
|
|
72466
73532
|
const thread = unitThread(instance, updated, units.length);
|
|
72467
73533
|
if (host.kind === "host")
|
|
72468
|
-
hostPublish(
|
|
73534
|
+
await hostPublish(
|
|
72469
73535
|
deps,
|
|
72470
73536
|
instance,
|
|
72471
73537
|
host.runId,
|
|
@@ -72496,7 +73562,7 @@ async function unitEnd(body, deps) {
|
|
|
72496
73562
|
`unit-end:${row2.unit}`
|
|
72497
73563
|
).catch(
|
|
72498
73564
|
(err2) => (deps.log ?? console.warn)(
|
|
72499
|
-
`[coordinator] ${instance.id} ${row2.unit}: the leftover marks failed: ${
|
|
73565
|
+
`[coordinator] ${instance.id} ${row2.unit}: the leftover marks failed: ${describe12(err2)}`
|
|
72500
73566
|
)
|
|
72501
73567
|
);
|
|
72502
73568
|
const freshTurn = {
|
|
@@ -72514,7 +73580,7 @@ async function unitEnd(body, deps) {
|
|
|
72514
73580
|
};
|
|
72515
73581
|
void deps.dispatch(freshTurn, io).catch(
|
|
72516
73582
|
(err2) => (deps.log ?? console.warn)(
|
|
72517
|
-
`[coordinator] ${instance.id} ${row2.unit}: the leftovers' fresh turn threw: ${
|
|
73583
|
+
`[coordinator] ${instance.id} ${row2.unit}: the leftovers' fresh turn threw: ${describe12(err2)}`
|
|
72518
73584
|
)
|
|
72519
73585
|
);
|
|
72520
73586
|
(deps.log ?? console.log)(
|
|
@@ -72531,7 +73597,7 @@ async function unitEnd(body, deps) {
|
|
|
72531
73597
|
told = true;
|
|
72532
73598
|
} catch (err2) {
|
|
72533
73599
|
(deps.log ?? console.warn)(
|
|
72534
|
-
`[coordinator] ${instance.id} ${row2.unit}: the report could not be posted: ${
|
|
73600
|
+
`[coordinator] ${instance.id} ${row2.unit}: the report could not be posted: ${describe12(err2)}`
|
|
72535
73601
|
);
|
|
72536
73602
|
}
|
|
72537
73603
|
}
|
|
@@ -72545,7 +73611,7 @@ ${ending.report}` + (rendered !== void 0 ? `
|
|
|
72545
73611
|
${rendered}` : "");
|
|
72546
73612
|
await deps.github.commentIssue(instance.repo, row2.issue, comment).catch(
|
|
72547
73613
|
(err2) => (deps.log ?? console.warn)(
|
|
72548
|
-
`[coordinator] ${instance.id} ${row2.unit}: the board comment could not be posted: ${
|
|
73614
|
+
`[coordinator] ${instance.id} ${row2.unit}: the board comment could not be posted: ${describe12(err2)}`
|
|
72549
73615
|
)
|
|
72550
73616
|
);
|
|
72551
73617
|
}
|
|
@@ -72556,7 +73622,7 @@ ${rendered}` : "");
|
|
|
72556
73622
|
|
|
72557
73623
|
${ending.report}`).catch(
|
|
72558
73624
|
(err2) => (deps.log ?? console.warn)(
|
|
72559
|
-
`[coordinator] ${instance.id} ${row2.unit}: the human-gated report could not be posted on the pull request: ${
|
|
73625
|
+
`[coordinator] ${instance.id} ${row2.unit}: the human-gated report could not be posted on the pull request: ${describe12(err2)}`
|
|
72560
73626
|
)
|
|
72561
73627
|
);
|
|
72562
73628
|
}
|
|
@@ -72618,7 +73684,7 @@ async function rebaseStep(body, deps) {
|
|
|
72618
73684
|
at
|
|
72619
73685
|
});
|
|
72620
73686
|
} catch (err2) {
|
|
72621
|
-
return json3(200, { ok: true, outcome: "refused", reason:
|
|
73687
|
+
return json3(200, { ok: true, outcome: "refused", reason: describe12(err2), at });
|
|
72622
73688
|
}
|
|
72623
73689
|
}
|
|
72624
73690
|
async function merge(body, deps, subject2) {
|
|
@@ -72656,7 +73722,7 @@ async function merge(body, deps, subject2) {
|
|
|
72656
73722
|
try {
|
|
72657
73723
|
facts2 = await deps.fetchPrFacts(pr);
|
|
72658
73724
|
} catch (err2) {
|
|
72659
|
-
return json3(502, { ok: false, error: "github_unavailable", message:
|
|
73725
|
+
return json3(502, { ok: false, error: "github_unavailable", message: describe12(err2), at });
|
|
72660
73726
|
}
|
|
72661
73727
|
if (facts2 === void 0)
|
|
72662
73728
|
return json3(502, { ok: false, error: "github_unavailable", message: `${where} could not be read`, at });
|
|
@@ -72782,7 +73848,7 @@ async function merge(body, deps, subject2) {
|
|
|
72782
73848
|
try {
|
|
72783
73849
|
queued = await deps.enqueuePullRequest(pr, { sha: headSha });
|
|
72784
73850
|
} catch (err2) {
|
|
72785
|
-
return json3(502, { ok: false, error: "github_unavailable", message:
|
|
73851
|
+
return json3(502, { ok: false, error: "github_unavailable", message: describe12(err2), at });
|
|
72786
73852
|
}
|
|
72787
73853
|
if (!queued.ok) return refused7(`GitHub refused to enqueue ${where}: ${queued.reason}`);
|
|
72788
73854
|
log(
|
|
@@ -72799,7 +73865,7 @@ async function merge(body, deps, subject2) {
|
|
|
72799
73865
|
title: facts2.title ?? `Merge pull request #${pr.number}`
|
|
72800
73866
|
});
|
|
72801
73867
|
} catch (err2) {
|
|
72802
|
-
return json3(502, { ok: false, error: "github_unavailable", message:
|
|
73868
|
+
return json3(502, { ok: false, error: "github_unavailable", message: describe12(err2), at });
|
|
72803
73869
|
}
|
|
72804
73870
|
if (!merged.ok) {
|
|
72805
73871
|
if (merged.status === 405 && MERGE_QUEUE_405.test(merged.reason)) return enqueue();
|
|
@@ -72910,13 +73976,54 @@ async function finish(body, deps) {
|
|
|
72910
73976
|
if (host.kind === "not_host") return json3(409, { ok: false, error: "not_host", at });
|
|
72911
73977
|
const units = await deps.instances.listUnits(instance.id);
|
|
72912
73978
|
if (host.kind === "host") {
|
|
72913
|
-
|
|
72914
|
-
|
|
72915
|
-
|
|
72916
|
-
|
|
72917
|
-
|
|
72918
|
-
|
|
72919
|
-
|
|
73979
|
+
const ledgerRun = deps.ledgerRuns().find((run2) => run2.runId === host.runId);
|
|
73980
|
+
let summary = deps.registry.getById(host.runId);
|
|
73981
|
+
if (ledgerRun && summary) {
|
|
73982
|
+
if (summary.liveState === void 0) {
|
|
73983
|
+
await hostPublish(deps, instance, host.runId, [], at);
|
|
73984
|
+
summary = deps.registry.getById(host.runId);
|
|
73985
|
+
if (!summary) throw new Error("hosted run disappeared during finish backfill");
|
|
73986
|
+
}
|
|
73987
|
+
const bound = summary.liveState?.bound ?? at + minutesToMs(HOSTED_DEADLINE_MARGIN_MINUTES);
|
|
73988
|
+
const wrapping = await ledgerRun.assignLiveState({
|
|
73989
|
+
expectedSeq: summary.liveStateSeq ?? 0,
|
|
73990
|
+
eventSeq: summary.eventCount + 1,
|
|
73991
|
+
at,
|
|
73992
|
+
state: "wrapping_up",
|
|
73993
|
+
bound,
|
|
73994
|
+
detail: "writing the pipeline summary"
|
|
73995
|
+
});
|
|
73996
|
+
if (!wrapping.ok || !deps.registry.commitLiveState(host.runId, wrapping))
|
|
73997
|
+
throw new Error(`hosted wrap-up was not committed (${wrapping.ok ? "registry sequence" : wrapping.reason})`);
|
|
73998
|
+
summary = deps.registry.getById(host.runId);
|
|
73999
|
+
if (!summary) throw new Error("hosted run disappeared during wrap-up");
|
|
74000
|
+
const answer = { type: "answer", text: planSummary(units, isGenerated2(instance)), at };
|
|
74001
|
+
const answerSeq = summary.eventCount + 1;
|
|
74002
|
+
const refreshed = await ledgerRun.assignLiveState({
|
|
74003
|
+
expectedSeq: summary.liveStateSeq ?? 0,
|
|
74004
|
+
at,
|
|
74005
|
+
state: "wrapping_up",
|
|
74006
|
+
bound,
|
|
74007
|
+
detail: "writing the pipeline summary",
|
|
74008
|
+
sourceEvents: [{ ...answer, seq: answerSeq }]
|
|
74009
|
+
});
|
|
74010
|
+
if (!refreshed.ok || !deps.registry.commitLiveState(host.runId, refreshed))
|
|
74011
|
+
throw new Error(`hosted summary was not committed (${refreshed.ok ? "registry sequence" : refreshed.reason})`);
|
|
74012
|
+
deps.registry.publish(host.runId, answer);
|
|
74013
|
+
summary = deps.registry.getById(host.runId);
|
|
74014
|
+
if (!summary) throw new Error("hosted run disappeared before ending");
|
|
74015
|
+
const ended = await ledgerRun.assignLiveState({
|
|
74016
|
+
expectedSeq: summary.liveStateSeq ?? 0,
|
|
74017
|
+
eventSeq: summary.eventCount + 1,
|
|
74018
|
+
at,
|
|
74019
|
+
state: "ended",
|
|
74020
|
+
cause: body.outcome === "completed" ? "completed" : "failed"
|
|
74021
|
+
});
|
|
74022
|
+
if (!ended.ok || !deps.registry.commitLiveState(host.runId, ended))
|
|
74023
|
+
throw new Error(`hosted ending was not committed (${ended.ok ? "registry sequence" : ended.reason})`);
|
|
74024
|
+
} else {
|
|
74025
|
+
deps.registry.publish(host.runId, { type: "answer", text: planSummary(units, isGenerated2(instance)), at });
|
|
74026
|
+
}
|
|
72920
74027
|
deps.registry.finish(host.runId, body.outcome);
|
|
72921
74028
|
}
|
|
72922
74029
|
await drawCard(deps, instance, units, { icon: body.outcome === "completed" ? "\u2705" : "\u26A0\uFE0F" }).catch(() => {
|
|
@@ -72934,7 +74041,7 @@ ${planSummary(units)}`).catch(() => {
|
|
|
72934
74041
|
const summary = deps.registry.getById(host.runId);
|
|
72935
74042
|
const visibility = await deps.channelVisibilityOf(instance.channelId);
|
|
72936
74043
|
const finishedAt = snap?.finishedAt ?? at;
|
|
72937
|
-
const
|
|
74044
|
+
const record3 = assembleRunRecord({
|
|
72938
74045
|
run: { id: host.runId, ...summary?.label !== void 0 ? { label: summary.label } : {} },
|
|
72939
74046
|
snap,
|
|
72940
74047
|
agent: "ship",
|
|
@@ -72964,7 +74071,7 @@ ${planSummary(units)}`).catch(() => {
|
|
|
72964
74071
|
seal
|
|
72965
74072
|
});
|
|
72966
74073
|
const handle2 = deps.ledgerRuns().find((run2) => run2.runId === host.runId);
|
|
72967
|
-
deps.runHistoryWriter.write(
|
|
74074
|
+
deps.runHistoryWriter.write(record3, handle2 !== void 0 ? { via: handle2.sink } : void 0);
|
|
72968
74075
|
}
|
|
72969
74076
|
(deps.log ?? console.log)(`[coordinator] ${instance.id}: finished ${body.outcome} \u2014 record ${runId3}`);
|
|
72970
74077
|
return json3(200, { ok: true, runId: runId3, at });
|
|
@@ -73078,18 +74185,20 @@ function createAdminCoordinatorHandler(deps) {
|
|
|
73078
74185
|
}
|
|
73079
74186
|
write(res, await answerCoordinatorStep(door, read.body, deps));
|
|
73080
74187
|
} catch (err2) {
|
|
73081
|
-
(deps.log ?? console.error)(`[coordinator] ${
|
|
74188
|
+
(deps.log ?? console.error)(`[coordinator] ${describe12(err2)}`);
|
|
73082
74189
|
write(res, json3(500, { ok: false, error: "internal error" }));
|
|
73083
74190
|
}
|
|
73084
74191
|
})();
|
|
73085
74192
|
};
|
|
73086
74193
|
}
|
|
73087
|
-
var COORDINATOR_ADMIN_PREFIX, MAX_SPAWN_PROMPT_CHARS, FINISHED_LOOKBACK_PAGES, MAX_ADMIN_BODY_BYTES, UNIT_ID, PRESETS_OF_KIND, invalid, json3,
|
|
74194
|
+
var COORDINATOR_ADMIN_PREFIX, MAX_SPAWN_PROMPT_CHARS, FINISHED_LOOKBACK_PAGES, MAX_ADMIN_BODY_BYTES, UNIT_ID, PRESETS_OF_KIND, invalid, json3, describe12, isGenerated2, EVERY_RUN, REVIEW_POSTED_CHECKS, REVIEW_POSTED_RECHECK_MS, githubSecondStart, CHILD_SUPERSESSION_REASONS, ROUND_OUTCOMES, ENDING_ICON, STEPS;
|
|
73088
74195
|
var init_adminCoordinator = __esm({
|
|
73089
74196
|
"../../src/channels/adminCoordinator.ts"() {
|
|
73090
74197
|
"use strict";
|
|
73091
74198
|
init_budgets();
|
|
73092
74199
|
init_verbosity();
|
|
74200
|
+
init_prDescription();
|
|
74201
|
+
init_reply();
|
|
73093
74202
|
init_registry();
|
|
73094
74203
|
init_authorize();
|
|
73095
74204
|
init_actor();
|
|
@@ -73131,7 +74240,7 @@ var init_adminCoordinator = __esm({
|
|
|
73131
74240
|
};
|
|
73132
74241
|
invalid = (error) => ({ ok: false, error });
|
|
73133
74242
|
json3 = (status3, body) => ({ status: status3, body });
|
|
73134
|
-
|
|
74243
|
+
describe12 = (err2) => err2 instanceof Error ? err2.message : String(err2);
|
|
73135
74244
|
isGenerated2 = (instance) => instance.plan?.path === void 0;
|
|
73136
74245
|
EVERY_RUN = { kind: "all" };
|
|
73137
74246
|
REVIEW_POSTED_CHECKS = 3;
|
|
@@ -74366,6 +75475,13 @@ async function runBot() {
|
|
|
74366
75475
|
if (process.env.PORT) {
|
|
74367
75476
|
const ingress = createIngressHandler(deps, { auth, publicBaseUrl: process.env.PUBLIC_BASE_URL, personByEmail });
|
|
74368
75477
|
const mcp2 = createMcpHandler(deps, { auth, commands, grantsFor: (id) => config.grantsFor(id), personByEmail });
|
|
75478
|
+
const providerLiveState = createProviderLiveStateCoordinator({
|
|
75479
|
+
runLedger,
|
|
75480
|
+
ledger: ledgerClient,
|
|
75481
|
+
registry: defaultRunRegistry,
|
|
75482
|
+
clock: systemClock,
|
|
75483
|
+
warn: (message4) => console.warn(`[provider-state] ${message4}`)
|
|
75484
|
+
});
|
|
74369
75485
|
const modelProxy = createModelProxyHandler({
|
|
74370
75486
|
bearers: runBearers,
|
|
74371
75487
|
providers: () => config.config.providers,
|
|
@@ -74374,17 +75490,11 @@ async function runBot() {
|
|
|
74374
75490
|
...costsCfg?.prices ? { prices: () => costsCfg.prices } : {},
|
|
74375
75491
|
secrets: processSecrets,
|
|
74376
75492
|
clock: systemClock,
|
|
74377
|
-
// The plane's provider seam (model-proxy item 12a; record 0064):
|
|
74378
|
-
// and
|
|
74379
|
-
// the null write-through swallows both where no ledger is configured.
|
|
75493
|
+
// The plane's provider seam (model-proxy item 12a; record 0064): one
|
|
75494
|
+
// coordinator sequences level and park writes; the proxy never waits.
|
|
74380
75495
|
plane: {
|
|
74381
|
-
level: (provider, side, cause) => void
|
|
74382
|
-
|
|
74383
|
-
name: "provider",
|
|
74384
|
-
side,
|
|
74385
|
-
...side === "down" && cause !== void 0 ? { cause } : {}
|
|
74386
|
-
}),
|
|
74387
|
-
park: (runId3, provider) => void runLedger.planePark(runId3, provider)
|
|
75496
|
+
level: (provider, side, cause) => void providerLiveState.level(provider, side, cause),
|
|
75497
|
+
park: (runId3, provider) => void providerLiveState.park(runId3, provider)
|
|
74388
75498
|
}
|
|
74389
75499
|
});
|
|
74390
75500
|
const harnessRoutes = createHarnessRoutesHandler({ bearers: runBearers, harnesses, takeover });
|
|
@@ -75128,6 +76238,7 @@ var init_index = __esm({
|
|
|
75128
76238
|
init_adminModelProxy();
|
|
75129
76239
|
init_modelProxy();
|
|
75130
76240
|
init_runBearers();
|
|
76241
|
+
init_providerLiveStateCoordinator();
|
|
75131
76242
|
init_piHarness();
|
|
75132
76243
|
init_harness2();
|
|
75133
76244
|
init_relay();
|