sortie-dogs 0.16.4 → 0.16.5
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/asset-version.d.ts +1 -1
- package/dist/asset-version.js +1 -1
- package/dist/core/operator-mission.d.ts +2 -0
- package/dist/core/operator-mission.js +1 -1
- package/dist/core/operator-runtime.d.ts +6 -0
- package/dist/core/operator-runtime.js +17 -1
- package/dist/plugin/index.js +52 -50
- package/dist/plugin/profiled.js +175 -125
- package/dist/plugin/runtime-bridge.d.ts +8 -0
- package/package.json +1 -1
package/dist/asset-version.d.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
* installed project marker without importing every asset body.
|
|
4
4
|
*/
|
|
5
5
|
export declare const RUNTIME_ASSET_VERSION = "0.3.89-completion-proof-v1";
|
|
6
|
-
export declare const V010_RUNTIME_ASSET_VERSION = "0.16.
|
|
6
|
+
export declare const V010_RUNTIME_ASSET_VERSION = "0.16.5-mission-direct-retry-v2";
|
|
7
7
|
export declare const CODEX_SKILL_ASSET_VERSION = "0.14.6-codex-skill-v1";
|
|
8
8
|
export type RuntimeAssetVersion = typeof RUNTIME_ASSET_VERSION | typeof V010_RUNTIME_ASSET_VERSION | typeof CODEX_SKILL_ASSET_VERSION;
|
package/dist/asset-version.js
CHANGED
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
* installed project marker without importing every asset body.
|
|
4
4
|
*/
|
|
5
5
|
export const RUNTIME_ASSET_VERSION = "0.3.89-completion-proof-v1";
|
|
6
|
-
export const V010_RUNTIME_ASSET_VERSION = "0.16.
|
|
6
|
+
export const V010_RUNTIME_ASSET_VERSION = "0.16.5-mission-direct-retry-v2";
|
|
7
7
|
export const CODEX_SKILL_ASSET_VERSION = "0.14.6-codex-skill-v1";
|
|
@@ -64,6 +64,8 @@ export interface MissionAttempt {
|
|
|
64
64
|
/** Fingerprint of the settled scoped candidate against which a later Rescue is proposed. */
|
|
65
65
|
candidateID?: string;
|
|
66
66
|
kind: "implementation" | "normal_remediation" | "astra_rescue" | "reviewer_correction" | "direct_execution";
|
|
67
|
+
/** A direct execution may itself be the one ordinary remediation. */
|
|
68
|
+
normalRemediation?: boolean;
|
|
67
69
|
status: "pending" | "dispatched" | "succeeded" | "failed" | "cancelled" | "unconfirmed" | "handed-off";
|
|
68
70
|
callID?: string;
|
|
69
71
|
childSessionID?: string;
|
|
@@ -964,7 +964,7 @@ export function missionPacket(mission, run, includeWorkQuantity = true) {
|
|
|
964
964
|
: run?.phase === "awaiting-decision" ? (run.units.some(unit => unit.dispatchDenial)
|
|
965
965
|
? "Coordinator: inspect units[].dispatch_denial before changing the plan. Correct only its diagnosed cause; do not repeat an unchanged refused Task or replan for a host-state mismatch. Report an unresolved runtime mismatch with the loaded runtime identity; preserve requirements and cumulative spend."
|
|
966
966
|
: run.units.some(unit => unit.status === "failed" && unit.resultClass === "acceptance" && unit.failure?.outcome === "fail" && !unit.normalRemediationUsed)
|
|
967
|
-
?
|
|
967
|
+
? `Coordinator: one exact declared validation failed. Reconcile the ${run.units.some(unit => unit.status === "failed" && unit.resultClass === "acceptance" && unit.failure?.outcome === "fail" && !unit.normalRemediationUsed && unit.directExecution) ? "settled direct execution" : "returned Worker"} and cumulative budget, then call retry_mission_unit once for that unit before replanning. This preserves the same scope and acceptance.`
|
|
968
968
|
: run.units.some(unit => unit.status === "failed" && unit.resultClass === "acceptance" && unit.failure?.outcome === "fail" && unit.normalRemediationUsed && !unit.terminalRescue)
|
|
969
969
|
? "Coordinator: the one ordinary remediation failed the declared validation again. If its native terminal, writer release, exact candidate and cumulative budget permit, call rescue_mission_unit once; inspect and report a non_rescue reason, then continue ordinary correction within budget. Rescue does not bypass validation, review or root acceptance."
|
|
970
970
|
: "Coordinator: correct the cause and call plan_units with the remaining work and all requirements; budget is cumulative.")
|
|
@@ -155,6 +155,12 @@ interface UnitState {
|
|
|
155
155
|
handedOffAt: string;
|
|
156
156
|
settledCallID?: string;
|
|
157
157
|
})[];
|
|
158
|
+
/** Settled direct attempts are historical, not handoffs or validation for a later attempt. */
|
|
159
|
+
priorDirectExecutions?: (NonNullable<UnitState["directExecution"]> & {
|
|
160
|
+
callID: string;
|
|
161
|
+
resultClass: string | null;
|
|
162
|
+
failure?: SerialDispatchSettlement["failure"];
|
|
163
|
+
})[];
|
|
158
164
|
resultClass: string | null;
|
|
159
165
|
failure?: SerialDispatchSettlement["failure"];
|
|
160
166
|
normalRemediationUsed?: boolean;
|
|
@@ -393,6 +393,7 @@ export class OperatorRuntime {
|
|
|
393
393
|
...(unit.reviewerCorrection ? { reviewerCorrection: sizedChecks(unit.reviewerCorrection) } : {}),
|
|
394
394
|
...(unit.validationRegistration ? { validationRegistration: sizedChecks(unit.validationRegistration) } : {}),
|
|
395
395
|
...(Array.isArray(unit.directHandoffs) ? { directHandoffs: unit.directHandoffs.map(sizedChecks) } : {}),
|
|
396
|
+
...(Array.isArray(unit.priorDirectExecutions) ? { priorDirectExecutions: unit.priorDirectExecutions.map(sizedChecks) } : {}),
|
|
396
397
|
};
|
|
397
398
|
}) : execution.units };
|
|
398
399
|
if (Buffer.byteLength(JSON.stringify(sized)) > OPERATOR_LIMITS.planBytes * 4)
|
|
@@ -2000,11 +2001,19 @@ export class OperatorRuntime {
|
|
|
2000
2001
|
state.units.some(candidate => candidate.terminalRescue))
|
|
2001
2002
|
throw new Error("operator-mission-normal-remediation-unavailable");
|
|
2002
2003
|
await this.verifyControls(unit);
|
|
2004
|
+
if (unit.directExecution) {
|
|
2005
|
+
if (!unit.directExecution.finishedAt || !unit.callID)
|
|
2006
|
+
throw new Error("operator-mission-normal-remediation-unavailable");
|
|
2007
|
+
(unit.priorDirectExecutions ??= []).push({ ...structuredClone(unit.directExecution), callID: unit.callID,
|
|
2008
|
+
resultClass: unit.resultClass, failure: structuredClone(unit.failure) });
|
|
2009
|
+
delete unit.directExecution;
|
|
2010
|
+
}
|
|
2003
2011
|
// The ordinary retry keeps its exact scope and validation, but the next Worker needs the
|
|
2004
2012
|
// host-observed failed command/exit rather than reconstructing it from an earlier session.
|
|
2005
2013
|
unit.task = { ...unit.task, prompt: `${unit.task.prompt}\nnormal_remediation_prior_validation: ${JSON.stringify({
|
|
2006
2014
|
command: unit.failure.command, exit_code: unit.failure.exitCode
|
|
2007
|
-
})}
|
|
2015
|
+
})}${unit.validationRegistration
|
|
2016
|
+
? `\nnormal_remediation_validation: ${JSON.stringify({ validation: unitValidation(unit), validation_cwd: unitValidationCwd(unit) })}` : ""}` };
|
|
2008
2017
|
unit.normalRemediationUsed = true;
|
|
2009
2018
|
unit.status = "pending";
|
|
2010
2019
|
unit.callID = null;
|
|
@@ -2048,6 +2057,13 @@ export class OperatorRuntime {
|
|
|
2048
2057
|
await this.verifyControls(unit);
|
|
2049
2058
|
// The Rescue route is sealed in host-owned operator state and the returned Task reference.
|
|
2050
2059
|
// Do not alter the registered handoff or expose the stable runtime's rescue capability.
|
|
2060
|
+
if (unit.directExecution) {
|
|
2061
|
+
if (!unit.directExecution.finishedAt || !unit.callID)
|
|
2062
|
+
throw new Error("operator-mission-terminal-rescue-unavailable");
|
|
2063
|
+
(unit.priorDirectExecutions ??= []).push({ ...structuredClone(unit.directExecution), callID: unit.callID,
|
|
2064
|
+
resultClass: unit.resultClass, failure: structuredClone(unit.failure) });
|
|
2065
|
+
delete unit.directExecution;
|
|
2066
|
+
}
|
|
2051
2067
|
unit.task = { ...unit.task, prompt: unit.task.prompt.replace(header, line => `${line}\nterminal_rescue_attempt: ${input.attempt_id}`) };
|
|
2052
2068
|
unit.terminalRescue = { attempt_id: input.attempt_id, selected_model: input.selected_model,
|
|
2053
2069
|
selected_variant: input.selected_variant, accepted_base: structuredClone(base), prior_failure: structuredClone(unit.failure), status: "prepared" };
|
package/dist/plugin/index.js
CHANGED
|
@@ -7942,6 +7942,56 @@ export const SortieDogsPlugin = async (input, options) => {
|
|
|
7942
7942
|
}
|
|
7943
7943
|
},
|
|
7944
7944
|
};
|
|
7945
|
+
// Both direct and Worker retries must prove the exact reservation settled and its writer released.
|
|
7946
|
+
// A direct actor is not a native child Task and must not acquire a fabricated terminal record.
|
|
7947
|
+
async function missionDispatchWriterReleased(root, taskID, callID, actor, writeScopes) {
|
|
7948
|
+
const snapshot = await (await goalLedger(root)).readGoal();
|
|
7949
|
+
const origin = await input.runtimeBridge?.missionDispatchOrigin?.(root, taskID, callID);
|
|
7950
|
+
const reservationID = goalFingerprint({ goal_id: snapshot.state.goal_id, unit_id: taskID, call_id: origin?.callID ?? callID });
|
|
7951
|
+
if (snapshot.state.outstanding_reservations.some(item => item.reservation_id === reservationID) ||
|
|
7952
|
+
!snapshot.records.some(({ event }) => event.kind === "unit.settled" && event.goal_id === snapshot.state.goal_id &&
|
|
7953
|
+
event.unit_id === taskID && event.reservation_id === reservationID)) {
|
|
7954
|
+
return { ready: false, reason: "exact_dispatch_settlement_missing" };
|
|
7955
|
+
}
|
|
7956
|
+
const active = activeSessions.get(actor), authorization = sessionAuthorizations.get(actor);
|
|
7957
|
+
if (authorization && (authorization.rootSessionID !== root || authorization.taskID !== taskID ||
|
|
7958
|
+
authorization.dispatchCallID !== callID))
|
|
7959
|
+
return { ready: false, reason: "writer_owned_by_other_dispatch" };
|
|
7960
|
+
if (active?.inFlightCalls.size) {
|
|
7961
|
+
const response = await input.client?.session?.messages?.({ path: { id: actor }, query: { directory: input.directory } }).catch(() => undefined);
|
|
7962
|
+
const history = isRecord(response) && Array.isArray(response.data) ? response.data : undefined;
|
|
7963
|
+
if (!history)
|
|
7964
|
+
return { ready: false, reason: "tool_terminal_records_unavailable" };
|
|
7965
|
+
for (const pendingID of active.inFlightCalls) {
|
|
7966
|
+
const parts = history.flatMap(message => isRecord(message) && isRecord(message.info) &&
|
|
7967
|
+
message.info.sessionID === actor && Array.isArray(message.parts) ? message.parts : [])
|
|
7968
|
+
.filter(part => isRecord(part) && part.type === "tool" && part.callID === pendingID);
|
|
7969
|
+
if (parts.length !== 1 || !isRecord(parts[0]) || !isRecord(parts[0].state) ||
|
|
7970
|
+
!["completed", "error"].includes(String(parts[0].state.status)))
|
|
7971
|
+
return { ready: false, reason: "tool_dispatch_active_or_unproven" };
|
|
7972
|
+
}
|
|
7973
|
+
active.inFlightCalls.clear();
|
|
7974
|
+
}
|
|
7975
|
+
const released = JSON.parse(await releaseWriteGate(actor));
|
|
7976
|
+
if (released.status === "denied")
|
|
7977
|
+
return { ready: false, reason: released.reason };
|
|
7978
|
+
if (active)
|
|
7979
|
+
active.released = true;
|
|
7980
|
+
const scopeRoot = await durableScopeRoot(project?.root ?? input.directory);
|
|
7981
|
+
if (scopeRoot === undefined)
|
|
7982
|
+
return active?.parallel === "valid"
|
|
7983
|
+
? { ready: false, reason: "writer_registry_unavailable" } : { ready: true };
|
|
7984
|
+
try {
|
|
7985
|
+
const local = writeScopes.map(path => relative(project?.root ?? input.directory, resolve(project?.root ?? input.directory, normalizeManifestScope(path).path)).replaceAll("\\", "/"))
|
|
7986
|
+
.filter(path => path !== ".." && !path.startsWith("../") && !isAbsolute(path));
|
|
7987
|
+
const scope = normalizeWorktreeScope({ read: [], write: local });
|
|
7988
|
+
return await new ScopeLeaseRegistry(scopeRoot).hasConflictingLease(scope)
|
|
7989
|
+
? { ready: false, reason: "writer_lease_owned_elsewhere" } : { ready: true };
|
|
7990
|
+
}
|
|
7991
|
+
catch {
|
|
7992
|
+
return { ready: false, reason: "writer_registry_unavailable" };
|
|
7993
|
+
}
|
|
7994
|
+
}
|
|
7945
7995
|
input.runtimeBridge?.connected?.({
|
|
7946
7996
|
renderReturnReport: async (root, text, expectedReceipt, missionReview, reviewEvidenceGaps) => {
|
|
7947
7997
|
let rendered;
|
|
@@ -8571,56 +8621,8 @@ export const SortieDogsPlugin = async (input, options) => {
|
|
|
8571
8621
|
throw new Error("mission-activation-grant-stale");
|
|
8572
8622
|
}
|
|
8573
8623
|
}),
|
|
8574
|
-
missionWorkerTerminal:
|
|
8575
|
-
|
|
8576
|
-
const snapshot = await (await goalLedger(root)).readGoal();
|
|
8577
|
-
const origin = await input.runtimeBridge?.missionDispatchOrigin?.(root, terminal.taskID, terminal.callID);
|
|
8578
|
-
const reservationID = goalFingerprint({ goal_id: snapshot.state.goal_id, unit_id: terminal.taskID, call_id: origin?.callID ?? terminal.callID });
|
|
8579
|
-
if (snapshot.state.outstanding_reservations.some(item => item.reservation_id === reservationID) ||
|
|
8580
|
-
!snapshot.records.some(({ event }) => event.kind === "unit.settled" && event.goal_id === snapshot.state.goal_id &&
|
|
8581
|
-
event.unit_id === terminal.taskID && event.reservation_id === reservationID)) {
|
|
8582
|
-
return { ready: false, reason: "exact_dispatch_settlement_missing" };
|
|
8583
|
-
}
|
|
8584
|
-
const active = activeSessions.get(childSessionID), authorization = sessionAuthorizations.get(childSessionID);
|
|
8585
|
-
if (authorization && (authorization.rootSessionID !== root || authorization.taskID !== terminal.taskID ||
|
|
8586
|
-
authorization.dispatchCallID !== terminal.callID)) {
|
|
8587
|
-
return { ready: false, reason: "writer_owned_by_other_dispatch" };
|
|
8588
|
-
}
|
|
8589
|
-
if (active?.inFlightCalls.size) {
|
|
8590
|
-
const response = await input.client?.session?.messages?.({ path: { id: childSessionID }, query: { directory: input.directory } }).catch(() => undefined);
|
|
8591
|
-
const history = isRecord(response) && Array.isArray(response.data) ? response.data : undefined;
|
|
8592
|
-
if (!history)
|
|
8593
|
-
return { ready: false, reason: "tool_terminal_records_unavailable" };
|
|
8594
|
-
for (const callID of active.inFlightCalls) {
|
|
8595
|
-
const parts = history.flatMap(message => isRecord(message) && isRecord(message.info) &&
|
|
8596
|
-
message.info.sessionID === childSessionID && Array.isArray(message.parts) ? message.parts : [])
|
|
8597
|
-
.filter(part => isRecord(part) && part.type === "tool" && part.callID === callID);
|
|
8598
|
-
if (parts.length !== 1 || !isRecord(parts[0]) || !isRecord(parts[0].state) ||
|
|
8599
|
-
!["completed", "error"].includes(String(parts[0].state.status)))
|
|
8600
|
-
return { ready: false, reason: "tool_dispatch_active_or_unproven" };
|
|
8601
|
-
}
|
|
8602
|
-
active.inFlightCalls.clear();
|
|
8603
|
-
}
|
|
8604
|
-
const released = JSON.parse(await releaseWriteGate(childSessionID));
|
|
8605
|
-
if (released.status === "denied")
|
|
8606
|
-
return { ready: false, reason: released.reason };
|
|
8607
|
-
if (active)
|
|
8608
|
-
active.released = true;
|
|
8609
|
-
const scopeRoot = await durableScopeRoot(project?.root ?? input.directory);
|
|
8610
|
-
if (scopeRoot === undefined)
|
|
8611
|
-
return active?.parallel === "valid"
|
|
8612
|
-
? { ready: false, reason: "writer_registry_unavailable" } : { ready: true };
|
|
8613
|
-
try {
|
|
8614
|
-
const local = writeScopes.map(path => relative(project?.root ?? input.directory, resolve(project?.root ?? input.directory, normalizeManifestScope(path).path)).replaceAll("\\", "/"))
|
|
8615
|
-
.filter(path => path !== ".." && !path.startsWith("../") && !isAbsolute(path));
|
|
8616
|
-
const scope = normalizeWorktreeScope({ read: [], write: local });
|
|
8617
|
-
return await new ScopeLeaseRegistry(scopeRoot).hasConflictingLease(scope)
|
|
8618
|
-
? { ready: false, reason: "writer_lease_owned_elsewhere" } : { ready: true };
|
|
8619
|
-
}
|
|
8620
|
-
catch {
|
|
8621
|
-
return { ready: false, reason: "writer_registry_unavailable" };
|
|
8622
|
-
}
|
|
8623
|
-
},
|
|
8624
|
+
missionWorkerTerminal: (root, terminal, writeScopes) => missionDispatchWriterReleased(root, terminal.taskID, terminal.callID, terminal.childSessionID, writeScopes),
|
|
8625
|
+
missionDirectTerminal: (root, dispatch, writeScopes) => missionDispatchWriterReleased(root, dispatch.taskID, dispatch.callID, dispatch.actor, writeScopes),
|
|
8624
8626
|
expandMissionWriteGate,
|
|
8625
8627
|
registerGoalDeclaration: async (root, prompt, missionRevision) => {
|
|
8626
8628
|
if (!isCoordinatorSession(root) && !await recoverCoordinatorRoot(root))
|
package/dist/plugin/profiled.js
CHANGED
|
@@ -940,7 +940,8 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
940
940
|
: undefined;
|
|
941
941
|
const attemptFailure = result.disposition === "cancelled"
|
|
942
942
|
? { category: "cancellation", code: "native-task-cancelled" }
|
|
943
|
-
: result.resultClass === "acceptance" && result.failure?.outcome === "fail" &&
|
|
943
|
+
: result.resultClass === "acceptance" && result.failure?.outcome === "fail" &&
|
|
944
|
+
(observed.outcome === "completed" || !!unit.directExecution?.finishedAt)
|
|
944
945
|
? { category: "implementation",
|
|
945
946
|
code: `validation-failed:${result.failure.exitCode ?? "unknown"}` }
|
|
946
947
|
: result.resultClass === "process-defect"
|
|
@@ -1085,10 +1086,28 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
1085
1086
|
unit.childSessionID !== attempt.childSessionID || /^task_id: (.+)$/m.exec(unit.task.prompt)?.[1] !== attempt.taskID) {
|
|
1086
1087
|
return { status: "non_rescue", reason: "terminal_identity_conflict" };
|
|
1087
1088
|
}
|
|
1088
|
-
if (unit.directExecution)
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1089
|
+
if (unit.directExecution) {
|
|
1090
|
+
if (!unit.directExecution.finishedAt || unit.status === "running")
|
|
1091
|
+
return { status: "non_rescue", reason: "direct_unit_still_running" };
|
|
1092
|
+
if (unit.directExecution.actor !== attempt.childSessionID)
|
|
1093
|
+
return { status: "non_rescue", reason: "terminal_identity_conflict" };
|
|
1094
|
+
if (checkLiveOutcome) {
|
|
1095
|
+
try {
|
|
1096
|
+
await control.assertActiveGoal(root, await operators.completionGoalFingerprint(run));
|
|
1097
|
+
}
|
|
1098
|
+
catch {
|
|
1099
|
+
return { status: "non_rescue", reason: "goal_not_active" };
|
|
1100
|
+
}
|
|
1101
|
+
const budget = await control.currentBudget(root, { reconcileUsage: false });
|
|
1102
|
+
if (!budget || budget.reserved_units !== 0)
|
|
1103
|
+
return { status: "non_rescue", reason: "goal_reservation_unsettled" };
|
|
1104
|
+
const released = await control.missionDirectTerminal(root, { taskID: attempt.taskID, callID: attempt.callID,
|
|
1105
|
+
actor: unit.directExecution.actor }, unit.unit.write);
|
|
1106
|
+
if (!released.ready)
|
|
1107
|
+
return { status: "non_rescue", reason: released.reason ?? "writer_not_released" };
|
|
1108
|
+
}
|
|
1109
|
+
return { status: "ready", child: unit.directExecution.actor };
|
|
1110
|
+
}
|
|
1092
1111
|
const observed = await observeWorkerTerminal(mission, run, attempt, !checkLiveOutcome);
|
|
1093
1112
|
if (observed.status !== "ready")
|
|
1094
1113
|
return observed;
|
|
@@ -1306,7 +1325,7 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
1306
1325
|
run.units[0]?.status === "failed" && run.units[0]?.resultClass === "acceptance" &&
|
|
1307
1326
|
run.units[0]?.failure?.outcome === "fail" && !run.units[0]?.normalRemediationUsed) {
|
|
1308
1327
|
return { ...packet, task: missions.task(mission),
|
|
1309
|
-
next_action: `Fast-lane: declared validation failed. After the Worker returns, for the same scope and command ` +
|
|
1328
|
+
next_action: `Fast-lane: declared validation failed. After the ${run.units[0]?.directExecution ? "direct execution settles" : "Worker returns"}, for the same scope and command ` +
|
|
1310
1329
|
`call ${retryMissionUnit} once, then ${startDirectUnit} to correct and formally validate here when you have the context; ` +
|
|
1311
1330
|
`delegate its Worker only when useful. For a changed contract use ${planUnits} with executor=self, reason and one ` +
|
|
1312
1331
|
`corrective unit. The Coordinator remains available for actual coordination. Keep cumulative budget and failed history.` };
|
|
@@ -2398,8 +2417,10 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
2398
2417
|
const unit = run.units.find(item => item.directExecution?.actor === actor && item.status === "running");
|
|
2399
2418
|
const taskID = /^task_id: (.+)$/mu.exec(unit.task.prompt)[1];
|
|
2400
2419
|
await missions.update(root, mission => {
|
|
2420
|
+
const previous = [...(mission.attempts ?? [])].reverse().find(item => item.runID === run.runID && item.unitID === unit.unit.id);
|
|
2401
2421
|
(mission.attempts ??= []).push({ attemptID: randomUUID(), runID: run.runID, unitID: unit.unit.id,
|
|
2402
|
-
taskID, kind: "direct_execution",
|
|
2422
|
+
taskID, kind: "direct_execution", ...(unit.normalRemediationUsed ? { normalRemediation: true } : {}),
|
|
2423
|
+
...(previous ? { predecessorAttemptID: previous.attemptID } : {}), status: "dispatched", callID: unit.callID, childSessionID: actor });
|
|
2403
2424
|
});
|
|
2404
2425
|
direct = await directExecution(actor);
|
|
2405
2426
|
}
|
|
@@ -2416,7 +2437,7 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
2416
2437
|
throw new Error("mission-run-registration-incomplete: retry plan_units with the same plan to finish goal registration and Mission binding; no unit admitted");
|
|
2417
2438
|
await operators.verifyContinuityControls(run);
|
|
2418
2439
|
}
|
|
2419
|
-
async function assertDirectPlanningQuiescent(actor, planningCallID) {
|
|
2440
|
+
async function assertDirectPlanningQuiescent(actor, planningCallID, planningTool = planUnits) {
|
|
2420
2441
|
await control.assertDirectUnitQuiescent(actor);
|
|
2421
2442
|
// Cold hook state is not proof. Only the exact current planner may be pending;
|
|
2422
2443
|
// a completed background launch or another Task remains an active/unproven writer.
|
|
@@ -2433,7 +2454,7 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
2433
2454
|
throw new Error("mission-replan-terminal-unreconciled:tool_terminal_records_unavailable");
|
|
2434
2455
|
if (part.type !== "tool")
|
|
2435
2456
|
continue;
|
|
2436
|
-
if (part.callID === planningCallID && planningCallID && part.tool ===
|
|
2457
|
+
if (part.callID === planningCallID && planningCallID && part.tool === planningTool)
|
|
2437
2458
|
continue;
|
|
2438
2459
|
if (typeof part.callID !== "string")
|
|
2439
2460
|
throw new Error("mission-replan-terminal-unreconciled:tool_identity_unavailable");
|
|
@@ -2703,129 +2724,158 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
2703
2724
|
return JSON.stringify({ status: "recorded", consultation: consultation.consultations?.at(-1) });
|
|
2704
2725
|
} };
|
|
2705
2726
|
const retryMissionUnit = `${profile.toolPrefix}retry_mission_unit`, rescueMissionUnit = `${profile.toolPrefix}rescue_mission_unit`;
|
|
2706
|
-
tools[retryMissionUnit] = { description: "Owning Coordinator or Fast-lane Operator: after a host-classified Worker validation failure, prepare one same-scope remediation. Use start_direct_unit to correct and formally validate in this session, or dispatch the returned Worker when useful.
|
|
2727
|
+
tools[retryMissionUnit] = { description: "Owning Coordinator or Fast-lane Operator: after a host-classified direct or Worker validation failure, prepare one same-scope remediation. Use start_direct_unit to correct and formally validate in this session, or dispatch the returned Worker when useful. Exact settlement, a quiescent and released writer, and remaining cumulative unit budget are required; acceptance and scope remain intact.",
|
|
2707
2728
|
args: { unit_id: stringSchema }, execute: async (args, context) => {
|
|
2708
|
-
const { root
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
attempt.failure?.category
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2729
|
+
const { root } = await missionAuthority(context.sessionID);
|
|
2730
|
+
return serializeDispatchTransition(root, async () => {
|
|
2731
|
+
const { mission } = await missionAuthority(context.sessionID);
|
|
2732
|
+
if (context.sessionID !== (mission.coordinator ?? root) ||
|
|
2733
|
+
(await identity(context.sessionID)).role !== (mission.coordinator ? "dog-operator" : "dog-coordinator")) {
|
|
2734
|
+
throw new Error("mission-remediation-coordinator-required");
|
|
2735
|
+
}
|
|
2736
|
+
const run = await operators.required(root), unitID = String(args.unit_id);
|
|
2737
|
+
const unit = run.units.find(item => item.unit.id === unitID);
|
|
2738
|
+
const attempt = [...(mission.attempts ?? [])].reverse().find(item => item.runID === run.runID && item.unitID === unitID);
|
|
2739
|
+
const oldDirectUnknown = attempt?.kind === "direct_execution" && attempt.failure?.category === "unknown" &&
|
|
2740
|
+
attempt.failure.code === "acceptance" && typeof unit?.failure?.exitCode === "number" && unit.failure.exitCode !== 0 &&
|
|
2741
|
+
unit.directExecution?.checks.some(check => check.exitCode === unit.failure?.exitCode &&
|
|
2742
|
+
JSON.stringify(check.command) === JSON.stringify(unit.failure?.command));
|
|
2743
|
+
if (!unit || unit.status !== "failed" || unit.resultClass !== "acceptance" || unit.failure?.outcome !== "fail" ||
|
|
2744
|
+
unit.normalRemediationUsed || !attempt || !["implementation", "direct_execution"].includes(attempt.kind) || attempt.status !== "failed" ||
|
|
2745
|
+
(attempt.failure?.category !== "implementation" && !oldDirectUnknown))
|
|
2746
|
+
throw new Error("operator-mission-normal-remediation-unavailable");
|
|
2747
|
+
if (attempt.kind === "direct_execution") {
|
|
2748
|
+
try {
|
|
2749
|
+
await assertDirectPlanningQuiescent(context.sessionID, context.callID, retryMissionUnit);
|
|
2750
|
+
}
|
|
2751
|
+
catch (error) {
|
|
2752
|
+
const packet = missionPacket(mission, run);
|
|
2753
|
+
return JSON.stringify({ ...packet, run_status: packet.status, status: "non_rescue",
|
|
2754
|
+
reason: error instanceof Error ? error.message : "direct_unit_tools_unreconciled" });
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2757
|
+
const terminal = await missionWorkerTerminalProof(root, mission, run, attempt, true);
|
|
2758
|
+
if (terminal.status !== "ready") {
|
|
2759
|
+
const packet = missionPacket(mission, run);
|
|
2760
|
+
return JSON.stringify({ ...packet, run_status: packet.status, status: "non_rescue", reason: terminal.reason });
|
|
2761
|
+
}
|
|
2762
|
+
const budget = await control.currentBudget(root);
|
|
2763
|
+
if (!budget || budget.remaining_units < 1) {
|
|
2764
|
+
const packet = missionPacket(mission, run);
|
|
2765
|
+
return JSON.stringify({ ...packet, run_status: packet.status, status: "non_rescue", reason: "budget_exhausted", budget });
|
|
2766
|
+
}
|
|
2767
|
+
const prepared = await operators.prepareMissionNormalRemediation(root, run.runID, unitID);
|
|
2768
|
+
control.enableUnits(root, 1);
|
|
2769
|
+
const next = await operators.next(root, context.sessionID);
|
|
2770
|
+
return JSON.stringify({ status: "normal_remediation_prepared", run_id: prepared.runID,
|
|
2771
|
+
unit_id: unitID, task: record(next) ? next.task : undefined, budget: await control.currentBudget(root) });
|
|
2772
|
+
});
|
|
2735
2773
|
} };
|
|
2736
2774
|
tools[rescueMissionUnit] = { description: "Coordinator: only after the same unit's one ordinary remediation failed the same declared validation, evaluate one optional Astra Rescue. The host requires the current Mission failure class, reconciled native terminal, exact current candidate/acceptance/scope/validation, discovered model availability, one-use and cumulative budget; the returned Worker must still pass ordinary validation, independent review, and root acceptance. This is not the legacy sortie_execute_terminal_rescue tool.",
|
|
2737
2775
|
args: { unit_id: stringSchema }, execute: async (args, context) => {
|
|
2738
|
-
const { root
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2776
|
+
const { root } = await missionAuthority(context.sessionID);
|
|
2777
|
+
return serializeDispatchTransition(root, async () => {
|
|
2778
|
+
const { mission } = await missionAuthority(context.sessionID);
|
|
2779
|
+
if (context.sessionID !== mission.coordinator || (await identity(context.sessionID)).role !== "dog-operator") {
|
|
2780
|
+
throw new Error("mission-rescue-coordinator-required");
|
|
2781
|
+
}
|
|
2782
|
+
const run = await operators.required(root), unitID = String(args.unit_id);
|
|
2783
|
+
const unit = run.units.find(item => item.unit.id === unitID);
|
|
2784
|
+
const attempt = [...(mission.attempts ?? [])].reverse().find(item => item.runID === run.runID && item.unitID === unitID);
|
|
2785
|
+
const nonRescue = async (reason) => {
|
|
2786
|
+
await missions.update(root, state => {
|
|
2787
|
+
state.rescue = { attemptID: attempt?.attemptID ?? randomUUID(),
|
|
2788
|
+
runID: run.runID, unitID, status: "non_rescue", reason };
|
|
2789
|
+
});
|
|
2790
|
+
const packet = missionPacket(await missions.required(root), await operators.read(root));
|
|
2791
|
+
return JSON.stringify({ ...packet, run_status: packet.status, status: "non_rescue", reason });
|
|
2792
|
+
};
|
|
2793
|
+
if (!unit || unit.status !== "failed" || unit.resultClass !== "acceptance" || unit.failure?.outcome !== "fail" ||
|
|
2794
|
+
unit.normalRemediationUsed !== true || unit.terminalRescue || !attempt ||
|
|
2795
|
+
!(attempt.kind === "normal_remediation" || attempt.kind === "direct_execution" && attempt.normalRemediation === true) ||
|
|
2796
|
+
attempt.status !== "failed" || attempt.resultClass !== "acceptance" || attempt.failure?.category !== "implementation") {
|
|
2797
|
+
return nonRescue("normal_remediation_not_exhausted");
|
|
2798
|
+
}
|
|
2799
|
+
if (attempt.kind === "direct_execution") {
|
|
2800
|
+
try {
|
|
2801
|
+
await assertDirectPlanningQuiescent(context.sessionID, context.callID, rescueMissionUnit);
|
|
2802
|
+
}
|
|
2803
|
+
catch (error) {
|
|
2804
|
+
return nonRescue(error instanceof Error ? error.message : "direct_unit_tools_unreconciled");
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
const terminal = await missionWorkerTerminalProof(root, mission, run, attempt, true);
|
|
2808
|
+
if (terminal.status !== "ready")
|
|
2809
|
+
return nonRescue(terminal.reason);
|
|
2810
|
+
const candidate = await missionReviewSource(input.directory, run, [], mission.reviewBaseline, mission.reviewScope);
|
|
2811
|
+
if (!attempt.candidateID || attempt.candidateID !== candidate.fingerprint)
|
|
2812
|
+
return nonRescue("accepted_candidate_changed");
|
|
2813
|
+
const budget = await control.currentBudget(root);
|
|
2814
|
+
if (!budget || budget.reserved_units !== 0)
|
|
2815
|
+
return nonRescue("budget_exhausted");
|
|
2816
|
+
const budgetDetails = budget;
|
|
2817
|
+
const hasTimeLimit = typeof budgetDetails.time_limit_ms === "number";
|
|
2818
|
+
const timeLimit = hasTimeLimit ? budgetDetails.time_limit_ms : Number.MAX_SAFE_INTEGER;
|
|
2819
|
+
const consumedTime = hasTimeLimit ? budgetDetails.settled_time_ms : 0;
|
|
2820
|
+
const hasCostLimit = typeof budgetDetails.cost_limit_usd === "number";
|
|
2821
|
+
const costLimit = hasCostLimit ? budgetDetails.cost_limit_usd : Number.MAX_VALUE;
|
|
2822
|
+
const consumedCost = hasCostLimit ? budgetDetails.settled_cost_usd : (budgetDetails.settled_cost_usd ?? 0);
|
|
2823
|
+
if (!Number.isSafeInteger(timeLimit) || timeLimit < 0 || !Number.isSafeInteger(consumedTime) || consumedTime < 0 ||
|
|
2824
|
+
!Number.isFinite(costLimit) || costLimit < 0 || typeof consumedCost !== "number" || !Number.isFinite(consumedCost) || consumedCost < 0) {
|
|
2825
|
+
return nonRescue("budget_exhausted");
|
|
2826
|
+
}
|
|
2827
|
+
if ((hasTimeLimit && consumedTime >= timeLimit) || (hasCostLimit && consumedCost >= costLimit)) {
|
|
2828
|
+
return nonRescue("budget_exhausted");
|
|
2829
|
+
}
|
|
2830
|
+
const nativeModels = await readHostModels(input.client);
|
|
2831
|
+
const target = nativeModels?.has(DEFAULT_TERMINAL_RESCUE_MODEL)
|
|
2832
|
+
? { model: DEFAULT_TERMINAL_RESCUE_MODEL, variant: null } : null;
|
|
2833
|
+
const terminalIdentity = { run_id: run.runID, unit_id: unitID, attempt_id: attempt.attemptID,
|
|
2834
|
+
predecessor_attempt_id: attempt.predecessorAttemptID ?? null, candidate_id: candidate.fingerprint,
|
|
2835
|
+
route_id: `${profile.id}:mission:${unitID}`, child_id: terminal.child, call_id: attempt.callID };
|
|
2836
|
+
const priorFailure = attempt.failure;
|
|
2837
|
+
const policy = proposeTerminalRescue({ prior_attempt: { identity: terminalIdentity, role: "implementation", recovery_kind: "normal_remediation",
|
|
2838
|
+
disposition: "failed", failure: priorFailure ? { category: priorFailure.category, code: priorFailure.code } : null },
|
|
2839
|
+
terminal_reconciliation: { current: terminalIdentity, observation: { identity: terminalIdentity, disposition: "failed" }, evidence: {
|
|
2840
|
+
terminal: "satisfied", tools_quiescent: "satisfied", artifact_window_closed: "satisfied", writer_released: "satisfied",
|
|
2841
|
+
gate_released: "satisfied", lease_released: "satisfied", worktree_released: "satisfied"
|
|
2842
|
+
} },
|
|
2843
|
+
accepted_base: { candidate_id: candidate.fingerprint, contract_id: run.acceptanceFingerprint, scope: [...unit.unit.write],
|
|
2844
|
+
acceptance: [...run.acceptance], validation: [...unit.unit.validation] }, available_target: target,
|
|
2845
|
+
explicit_override: (attempt.selectedModel !== undefined && attempt.selectedModel !== PREVIEW_WORKER_ROUTE.model) ||
|
|
2846
|
+
(attempt.observedModel !== undefined && attempt.observedModel !== PREVIEW_WORKER_ROUTE.model) ||
|
|
2847
|
+
(attempt.observedVariant !== undefined && attempt.observedVariant !== PREVIEW_WORKER_ROUTE.variant),
|
|
2848
|
+
unit_rescue_count: (mission.attempts ?? []).filter(item => item.runID === run.runID && item.unitID === unitID && item.kind === "astra_rescue").length,
|
|
2849
|
+
active_run_rescue_count: (mission.attempts ?? []).filter(item => item.runID === run.runID && item.kind === "astra_rescue").length,
|
|
2850
|
+
budget_limits: { counters: { recovery_actions: budget.max_units, probe_iterations: 0, model_attempts: budget.max_units },
|
|
2851
|
+
resources: { time_ms: timeLimit, cost_usd: costLimit } },
|
|
2852
|
+
budget_consumed: { counters: { recovery_actions: budget.consumed_units + budget.reserved_units, probe_iterations: 0,
|
|
2853
|
+
model_attempts: budget.consumed_units + budget.reserved_units },
|
|
2854
|
+
resources: { time_ms: consumedTime, cost_usd: consumedCost } },
|
|
2855
|
+
budget_request: { counters: { recovery_actions: 1, probe_iterations: 0, model_attempts: 1 },
|
|
2856
|
+
// Current Mission charges native time/cost through its cumulative goal ledger at normal dispatch settlement;
|
|
2857
|
+
// this policy reservation consumes one existing unit, not an invented parallel resource allowance.
|
|
2858
|
+
resources: { time_ms: 0, cost_usd: 0 } } });
|
|
2859
|
+
if (policy.status !== "proposed")
|
|
2860
|
+
return nonRescue(policy.reason);
|
|
2861
|
+
const rescueAttemptID = randomUUID();
|
|
2862
|
+
const prepared = await operators.prepareMissionTerminalRescue(root, run.runID, unitID, {
|
|
2863
|
+
attempt_id: rescueAttemptID, selected_model: policy.proposal.target.model,
|
|
2864
|
+
selected_variant: policy.proposal.target.variant,
|
|
2865
|
+
accepted_base: { candidate_id: policy.proposal.accepted_base_candidate_id, contract_id: policy.proposal.contract_id,
|
|
2866
|
+
scope: policy.proposal.scope, acceptance: policy.proposal.acceptance, validation: policy.proposal.validation },
|
|
2867
|
+
});
|
|
2868
|
+
control.enableUnits(root, 1);
|
|
2746
2869
|
await missions.update(root, state => {
|
|
2747
|
-
state.rescue = { attemptID:
|
|
2748
|
-
|
|
2870
|
+
state.rescue = { attemptID: rescueAttemptID, runID: run.runID, unitID,
|
|
2871
|
+
selectedModel: policy.proposal.target.model, selectedVariant: policy.proposal.target.variant, status: "prepared" };
|
|
2749
2872
|
});
|
|
2750
|
-
const
|
|
2751
|
-
return JSON.stringify({
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
attempt.status !== "failed" || attempt.resultClass !== "acceptance" || attempt.failure?.category !== "implementation") {
|
|
2756
|
-
return nonRescue("normal_remediation_not_exhausted");
|
|
2757
|
-
}
|
|
2758
|
-
const terminal = await missionWorkerTerminalProof(root, mission, run, attempt, true);
|
|
2759
|
-
if (terminal.status !== "ready")
|
|
2760
|
-
return nonRescue(terminal.reason);
|
|
2761
|
-
const candidate = await missionReviewSource(input.directory, run, [], mission.reviewBaseline, mission.reviewScope);
|
|
2762
|
-
if (!attempt.candidateID || attempt.candidateID !== candidate.fingerprint)
|
|
2763
|
-
return nonRescue("accepted_candidate_changed");
|
|
2764
|
-
const budget = await control.currentBudget(root);
|
|
2765
|
-
if (!budget || budget.reserved_units !== 0)
|
|
2766
|
-
return nonRescue("budget_exhausted");
|
|
2767
|
-
const budgetDetails = budget;
|
|
2768
|
-
const hasTimeLimit = typeof budgetDetails.time_limit_ms === "number";
|
|
2769
|
-
const timeLimit = hasTimeLimit ? budgetDetails.time_limit_ms : Number.MAX_SAFE_INTEGER;
|
|
2770
|
-
const consumedTime = hasTimeLimit ? budgetDetails.settled_time_ms : 0;
|
|
2771
|
-
const hasCostLimit = typeof budgetDetails.cost_limit_usd === "number";
|
|
2772
|
-
const costLimit = hasCostLimit ? budgetDetails.cost_limit_usd : Number.MAX_VALUE;
|
|
2773
|
-
const consumedCost = hasCostLimit ? budgetDetails.settled_cost_usd : (budgetDetails.settled_cost_usd ?? 0);
|
|
2774
|
-
if (!Number.isSafeInteger(timeLimit) || timeLimit < 0 || !Number.isSafeInteger(consumedTime) || consumedTime < 0 ||
|
|
2775
|
-
!Number.isFinite(costLimit) || costLimit < 0 || typeof consumedCost !== "number" || !Number.isFinite(consumedCost) || consumedCost < 0) {
|
|
2776
|
-
return nonRescue("budget_exhausted");
|
|
2777
|
-
}
|
|
2778
|
-
if ((hasTimeLimit && consumedTime >= timeLimit) || (hasCostLimit && consumedCost >= costLimit)) {
|
|
2779
|
-
return nonRescue("budget_exhausted");
|
|
2780
|
-
}
|
|
2781
|
-
const nativeModels = await readHostModels(input.client);
|
|
2782
|
-
const target = nativeModels?.has(DEFAULT_TERMINAL_RESCUE_MODEL)
|
|
2783
|
-
? { model: DEFAULT_TERMINAL_RESCUE_MODEL, variant: null } : null;
|
|
2784
|
-
const terminalIdentity = { run_id: run.runID, unit_id: unitID, attempt_id: attempt.attemptID,
|
|
2785
|
-
predecessor_attempt_id: attempt.predecessorAttemptID ?? null, candidate_id: candidate.fingerprint,
|
|
2786
|
-
route_id: `${profile.id}:mission:${unitID}`, child_id: terminal.child, call_id: attempt.callID };
|
|
2787
|
-
const priorFailure = attempt.failure;
|
|
2788
|
-
const policy = proposeTerminalRescue({ prior_attempt: { identity: terminalIdentity, role: "implementation", recovery_kind: "normal_remediation",
|
|
2789
|
-
disposition: "failed", failure: priorFailure ? { category: priorFailure.category, code: priorFailure.code } : null },
|
|
2790
|
-
terminal_reconciliation: { current: terminalIdentity, observation: { identity: terminalIdentity, disposition: "failed" }, evidence: {
|
|
2791
|
-
terminal: "satisfied", tools_quiescent: "satisfied", artifact_window_closed: "satisfied", writer_released: "satisfied",
|
|
2792
|
-
gate_released: "satisfied", lease_released: "satisfied", worktree_released: "satisfied"
|
|
2793
|
-
} },
|
|
2794
|
-
accepted_base: { candidate_id: candidate.fingerprint, contract_id: run.acceptanceFingerprint, scope: [...unit.unit.write],
|
|
2795
|
-
acceptance: [...run.acceptance], validation: [...unit.unit.validation] }, available_target: target,
|
|
2796
|
-
explicit_override: (attempt.selectedModel !== undefined && attempt.selectedModel !== PREVIEW_WORKER_ROUTE.model) ||
|
|
2797
|
-
(attempt.observedModel !== undefined && attempt.observedModel !== PREVIEW_WORKER_ROUTE.model) ||
|
|
2798
|
-
(attempt.observedVariant !== undefined && attempt.observedVariant !== PREVIEW_WORKER_ROUTE.variant),
|
|
2799
|
-
unit_rescue_count: (mission.attempts ?? []).filter(item => item.runID === run.runID && item.unitID === unitID && item.kind === "astra_rescue").length,
|
|
2800
|
-
active_run_rescue_count: (mission.attempts ?? []).filter(item => item.runID === run.runID && item.kind === "astra_rescue").length,
|
|
2801
|
-
budget_limits: { counters: { recovery_actions: budget.max_units, probe_iterations: 0, model_attempts: budget.max_units },
|
|
2802
|
-
resources: { time_ms: timeLimit, cost_usd: costLimit } },
|
|
2803
|
-
budget_consumed: { counters: { recovery_actions: budget.consumed_units + budget.reserved_units, probe_iterations: 0,
|
|
2804
|
-
model_attempts: budget.consumed_units + budget.reserved_units },
|
|
2805
|
-
resources: { time_ms: consumedTime, cost_usd: consumedCost } },
|
|
2806
|
-
budget_request: { counters: { recovery_actions: 1, probe_iterations: 0, model_attempts: 1 },
|
|
2807
|
-
// Current Mission charges native time/cost through its cumulative goal ledger at normal dispatch settlement;
|
|
2808
|
-
// this policy reservation consumes one existing unit, not an invented parallel resource allowance.
|
|
2809
|
-
resources: { time_ms: 0, cost_usd: 0 } } });
|
|
2810
|
-
if (policy.status !== "proposed")
|
|
2811
|
-
return nonRescue(policy.reason);
|
|
2812
|
-
const rescueAttemptID = randomUUID();
|
|
2813
|
-
const prepared = await operators.prepareMissionTerminalRescue(root, run.runID, unitID, {
|
|
2814
|
-
attempt_id: rescueAttemptID, selected_model: policy.proposal.target.model,
|
|
2815
|
-
selected_variant: policy.proposal.target.variant,
|
|
2816
|
-
accepted_base: { candidate_id: policy.proposal.accepted_base_candidate_id, contract_id: policy.proposal.contract_id,
|
|
2817
|
-
scope: policy.proposal.scope, acceptance: policy.proposal.acceptance, validation: policy.proposal.validation },
|
|
2818
|
-
});
|
|
2819
|
-
control.enableUnits(root, 1);
|
|
2820
|
-
await missions.update(root, state => {
|
|
2821
|
-
state.rescue = { attemptID: rescueAttemptID, runID: run.runID, unitID,
|
|
2822
|
-
selectedModel: policy.proposal.target.model, selectedVariant: policy.proposal.target.variant, status: "prepared" };
|
|
2873
|
+
const next = await operators.next(root, context.sessionID);
|
|
2874
|
+
return JSON.stringify({ status: "prepared", rescue: { attempt_id: rescueAttemptID, selected_model: policy.proposal.target.model,
|
|
2875
|
+
selected_variant: policy.proposal.target.variant, accepted_base_candidate_id: policy.proposal.accepted_base_candidate_id,
|
|
2876
|
+
obligations: policy.proposal.obligations }, run_id: prepared.runID, unit_id: unitID,
|
|
2877
|
+
task: record(next) ? next.task : undefined, budget: await control.currentBudget(root) });
|
|
2823
2878
|
});
|
|
2824
|
-
const next = await operators.next(root, context.sessionID);
|
|
2825
|
-
return JSON.stringify({ status: "prepared", rescue: { attempt_id: rescueAttemptID, selected_model: policy.proposal.target.model,
|
|
2826
|
-
selected_variant: policy.proposal.target.variant, accepted_base_candidate_id: policy.proposal.accepted_base_candidate_id,
|
|
2827
|
-
obligations: policy.proposal.obligations }, run_id: prepared.runID, unit_id: unitID,
|
|
2828
|
-
task: record(next) ? next.task : undefined, budget: await control.currentBudget(root) });
|
|
2829
2879
|
} };
|
|
2830
2880
|
function declaredMissionExecution(mission, execution) {
|
|
2831
2881
|
const operation = mission.execution;
|
|
@@ -239,6 +239,14 @@ export interface RuntimeBridge {
|
|
|
239
239
|
ready: boolean;
|
|
240
240
|
reason?: string;
|
|
241
241
|
}>;
|
|
242
|
+
missionDirectTerminal(rootSessionID: string, dispatch: {
|
|
243
|
+
taskID: string;
|
|
244
|
+
callID: string;
|
|
245
|
+
actor: string;
|
|
246
|
+
}, writeScopes: readonly string[]): Promise<{
|
|
247
|
+
ready: boolean;
|
|
248
|
+
reason?: string;
|
|
249
|
+
}>;
|
|
242
250
|
restoreReviewerCorrectionChild(rootSessionID: string, childSessionID: string, callID: string, taskID: string): Promise<void>;
|
|
243
251
|
activateMissionWorker(rootSessionID: string, childSessionID: string, handoffPath: string, admission: MissionImplementationAdmission): Promise<void>;
|
|
244
252
|
activateDirectUnit(rootSessionID: string, actorSessionID: string, prompt: string, handoffPath: string): Promise<void>;
|