@claudexor/orchestrator 6.1.1 → 6.1.2
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/attemptUsageCost.d.ts +2 -2
- package/dist/attemptUsageCost.d.ts.map +1 -1
- package/dist/attemptUsageCost.js +3 -3
- package/dist/attemptUsageCost.js.map +1 -1
- package/dist/candidateOutputs.d.ts +3 -2
- package/dist/candidateOutputs.d.ts.map +1 -1
- package/dist/candidateOutputs.js +5 -4
- package/dist/candidateOutputs.js.map +1 -1
- package/dist/candidateReview.js +3 -3
- package/dist/candidateReview.js.map +1 -1
- package/dist/candidateTerminals.js +3 -3
- package/dist/candidateTerminals.js.map +1 -1
- package/dist/candidateWorkProduct.js +2 -2
- package/dist/candidateWorkProduct.js.map +1 -1
- package/dist/continuation-custody.d.ts +15 -3
- package/dist/continuation-custody.d.ts.map +1 -1
- package/dist/continuation-custody.js +42 -14
- package/dist/continuation-custody.js.map +1 -1
- package/dist/continue-from.d.ts.map +1 -1
- package/dist/continue-from.js +6 -3
- package/dist/continue-from.js.map +1 -1
- package/dist/deepScanReducer.d.ts +1 -1
- package/dist/deepScanReducer.d.ts.map +1 -1
- package/dist/deepScanReducer.js +7 -5
- package/dist/deepScanReducer.js.map +1 -1
- package/dist/delegationFailure.js +1 -1
- package/dist/delegationFailure.js.map +1 -1
- package/dist/directoryCandidate.js +4 -4
- package/dist/directoryCandidate.js.map +1 -1
- package/dist/git-precondition.js +1 -1
- package/dist/git-precondition.js.map +1 -1
- package/dist/inrun-continuity.d.ts.map +1 -1
- package/dist/inrun-continuity.js +5 -6
- package/dist/inrun-continuity.js.map +1 -1
- package/dist/interaction.d.ts +4 -3
- package/dist/interaction.d.ts.map +1 -1
- package/dist/interaction.js +10 -6
- package/dist/interaction.js.map +1 -1
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +64 -61
- package/dist/orchestrator.js.map +1 -1
- package/dist/planRun.d.ts +1 -1
- package/dist/planRun.d.ts.map +1 -1
- package/dist/planRun.js +5 -5
- package/dist/planRun.js.map +1 -1
- package/dist/plannerAttempt.d.ts.map +1 -1
- package/dist/plannerAttempt.js +6 -5
- package/dist/plannerAttempt.js.map +1 -1
- package/dist/retainedOutput.d.ts.map +1 -1
- package/dist/retainedOutput.js +4 -3
- package/dist/retainedOutput.js.map +1 -1
- package/dist/reviewerPanel.js +2 -2
- package/dist/reviewerPanel.js.map +1 -1
- package/dist/routeContext.d.ts +1 -1
- package/dist/routeContext.d.ts.map +1 -1
- package/dist/runEventLog.d.ts +11 -7
- package/dist/runEventLog.d.ts.map +1 -1
- package/dist/runEventLog.js +17 -13
- package/dist/runEventLog.js.map +1 -1
- package/dist/runScope.d.ts +3 -2
- package/dist/runScope.d.ts.map +1 -1
- package/dist/runScope.js +5 -4
- package/dist/runScope.js.map +1 -1
- package/dist/runSupport.d.ts +18 -1
- package/dist/runSupport.d.ts.map +1 -1
- package/dist/runSupport.js +16 -1
- package/dist/runSupport.js.map +1 -1
- package/dist/runTerminalHelpers.d.ts +14 -0
- package/dist/runTerminalHelpers.d.ts.map +1 -1
- package/dist/runTerminalHelpers.js +54 -1
- package/dist/runTerminalHelpers.js.map +1 -1
- package/dist/runTerminalResults.d.ts +5 -1
- package/dist/runTerminalResults.d.ts.map +1 -1
- package/dist/runTerminalResults.js +37 -4
- package/dist/runTerminalResults.js.map +1 -1
- package/dist/runTerminals.d.ts.map +1 -1
- package/dist/runTerminals.js +140 -138
- package/dist/runTerminals.js.map +1 -1
- package/dist/secretDiff.d.ts +4 -3
- package/dist/secretDiff.d.ts.map +1 -1
- package/dist/secretDiff.js +4 -3
- package/dist/secretDiff.js.map +1 -1
- package/package.json +17 -17
package/dist/orchestrator.js
CHANGED
|
@@ -51,7 +51,7 @@ import { budgetFailureRecord, classifyBudgetFailure } from "./budgetFailure.js";
|
|
|
51
51
|
import { finalizeStructuredOutput } from "./structuredOutput.js";
|
|
52
52
|
import { prepareRunAdmission } from "./runAdmission.js";
|
|
53
53
|
import { dropDeltaPastBudget, emitPlanProgress, emitTransientExhausted, observeUsageSpend, recordAdapterThrow, } from "./laneStreamEvents.js";
|
|
54
|
-
import { promptWithEngineConstraints, sleep, harnessEventPayload, safeErrorMessage, renderSummary, observeBudgetSignals, rotateOnStall, recordCleanAttemptMetrics, envInheritance, transientRetryPolicy, reviewerTimeoutMs, harnessInactivityTimeoutMs, observeAuthSwitch, emitPoolDegraded, deliveryRefusalFailure, winnerNeedsHuman, writeRaceDeliveryDecision, } from "./runSupport.js";
|
|
54
|
+
import { promptWithEngineConstraints, sleep, harnessEventPayload, safeErrorMessage, renderSummary, observeBudgetSignals, rotateOnStall, recordCleanAttemptMetrics, envInheritance, transientRetryPolicy, reviewerTimeoutMs, harnessInactivityTimeoutMs, laneSuspension, observeAuthSwitch, emitPoolDegraded, deliveryRefusalFailure, winnerNeedsHuman, writeRaceDeliveryDecision, } from "./runSupport.js";
|
|
55
55
|
import { candidateStatusInRouteContext, resolveReadOnlyRouteContext, } from "./routeContext.js";
|
|
56
56
|
import { resolveAutoReviewerPanel, resolveExplicitReviewerPanel } from "./reviewerPanel.js";
|
|
57
57
|
import { ensureWriteModeGitBoundary } from "./git-precondition.js";
|
|
@@ -84,7 +84,7 @@ import { ReadinessLedger, evaluateConvergence, failureSignature, gatesPassed, re
|
|
|
84
84
|
import { arbitrate } from "@claudexor/arbitration";
|
|
85
85
|
import { buildSynthesisPlan, decideSynthesis } from "@claudexor/synthesis";
|
|
86
86
|
import { billingKnowledgeForAuthRoute, attemptUsageCostSettlement, BudgetLedger, isBudgetTerminal, explainRanking, loadHarnessMetrics, promptFingerprint, rankHarnesses, } from "@claudexor/budget";
|
|
87
|
-
import { hashJson, newId, noProjectRepoRoot, redactSecrets, safeInvoke, userConfigDir, } from "@claudexor/util";
|
|
87
|
+
import { hashJson, measureSync, newId, noProjectRepoRoot, pacedByAppends, redactSecrets, safeInvoke, userConfigDir, } from "@claudexor/util";
|
|
88
88
|
const LABELS = "ABCDEFGHIJ".split("");
|
|
89
89
|
const NO_PROJECT_ROOT = noProjectRepoRoot();
|
|
90
90
|
export class Orchestrator {
|
|
@@ -231,14 +231,14 @@ export class Orchestrator {
|
|
|
231
231
|
}
|
|
232
232
|
catch (err) {
|
|
233
233
|
const message = safeErrorMessage(err);
|
|
234
|
-
store.
|
|
234
|
+
await store.writeTextAsync(join(paths.contextDir, "context_error.md"), `# Reviewer Panel Error\n\n${message}\n`);
|
|
235
235
|
writeFailure(store, paths, {
|
|
236
236
|
phase: "review_preflight",
|
|
237
237
|
category: "harness_unavailable",
|
|
238
238
|
safeMessage: message,
|
|
239
239
|
runDir: paths.root,
|
|
240
240
|
});
|
|
241
|
-
store.
|
|
241
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), `# Run ${runId} (${mode})\n\n- Lifecycle: failed\n- Phase: review preflight\n\n${message}\n`);
|
|
242
242
|
log.emit("output.ready", { kind: "summary", path: "final/summary.md", state: "diagnostic" });
|
|
243
243
|
log.emit("run.failed", {
|
|
244
244
|
lifecycle: "failed",
|
|
@@ -971,7 +971,7 @@ export class Orchestrator {
|
|
|
971
971
|
include: projectCtx.include,
|
|
972
972
|
exclude: projectCtx.exclude,
|
|
973
973
|
});
|
|
974
|
-
store.
|
|
974
|
+
await store.writeYamlAsync(join(paths.contextDir, "context_pack.yaml"), pack);
|
|
975
975
|
log.emit("context.pack.created", {
|
|
976
976
|
hash: pack.hash,
|
|
977
977
|
files: pack.atlas.length,
|
|
@@ -1188,7 +1188,7 @@ export class Orchestrator {
|
|
|
1188
1188
|
if (!result.packetMarkdown)
|
|
1189
1189
|
return { pointerLine: null };
|
|
1190
1190
|
const briefPath = join(paths.contextDir, "THREAD.md");
|
|
1191
|
-
store.
|
|
1191
|
+
await store.writeTextAsync(briefPath, result.packetMarkdown);
|
|
1192
1192
|
return {
|
|
1193
1193
|
pointerLine: threadContextPointer(briefPath),
|
|
1194
1194
|
};
|
|
@@ -1419,6 +1419,7 @@ export class Orchestrator {
|
|
|
1419
1419
|
const rateLimitStart = telemetry.rateLimits.length;
|
|
1420
1420
|
rawLane.beginTry();
|
|
1421
1421
|
try {
|
|
1422
|
+
const pacing = { waiting: false, version: 0 };
|
|
1422
1423
|
const watched = withInactivityWatchdog(runModelGovernedRoute(routed, runSpec, dispatch), {
|
|
1423
1424
|
timeoutMs: inactivityMs,
|
|
1424
1425
|
countsAsProgress: countsAsAgentProgress,
|
|
@@ -1428,12 +1429,11 @@ export class Orchestrator {
|
|
|
1428
1429
|
},
|
|
1429
1430
|
// Waiting on the USER is legitimate silence. The interaction policy
|
|
1430
1431
|
// either enforces a finite deadline or waits until answer/cancel/
|
|
1431
|
-
// terminal/restart when the timeout is disabled.
|
|
1432
|
-
|
|
1433
|
-
suspensionVersion: () => interaction?.suspensionVersion?.() ?? 0,
|
|
1432
|
+
// terminal/restart when the timeout is disabled. So is the journal wait.
|
|
1433
|
+
...laneSuspension(pacing, interaction),
|
|
1434
1434
|
stopSignal: signal, // after Stop: drained events are recorded, never used
|
|
1435
1435
|
});
|
|
1436
|
-
for await (const ev of watched) {
|
|
1436
|
+
for await (const ev of pacedByAppends(watched, [paths.eventsPath], pacing)) {
|
|
1437
1437
|
// After Stop: stored evidence only, but file paths are still collected for the capture.
|
|
1438
1438
|
const stopped = signal?.aborted === true;
|
|
1439
1439
|
if (!stopped)
|
|
@@ -1708,7 +1708,7 @@ export class Orchestrator {
|
|
|
1708
1708
|
aborted: signal?.aborted === true,
|
|
1709
1709
|
authMode: telemetry.authMode,
|
|
1710
1710
|
});
|
|
1711
|
-
const { produced: producedFiles, omitted: producedOmitted } = AC.withAttemptFailureCost(() => writeCandidateAttemptArtifacts({
|
|
1711
|
+
const { produced: producedFiles, omitted: producedOmitted } = await AC.withAttemptFailureCost(() => writeCandidateAttemptArtifacts({
|
|
1712
1712
|
store,
|
|
1713
1713
|
attemptDir,
|
|
1714
1714
|
worktreePath: envelope.worktree_path,
|
|
@@ -1838,7 +1838,7 @@ export class Orchestrator {
|
|
|
1838
1838
|
const mutatingRun = isMutatingAccess(contract.access.effective_profile);
|
|
1839
1839
|
const planBrief = verifiedPlanBrief(input);
|
|
1840
1840
|
const quotaSnapshots = this.quotaSnapshotPreflight();
|
|
1841
|
-
const { store, paths, log, ledger, runContext } = beginAnnouncedRun({
|
|
1841
|
+
const { store, paths, log, ledger, runContext } = await beginAnnouncedRun({
|
|
1842
1842
|
input,
|
|
1843
1843
|
contract,
|
|
1844
1844
|
quotaSnapshots,
|
|
@@ -1860,7 +1860,7 @@ export class Orchestrator {
|
|
|
1860
1860
|
const projectRoot = input.repoRoot;
|
|
1861
1861
|
const wsm = new WorkspaceManager(execRoot, { projectRoot, runtimeRoot: runRuntimeRoot(input) });
|
|
1862
1862
|
const anchors = secretDiff.revertAnchors(execRoot, projectRoot);
|
|
1863
|
-
store.
|
|
1863
|
+
await store.writeYamlAsync(join(paths.contextDir, "task.yaml"), contract);
|
|
1864
1864
|
log.emit("task.contract.created", { task_contract_hash: hashJson(contract) });
|
|
1865
1865
|
// Write modes need a git boundary for worktree isolation and honest diffs.
|
|
1866
1866
|
// A non-git project folder is initialized automatically (baseline commit),
|
|
@@ -2208,7 +2208,7 @@ export class Orchestrator {
|
|
|
2208
2208
|
error: message,
|
|
2209
2209
|
phase: infraPhase,
|
|
2210
2210
|
});
|
|
2211
|
-
store.
|
|
2211
|
+
await store.writeYamlAsync(join(paths.attemptsDir, slot.attemptId, "attempt.yaml"), AC.attemptFailureRecord(slot.attemptId, adapter.id, failureCost, infraPhase, message, applied));
|
|
2212
2212
|
runsBySlot[slotIdx] = {
|
|
2213
2213
|
attemptId: slot.attemptId,
|
|
2214
2214
|
harnessId: adapter.id,
|
|
@@ -2405,7 +2405,7 @@ export class Orchestrator {
|
|
|
2405
2405
|
sources: evidences.map((evidence) => evidence.attemptId),
|
|
2406
2406
|
};
|
|
2407
2407
|
try {
|
|
2408
|
-
store.
|
|
2408
|
+
await store.writeYamlAsync(join(paths.arbitrationDir, "synthesis.yaml"), synth);
|
|
2409
2409
|
log.emit("synthesis.started", { synthesize: synth.synthesize, reason: synth.reason });
|
|
2410
2410
|
if (synth.synthesize && !budgetStopped) {
|
|
2411
2411
|
const synthRouted = adapters[0];
|
|
@@ -2578,7 +2578,7 @@ export class Orchestrator {
|
|
|
2578
2578
|
facts = { ...facts, checks: "failed", reason: "checks_failed" };
|
|
2579
2579
|
}
|
|
2580
2580
|
const needsDec = facts.review === "blocked" || facts.checks === "failed";
|
|
2581
|
-
store.
|
|
2581
|
+
await store.writeYamlAsync(join(paths.arbitrationDir, "decision.yaml"), {
|
|
2582
2582
|
...result.decision,
|
|
2583
2583
|
...(needsDec
|
|
2584
2584
|
? blockedDecisionOverride(result.decision.evidence_facts, facts, finalVerify)
|
|
@@ -2586,7 +2586,7 @@ export class Orchestrator {
|
|
|
2586
2586
|
review_verified: actualReviewVerified,
|
|
2587
2587
|
final_verify: finalVerify,
|
|
2588
2588
|
});
|
|
2589
|
-
store.
|
|
2589
|
+
await store.writeYamlAsync(join(paths.arbitrationDir, "pairwise.yaml"), result.pairwise);
|
|
2590
2590
|
const decisionPath = join(paths.arbitrationDir, "decision.yaml");
|
|
2591
2591
|
// Every attempt's failed tries by the FINAL outcome (delivery below can
|
|
2592
2592
|
// still fail the checks); a review or check block is not an account failure.
|
|
@@ -2601,7 +2601,7 @@ export class Orchestrator {
|
|
|
2601
2601
|
}
|
|
2602
2602
|
const winnerAnswer = winnerRun.answerText ?? "";
|
|
2603
2603
|
if (winnerAnswer.length > 0) {
|
|
2604
|
-
store.
|
|
2604
|
+
await store.writeTextAsync(join(paths.finalDir, "answer.md"), winnerAnswer + "\n");
|
|
2605
2605
|
}
|
|
2606
2606
|
if (contract.output_schema) {
|
|
2607
2607
|
finalizeStructuredOutput({
|
|
@@ -2623,7 +2623,7 @@ export class Orchestrator {
|
|
|
2623
2623
|
const delivered = await verifyAndDeliverFiles(execRoot, winnerRun.files, {}, gateSpecsFromContract(contract, input.runScopeMarker), (freshVerify) => finalVerifyBlocks(freshVerify)
|
|
2624
2624
|
? (freshVerify.reason ?? "final verify failed before directory race adoption")
|
|
2625
2625
|
: null, log);
|
|
2626
|
-
store.
|
|
2626
|
+
await store.writeYamlAsync(join(paths.finalDir, "delivery_receipt.yaml"), delivered);
|
|
2627
2627
|
directoryDeliveryReceipt = true;
|
|
2628
2628
|
directoryDelivery = delivered;
|
|
2629
2629
|
finalVerify = delivered.finalVerify;
|
|
@@ -2655,7 +2655,7 @@ export class Orchestrator {
|
|
|
2655
2655
|
});
|
|
2656
2656
|
}
|
|
2657
2657
|
else if (mutatingRun) {
|
|
2658
|
-
const savedPatch = secretDiff.persistFinalPatch(store, paths.finalDir, winnerRun);
|
|
2658
|
+
const savedPatch = await secretDiff.persistFinalPatch(store, paths.finalDir, winnerRun);
|
|
2659
2659
|
const patchSha256 = savedPatch.patchSha256;
|
|
2660
2660
|
const wstats = secretDiff.resultDiffStats(winnerRun);
|
|
2661
2661
|
const hasDiff = secretDiff.hasCandidateChanges(winnerRun);
|
|
@@ -2690,7 +2690,7 @@ export class Orchestrator {
|
|
|
2690
2690
|
: null;
|
|
2691
2691
|
}, log);
|
|
2692
2692
|
raceDeliveryReceipt = applied;
|
|
2693
|
-
store.
|
|
2693
|
+
await store.writeYamlAsync(join(paths.finalDir, "delivery_receipt.yaml"), applied);
|
|
2694
2694
|
finalVerify = applied.finalVerify;
|
|
2695
2695
|
if (applied.applied) {
|
|
2696
2696
|
adopted = true;
|
|
@@ -2736,7 +2736,7 @@ export class Orchestrator {
|
|
|
2736
2736
|
revertAnchorId = await anchors.turn(preTurnSha, postTurnSha);
|
|
2737
2737
|
}
|
|
2738
2738
|
const capturedNoGitChange = capturedNoGitChangeValue(winnerRun);
|
|
2739
|
-
store.
|
|
2739
|
+
await store.writeYamlAsync(join(paths.finalDir, "work_product.yaml"), {
|
|
2740
2740
|
id: newId("wp"),
|
|
2741
2741
|
kind: input.create === true ? "new_repo" : "patch",
|
|
2742
2742
|
source_task_id: taskId,
|
|
@@ -2771,7 +2771,7 @@ export class Orchestrator {
|
|
|
2771
2771
|
},
|
|
2772
2772
|
});
|
|
2773
2773
|
}
|
|
2774
|
-
store.
|
|
2774
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), withPoolAttempts(renderSummary(runId, mode, { ...result.decision, facts }, evidences, synth.reason, actualReviewVerified, delegateFailure.raceSummaryDisclosure(winnerRun, runs)), racePool()));
|
|
2775
2775
|
// summary.md is a DIAGNOSTIC artifact only (V8/PLAN addendum 2): it no
|
|
2776
2776
|
// longer carries primary-output authority. A clean applyable success or a
|
|
2777
2777
|
// winner answer still marks it ready for legacy INV-116 ordering; any
|
|
@@ -2883,7 +2883,7 @@ export class Orchestrator {
|
|
|
2883
2883
|
...(decisionBlock ? {} : erroredWinnerFailure(winnerRun, keptSources)),
|
|
2884
2884
|
});
|
|
2885
2885
|
if (!winnerRun) {
|
|
2886
|
-
store.
|
|
2886
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), `# Run ${runId} (${mode})\n\n- Lifecycle: ${facts.lifecycle}${facts.reason ? ` (${facts.reason})` : ""}\n- Phase: arbitration\n\n${withPoolAttempts(result.decision.why_winner, pool)}\n`);
|
|
2887
2887
|
log.emit("output.ready", {
|
|
2888
2888
|
kind: "summary",
|
|
2889
2889
|
path: "final/summary.md",
|
|
@@ -2949,9 +2949,10 @@ export class Orchestrator {
|
|
|
2949
2949
|
writeRunTelemetry(store, paths, contract, runId, taskId, mode, attempts, finalAttemptId, deepScanSynthesis) {
|
|
2950
2950
|
// QA-034: attach the routing rationale recorded at pool ordering (if this
|
|
2951
2951
|
// run computed one), then clear it — telemetry is written once at terminal.
|
|
2952
|
+
// It stays synchronous (several callers are synchronous callbacks), labeled (#688).
|
|
2952
2953
|
const routingRationale = this.routingRationaleByRun.get(runId) ?? null;
|
|
2953
2954
|
this.routingRationaleByRun.delete(runId);
|
|
2954
|
-
writeRunTelemetryArtifact({
|
|
2955
|
+
measureSync("run.telemetry_write", () => writeRunTelemetryArtifact({
|
|
2955
2956
|
store,
|
|
2956
2957
|
finalDir: paths.finalDir,
|
|
2957
2958
|
contract,
|
|
@@ -2963,7 +2964,7 @@ export class Orchestrator {
|
|
|
2963
2964
|
routingRationale,
|
|
2964
2965
|
deepScanSynthesis: deepScanSynthesis ?? null,
|
|
2965
2966
|
resolveAuthPreference: (harnessId) => this.authPreferenceForHarness(contract.repo.root, harnessId, contract.auth_preference),
|
|
2966
|
-
});
|
|
2967
|
+
}));
|
|
2967
2968
|
}
|
|
2968
2969
|
/**
|
|
2969
2970
|
* SINGLE funnel for every reviewer-panel invocation: run it inside a per-review
|
|
@@ -3017,7 +3018,7 @@ export class Orchestrator {
|
|
|
3017
3018
|
const contract = this.buildContract(input, taskId, mode);
|
|
3018
3019
|
const planBrief = verifiedPlanBrief(input);
|
|
3019
3020
|
const quotaSnapshots = this.quotaSnapshotPreflight();
|
|
3020
|
-
const { store, paths, log, ledger, runContext } = beginAnnouncedRun({
|
|
3021
|
+
const { store, paths, log, ledger, runContext } = await beginAnnouncedRun({
|
|
3021
3022
|
input,
|
|
3022
3023
|
contract,
|
|
3023
3024
|
quotaSnapshots,
|
|
@@ -3042,7 +3043,7 @@ export class Orchestrator {
|
|
|
3042
3043
|
});
|
|
3043
3044
|
const anchors = secretDiff.revertAnchors(execRoot, input.repoRoot);
|
|
3044
3045
|
const readiness = new ReadinessLedger();
|
|
3045
|
-
store.
|
|
3046
|
+
await store.writeYamlAsync(join(paths.contextDir, "task.yaml"), contract);
|
|
3046
3047
|
// Legacy Git envelopes need their boundary; explicit directory execution
|
|
3047
3048
|
// keeps the requested strategy without initializing the selected folder.
|
|
3048
3049
|
if (!input.inPlace && input.workspaceKind !== "directory") {
|
|
@@ -3108,7 +3109,7 @@ export class Orchestrator {
|
|
|
3108
3109
|
if (contract.convergence.require_final_cross_family_clean_review && !reviewVerified) {
|
|
3109
3110
|
const message = `convergence requires a cross-family clean review (>=2 healthy reviewer provider families); found ${new Set(reviewers.map((r) => r.providerFamily)).size}. ` +
|
|
3110
3111
|
"Configure reviewers from a second provider family and check `claudexor doctor` for reviewer readiness.";
|
|
3111
|
-
store.
|
|
3112
|
+
await store.writeTextAsync(join(paths.contextDir, "context_error.md"), `# Convergence Preflight Error\n\n${message}\n`);
|
|
3112
3113
|
writeFailure(store, paths, {
|
|
3113
3114
|
phase: "review",
|
|
3114
3115
|
category: "policy",
|
|
@@ -3119,7 +3120,7 @@ export class Orchestrator {
|
|
|
3119
3120
|
"Check harness doctor for reviewer readiness",
|
|
3120
3121
|
],
|
|
3121
3122
|
});
|
|
3122
|
-
store.
|
|
3123
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), `# Run ${runId} (${mode})\n\n- Lifecycle: failed\n- Phase: review preflight\n\n${message}\n`);
|
|
3123
3124
|
log.emit("output.ready", { kind: "summary", path: "final/summary.md", state: "diagnostic" });
|
|
3124
3125
|
log.emit("run.failed", {
|
|
3125
3126
|
lifecycle: "failed",
|
|
@@ -3284,7 +3285,7 @@ export class Orchestrator {
|
|
|
3284
3285
|
status: "failed",
|
|
3285
3286
|
error: message,
|
|
3286
3287
|
});
|
|
3287
|
-
store.
|
|
3288
|
+
await store.writeYamlAsync(join(paths.attemptsDir, attemptId, "attempt.yaml"), AC.attemptFailureRecord(attemptId, adapter.id, failureCost, "harness", message, applied));
|
|
3288
3289
|
run = {
|
|
3289
3290
|
applied,
|
|
3290
3291
|
attemptId,
|
|
@@ -3540,7 +3541,7 @@ export class Orchestrator {
|
|
|
3540
3541
|
toCandidateEvidence(lastRun, contract, lastFindings, lastFinalReviewClean, actualReviewVerified),
|
|
3541
3542
|
], { ...arbitrationBudgetOptions(ledger), reviewRequested: contract.review_requested });
|
|
3542
3543
|
decision = arb.decision;
|
|
3543
|
-
store.
|
|
3544
|
+
await store.writeYamlAsync(join(paths.arbitrationDir, "decision.yaml"), decision);
|
|
3544
3545
|
// A converged run adopts the arbitration axes (checks/review); an
|
|
3545
3546
|
// otherwise not-converged loop that nonetheless produced an applyable
|
|
3546
3547
|
// decision adopts it too.
|
|
@@ -3616,7 +3617,7 @@ export class Orchestrator {
|
|
|
3616
3617
|
: { facts }),
|
|
3617
3618
|
final_verify: convFinalVerify,
|
|
3618
3619
|
};
|
|
3619
|
-
store.
|
|
3620
|
+
await store.writeYamlAsync(join(paths.arbitrationDir, "decision.yaml"), decision);
|
|
3620
3621
|
}
|
|
3621
3622
|
this.writeRunTelemetry(store, paths, contract, runId, taskId, mode, attemptTelemetries, lastRun?.attemptId ?? null);
|
|
3622
3623
|
// Deliver the converged/last work to final/ so `apply` and `inspect` can
|
|
@@ -3638,7 +3639,7 @@ export class Orchestrator {
|
|
|
3638
3639
|
});
|
|
3639
3640
|
}
|
|
3640
3641
|
else {
|
|
3641
|
-
const savedPatch = secretDiff.persistFinalPatch(store, paths.finalDir, lastRun);
|
|
3642
|
+
const savedPatch = await secretDiff.persistFinalPatch(store, paths.finalDir, lastRun);
|
|
3642
3643
|
const patchSha256 = savedPatch.patchSha256;
|
|
3643
3644
|
// Honest apply-state (parity with runRace single-candidate in-place): a
|
|
3644
3645
|
// convergence run with inPlace mutated the live tree directly across its
|
|
@@ -3652,7 +3653,7 @@ export class Orchestrator {
|
|
|
3652
3653
|
: "not_applied";
|
|
3653
3654
|
const revertAnchorId = convAdopted === true ? await anchors.turn(preTurnSha, lastPostTurnSha) : null;
|
|
3654
3655
|
const capturedNoGitChange = capturedNoGitChangeValue(lastRun);
|
|
3655
|
-
store.
|
|
3656
|
+
await store.writeYamlAsync(join(paths.finalDir, "work_product.yaml"), {
|
|
3656
3657
|
id: newId("wp"),
|
|
3657
3658
|
kind: "patch",
|
|
3658
3659
|
source_task_id: taskId,
|
|
@@ -3678,10 +3679,10 @@ export class Orchestrator {
|
|
|
3678
3679
|
}
|
|
3679
3680
|
// The exact answer is kept for every convergence result, patch or files.
|
|
3680
3681
|
if (lastRun.answerText) {
|
|
3681
|
-
store.
|
|
3682
|
+
await store.writeTextAsync(join(paths.finalDir, "answer.md"), lastRun.answerText);
|
|
3682
3683
|
log.emit("output.ready", { kind: "answer", path: "final/answer.md" });
|
|
3683
3684
|
}
|
|
3684
|
-
store.
|
|
3685
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), `${withPoolAttempts(`# Run ${runId} (${mode})\n\n- Lifecycle: ${facts.lifecycle}${facts.reason ? ` (${facts.reason})` : ""}\n- Attempts: ${attempt}\n- Winner: ${lastRun.attemptId}\n- Review verified (cross-family): ${actualReviewVerified}\n- Apply recommendation: ${decision?.apply_recommendation ?? "inspect"}${stuckNoProgressReason ? `\n- No-progress reason: ${stuckNoProgressReason}` : ""}${convCause ? `\n- Failure: ${convCause}` : ""}${secretDiff.resultSummaryDisclosure(lastRun)}`, convPool)}\n`);
|
|
3685
3686
|
// Lifecycle invariant (all modes): output.ready precedes the terminal
|
|
3686
3687
|
// event so a client that applied the terminal event has the output.
|
|
3687
3688
|
log.emit("output.ready", {
|
|
@@ -3764,7 +3765,7 @@ export class Orchestrator {
|
|
|
3764
3765
|
// ARCHITECTURE event contract guarantees output.ready precedes the
|
|
3765
3766
|
// terminal in every mode.
|
|
3766
3767
|
if (!lastRun || (interrupted && input.inPlace !== true && !lastRun.files)) {
|
|
3767
|
-
store.
|
|
3768
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), `${withPoolAttempts(`# Run ${runId} (${mode})\n\n- Lifecycle: ${facts.lifecycle}${facts.reason ? ` (${facts.reason})` : ""}\n- Attempts: ${attempt}`, convPool)}\n`);
|
|
3768
3769
|
log.emit("output.ready", {
|
|
3769
3770
|
kind: "summary",
|
|
3770
3771
|
path: "final/summary.md",
|
|
@@ -3908,7 +3909,7 @@ export class Orchestrator {
|
|
|
3908
3909
|
// contract validation runs BEFORE the run is announced (see runRace).
|
|
3909
3910
|
const contract = this.buildContract(input, taskId, "plan");
|
|
3910
3911
|
const quotaSnapshots = this.quotaSnapshotPreflight();
|
|
3911
|
-
const { store, paths, log, ledger } = beginAnnouncedRun({
|
|
3912
|
+
const { store, paths, log, ledger } = await beginAnnouncedRun({
|
|
3912
3913
|
input,
|
|
3913
3914
|
contract,
|
|
3914
3915
|
quotaSnapshots,
|
|
@@ -3920,7 +3921,7 @@ export class Orchestrator {
|
|
|
3920
3921
|
phase: "plan",
|
|
3921
3922
|
prompt: input.prompt,
|
|
3922
3923
|
}, announce);
|
|
3923
|
-
store.
|
|
3924
|
+
await store.writeYamlAsync(join(paths.contextDir, "task.yaml"), contract);
|
|
3924
3925
|
log.emit("task.contract.created", { task_contract_hash: hashJson(contract) });
|
|
3925
3926
|
// W3.3: ONE resolved read-only context — the routing point-probe and every
|
|
3926
3927
|
// planner spawn consume the SAME scoped env (see routeContext.ts).
|
|
@@ -3936,7 +3937,7 @@ export class Orchestrator {
|
|
|
3936
3937
|
adapters = await this.resolveCandidateAdapters({ ...input, n: undefined }, "plan", ledger, log, roHome, runId);
|
|
3937
3938
|
}
|
|
3938
3939
|
catch (err) {
|
|
3939
|
-
roHome.dispose();
|
|
3940
|
+
await roHome.dispose();
|
|
3940
3941
|
const message = safeErrorMessage(err);
|
|
3941
3942
|
writeRoutingFailureTerminal(store, paths, log, {
|
|
3942
3943
|
runId,
|
|
@@ -3963,16 +3964,16 @@ export class Orchestrator {
|
|
|
3963
3964
|
contextSection = await this.lazyContextSection(input, contract, store, paths, log);
|
|
3964
3965
|
}
|
|
3965
3966
|
catch (err) {
|
|
3966
|
-
roHome.dispose();
|
|
3967
|
+
await roHome.dispose();
|
|
3967
3968
|
const message = safeErrorMessage(err);
|
|
3968
|
-
store.
|
|
3969
|
+
await store.writeTextAsync(join(paths.contextDir, "context_error.md"), `# Context Error\n\n${message}\n`);
|
|
3969
3970
|
writeFailure(store, paths, {
|
|
3970
3971
|
phase: "context",
|
|
3971
3972
|
category: "project",
|
|
3972
3973
|
safeMessage: message,
|
|
3973
3974
|
runDir: paths.root,
|
|
3974
3975
|
});
|
|
3975
|
-
store.
|
|
3976
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), `# Run ${runId} (plan)\n\n- Lifecycle: failed\n- Phase: context\n\n${message}\n`);
|
|
3976
3977
|
log.emit("output.ready", { kind: "summary", path: "final/summary.md", state: "diagnostic" });
|
|
3977
3978
|
log.emit("run.failed", {
|
|
3978
3979
|
lifecycle: "failed",
|
|
@@ -4085,7 +4086,7 @@ export class Orchestrator {
|
|
|
4085
4086
|
const text = outcome.text ?? "(no output)";
|
|
4086
4087
|
plans.push({ id: outcome.harnessId, text });
|
|
4087
4088
|
// The planner's own saved copy keeps its exact text (INV-146).
|
|
4088
|
-
store.
|
|
4089
|
+
await store.writeTextAsync(join(paths.root, "plans", `${outcome.harnessId}.md`), text + "\n");
|
|
4089
4090
|
// Solo planning (D31): the FIRST successful planner is the plan; later
|
|
4090
4091
|
// pool members are a sequential fallback chain (ask parity), not
|
|
4091
4092
|
// parallel co-authors. Council re-enables the multi-draft round.
|
|
@@ -4102,7 +4103,7 @@ export class Orchestrator {
|
|
|
4102
4103
|
}
|
|
4103
4104
|
finally {
|
|
4104
4105
|
// Planners done (or threw) — reclaim scoped scratch/API-route state.
|
|
4105
|
-
roHome.dispose();
|
|
4106
|
+
await roHome.dispose();
|
|
4106
4107
|
}
|
|
4107
4108
|
if (input.signal?.aborted) {
|
|
4108
4109
|
return cancelledResult(log, runId, taskId, "plan", paths.root, planAttempts.map((p) => ({
|
|
@@ -4272,7 +4273,7 @@ export class Orchestrator {
|
|
|
4272
4273
|
// recorded user intent is the CALLER's goal.
|
|
4273
4274
|
const contract = this.buildContract({ ...input, prompt: opts.contractIntent ?? prompt }, taskId, opts.mode);
|
|
4274
4275
|
const quotaSnapshots = this.quotaSnapshotPreflight();
|
|
4275
|
-
const { store, paths, log, ledger, runContext } = beginAnnouncedRun({
|
|
4276
|
+
const { store, paths, log, ledger, runContext } = await beginAnnouncedRun({
|
|
4276
4277
|
input,
|
|
4277
4278
|
contract,
|
|
4278
4279
|
quotaSnapshots,
|
|
@@ -4284,7 +4285,7 @@ export class Orchestrator {
|
|
|
4284
4285
|
phase: "report",
|
|
4285
4286
|
prompt,
|
|
4286
4287
|
}, announce);
|
|
4287
|
-
store.
|
|
4288
|
+
await store.writeYamlAsync(join(paths.contextDir, "task.yaml"), contract);
|
|
4288
4289
|
log.emit("task.contract.created", { task_contract_hash: hashJson(contract) });
|
|
4289
4290
|
// The ask/deep-scan report stays bare (its scouts read the tree themselves);
|
|
4290
4291
|
// no lazy ContextPack section is attached here.
|
|
@@ -4311,7 +4312,7 @@ export class Orchestrator {
|
|
|
4311
4312
|
}));
|
|
4312
4313
|
}
|
|
4313
4314
|
catch (err) {
|
|
4314
|
-
roHome.dispose();
|
|
4315
|
+
await roHome.dispose();
|
|
4315
4316
|
const message = safeErrorMessage(err);
|
|
4316
4317
|
writeRoutingFailureTerminal(store, paths, log, {
|
|
4317
4318
|
runId,
|
|
@@ -4539,7 +4540,7 @@ export class Orchestrator {
|
|
|
4539
4540
|
});
|
|
4540
4541
|
attemptTelemetries.push({ attemptId, harnessId: adapter.id, telemetry });
|
|
4541
4542
|
if (opts.deepScan) {
|
|
4542
|
-
store.
|
|
4543
|
+
await store.writeTextAsync(join(paths.findingsDir, `${attemptId}-error.md`), `# Explorer ${attemptId} failed\n\n${message}\n`);
|
|
4543
4544
|
}
|
|
4544
4545
|
return { status: "launched" };
|
|
4545
4546
|
}
|
|
@@ -4608,6 +4609,7 @@ export class Orchestrator {
|
|
|
4608
4609
|
...(knobs.ignored.length > 0 ? { ignored_settings: knobs.ignored } : {}),
|
|
4609
4610
|
});
|
|
4610
4611
|
try {
|
|
4612
|
+
const pacing = { waiting: false, version: 0 };
|
|
4611
4613
|
const watchedReport = withInactivityWatchdog(runModelGovernedRoute(routed, runSpec), {
|
|
4612
4614
|
timeoutMs: harnessInactivityTimeoutMs(this.config(input.repoRoot)),
|
|
4613
4615
|
countsAsProgress: countsAsAgentProgress,
|
|
@@ -4615,11 +4617,12 @@ export class Orchestrator {
|
|
|
4615
4617
|
tryAbort.abort();
|
|
4616
4618
|
void adapter.cancel?.(activeSessionId)?.catch(() => { });
|
|
4617
4619
|
},
|
|
4618
|
-
|
|
4619
|
-
suspensionVersion: () => reportInteraction?.suspensionVersion?.() ?? 0,
|
|
4620
|
+
...laneSuspension(pacing, reportInteraction),
|
|
4620
4621
|
stopSignal: input.signal, // after Stop: drained events are recorded, never used
|
|
4621
4622
|
});
|
|
4622
|
-
|
|
4623
|
+
const files = [paths.eventsPath, attemptEventsPath];
|
|
4624
|
+
const read = pacedByAppends(watchedReport, files, pacing);
|
|
4625
|
+
for await (const ev of read) {
|
|
4623
4626
|
// A read after Stop is stored evidence only; a callback may itself press Stop.
|
|
4624
4627
|
const shown = !input.signal?.aborted && ev.payload?.["buffered"] !== true;
|
|
4625
4628
|
if (shown)
|
|
@@ -4804,7 +4807,7 @@ export class Orchestrator {
|
|
|
4804
4807
|
});
|
|
4805
4808
|
launched.delete(tried);
|
|
4806
4809
|
if (opts.deepScan) {
|
|
4807
|
-
store.
|
|
4810
|
+
await store.writeTextAsync(join(paths.findingsDir, `${attemptId}-error.md`), `# Explorer ${attemptId} failed\n\n${harnessError}\n`);
|
|
4808
4811
|
}
|
|
4809
4812
|
return { status: "launched" };
|
|
4810
4813
|
}
|
|
@@ -4836,7 +4839,7 @@ export class Orchestrator {
|
|
|
4836
4839
|
const scoutTag = scoutInterrupted
|
|
4837
4840
|
? ` interrupted (${interruptionDetail(roFinalized.reason)})`
|
|
4838
4841
|
: ` (${adapter.id})`;
|
|
4839
|
-
store.
|
|
4842
|
+
await store.writeTextAsync(join(paths.findingsDir, `${attemptId}${scoutInterrupted ? "-interrupted" : ""}.md`), `# Explorer ${attemptId}${scoutTag}\n\n${report || "(no output)"}${warningNote}\n`);
|
|
4840
4843
|
}
|
|
4841
4844
|
return { status: "launched" };
|
|
4842
4845
|
};
|
|
@@ -4981,7 +4984,7 @@ export class Orchestrator {
|
|
|
4981
4984
|
finally {
|
|
4982
4985
|
// All read-only attempts done (or threw) — reclaim scoped scratch and
|
|
4983
4986
|
// injected API-route state. Vendor-owned native credentials were not copied.
|
|
4984
|
-
roHome.dispose();
|
|
4987
|
+
await roHome.dispose();
|
|
4985
4988
|
}
|
|
4986
4989
|
const candidateSummaries = attempts.map((a) => ({
|
|
4987
4990
|
attemptId: a.attemptId,
|
|
@@ -5037,7 +5040,7 @@ export class Orchestrator {
|
|
|
5037
5040
|
: reducedReport !== null
|
|
5038
5041
|
? reducedReport
|
|
5039
5042
|
: rawScoutBundle({ succeeded, unsuccessful, status: deepScanSynthesis });
|
|
5040
|
-
store.
|
|
5043
|
+
await store.writeTextAsync(join(paths.finalDir, opts.artifactName), `# ${opts.title}\n\n${report}\n`);
|
|
5041
5044
|
// ask is the only read-only strategy that can carry a structured-output
|
|
5042
5045
|
// contract (the boundary refuses the rest); validate the FINAL aggregate
|
|
5043
5046
|
// (the reduced synthesis, or the honest bundle for a degraded scan) — never
|
|
@@ -5058,7 +5061,7 @@ export class Orchestrator {
|
|
|
5058
5061
|
path: `final/${opts.artifactName}`,
|
|
5059
5062
|
});
|
|
5060
5063
|
if (opts.deepScan) {
|
|
5061
|
-
store.
|
|
5064
|
+
await store.writeYamlAsync(join(paths.finalDir, "explore-findings.yaml"), {
|
|
5062
5065
|
mode: "explore",
|
|
5063
5066
|
width,
|
|
5064
5067
|
attempts: attempts.map((a) => ({
|
|
@@ -5077,7 +5080,7 @@ export class Orchestrator {
|
|
|
5077
5080
|
})),
|
|
5078
5081
|
read_only: true,
|
|
5079
5082
|
});
|
|
5080
|
-
store.
|
|
5083
|
+
await store.writeTextAsync(join(paths.finalDir, "omissions.md"), `# Omissions\n\n${unsuccessful.map((a) => `- ${a.attemptId} / ${a.harnessId} (${a.status}): ${a.error}`).join("\n") || "- None recorded by the runner. Synthesis claims still require evidence checks."}\n`);
|
|
5081
5084
|
}
|
|
5082
5085
|
let terminalFacts = makeOutcomeFacts("succeeded");
|
|
5083
5086
|
const reportBudgetTerminal = ledger.terminal();
|
|
@@ -5106,13 +5109,13 @@ export class Orchestrator {
|
|
|
5106
5109
|
.join(", ");
|
|
5107
5110
|
// A delivered report that still ends unsuccessfully or blocked keeps it and names every failed try.
|
|
5108
5111
|
const reportPool = terminalPoolAttempts(terminalFacts, attempts);
|
|
5109
|
-
store.
|
|
5112
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), `# Run ${runId} (${opts.mode})\n\n- Harnesses: ${harnessLabel}\n- Lifecycle: ${terminalFacts.lifecycle}${terminalFacts.reason ? ` (${terminalFacts.reason})` : ""}\n\n${withPoolAttempts(report, reportPool)}\n`);
|
|
5110
5113
|
const reportProducerAttemptId = opts.deepScan &&
|
|
5111
5114
|
deepScanSynthesis?.status === "succeeded" &&
|
|
5112
5115
|
deepScanSynthesis.reducer_attempt_id
|
|
5113
5116
|
? deepScanSynthesis.reducer_attempt_id
|
|
5114
5117
|
: (succeeded[0]?.attemptId ?? "a01");
|
|
5115
|
-
store.
|
|
5118
|
+
await store.writeYamlAsync(join(paths.finalDir, "work_product.yaml"), {
|
|
5116
5119
|
id: newId("wp"),
|
|
5117
5120
|
kind: "report",
|
|
5118
5121
|
source_task_id: taskId,
|