@caupulican/pi-adaptative 0.96.0 → 0.96.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/CHANGELOG.md +22 -0
- package/dist/core/agent-session.d.ts +3 -3
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +17 -6
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/delegation/sanitized-context-fork.d.ts.map +1 -1
- package/dist/core/delegation/sanitized-context-fork.js +2 -15
- package/dist/core/delegation/sanitized-context-fork.js.map +1 -1
- package/dist/core/delegation/worker-retry-policy.d.ts.map +1 -1
- package/dist/core/delegation/worker-retry-policy.js +12 -4
- package/dist/core/delegation/worker-retry-policy.js.map +1 -1
- package/dist/core/foreground-recovery-controller.d.ts +1 -0
- package/dist/core/foreground-recovery-controller.d.ts.map +1 -1
- package/dist/core/foreground-recovery-controller.js +30 -13
- package/dist/core/foreground-recovery-controller.js.map +1 -1
- package/dist/core/goal-loop-controller.d.ts +2 -2
- package/dist/core/goal-loop-controller.js +2 -2
- package/dist/core/goal-loop-controller.js.map +1 -1
- package/dist/core/goals/compact-goal-context.d.ts.map +1 -1
- package/dist/core/goals/compact-goal-context.js +12 -8
- package/dist/core/goals/compact-goal-context.js.map +1 -1
- package/dist/core/goals/goal-continuation-controller.d.ts +3 -3
- package/dist/core/goals/goal-continuation-controller.js +14 -15
- package/dist/core/goals/goal-continuation-controller.js.map +1 -1
- package/dist/core/goals/goal-continuation-defaults.d.ts +3 -3
- package/dist/core/goals/goal-continuation-defaults.js +3 -3
- package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
- package/dist/core/goals/goal-lifecycle.d.ts +2 -0
- package/dist/core/goals/goal-lifecycle.d.ts.map +1 -1
- package/dist/core/goals/goal-lifecycle.js +22 -0
- package/dist/core/goals/goal-lifecycle.js.map +1 -1
- package/dist/core/goals/goal-session-controller.d.ts +8 -2
- package/dist/core/goals/goal-session-controller.d.ts.map +1 -1
- package/dist/core/goals/goal-session-controller.js +22 -3
- package/dist/core/goals/goal-session-controller.js.map +1 -1
- package/dist/core/goals/goal-state.d.ts.map +1 -1
- package/dist/core/goals/goal-state.js +1 -7
- package/dist/core/goals/goal-state.js.map +1 -1
- package/dist/core/goals/goal-tool-core.js +1 -1
- package/dist/core/goals/goal-tool-core.js.map +1 -1
- package/dist/core/message-phase.d.ts +8 -0
- package/dist/core/message-phase.d.ts.map +1 -0
- package/dist/core/message-phase.js +48 -0
- package/dist/core/message-phase.js.map +1 -0
- package/dist/core/model-resolver.js +1 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/models/perf-profile.d.ts +1 -0
- package/dist/core/models/perf-profile.d.ts.map +1 -1
- package/dist/core/models/perf-profile.js +12 -3
- package/dist/core/models/perf-profile.js.map +1 -1
- package/dist/core/package-manager.d.ts +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +2 -21
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +5 -3
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +44 -12
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/goal.js +2 -2
- package/dist/core/tools/goal.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +5 -3
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +7 -2
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +2 -2
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-event-controller.js +9 -0
- package/dist/modes/interactive/interactive-event-controller.js.map +1 -1
- package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
- package/dist/modes/interactive/session-flow-commands.js +9 -2
- package/dist/modes/interactive/session-flow-commands.js.map +1 -1
- package/docs/sessions.md +1 -1
- package/docs/tool-repair.md +4 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -36,9 +36,9 @@ export declare function evaluateGoalContinuation(args: {
|
|
|
36
36
|
now?: string;
|
|
37
37
|
/**
|
|
38
38
|
* Maximum milliseconds a bound in-flight requirement (`Requirement.boundAt`) may wait before
|
|
39
|
-
* this
|
|
40
|
-
* `"waiting"` -- a worker that is alive-but-hung past its deadline must not wait
|
|
41
|
-
* takes effect when BOTH `now` and this are supplied;
|
|
39
|
+
* this returns `action:"continue"`/`reasonCode:"worker_wait_timeout"` for autonomous recovery
|
|
40
|
+
* instead of `"waiting"` -- a worker that is alive-but-hung past its deadline must not wait
|
|
41
|
+
* forever. Only takes effect when BOTH `now` and this are supplied; recovery fires only once EVERY
|
|
42
42
|
* bound-in-flight open requirement has individually passed `boundAt + maxWorkerWaitMs`, so a
|
|
43
43
|
* goal with a mix of fresh and stale bindings keeps waiting on the fresh one.
|
|
44
44
|
*/
|
|
@@ -54,18 +54,17 @@ export function evaluateGoalContinuation(args) {
|
|
|
54
54
|
message: "The goal is explicitly blocked.",
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
// subagent loop is stuck. Forcefully retire the goal to prevent infinite orchestrator looping.
|
|
57
|
+
// Repeated blockers are recovery evidence, not permission to abandon the goal. Force another
|
|
58
|
+
// approach while leaving genuine owner/approval boundaries available through explicit goal state.
|
|
60
59
|
const MAX_REQUIREMENT_BLOCKS = 3;
|
|
61
60
|
for (const reqId of blockedRequirementIds) {
|
|
62
61
|
const blockCount = state.events.filter((e) => e.type === "block_requirement" && e.id === reqId).length;
|
|
63
62
|
if (blockCount >= MAX_REQUIREMENT_BLOCKS) {
|
|
64
63
|
return {
|
|
65
64
|
...baseDecision,
|
|
66
|
-
action: "
|
|
65
|
+
action: "continue",
|
|
67
66
|
reasonCode: "stall_limit_reached",
|
|
68
|
-
message: `
|
|
67
|
+
message: `Requirement '${reqId}' has been blocked ${blockCount} times. Inspect the blocker evidence and use a distinct recovery approach; ask the owner only when the blocker is a verified owner/approval boundary.`,
|
|
69
68
|
};
|
|
70
69
|
}
|
|
71
70
|
}
|
|
@@ -97,9 +96,9 @@ export function evaluateGoalContinuation(args) {
|
|
|
97
96
|
if (blockedRequirementIds.length > 0) {
|
|
98
97
|
return {
|
|
99
98
|
...baseDecision,
|
|
100
|
-
action: "
|
|
99
|
+
action: "continue",
|
|
101
100
|
reasonCode: "blocked_requirements_present",
|
|
102
|
-
message: "All remaining legacy goal requirements are blocked.",
|
|
101
|
+
message: "All remaining legacy goal requirements are blocked. Verify each blocker, reopen recoverable work, and ask the owner only for a proven owner/approval boundary.",
|
|
103
102
|
};
|
|
104
103
|
}
|
|
105
104
|
if (state.requirements.length === 0) {
|
|
@@ -181,10 +180,10 @@ export function evaluateGoalContinuation(args) {
|
|
|
181
180
|
inFlightGoalLaneIds.has(requirement.boundLaneId))
|
|
182
181
|
: [];
|
|
183
182
|
if (boundInFlightRequirements.length > 0) {
|
|
184
|
-
// Never-hang backstop: a worker alive-but-hung past its deadline must
|
|
185
|
-
// instead of waiting forever. Only evaluated when
|
|
186
|
-
// a deadline;
|
|
187
|
-
// so one fresh binding keeps the goal legitimately waiting.
|
|
183
|
+
// Never-hang backstop: a worker alive-but-hung past its deadline must return control to the
|
|
184
|
+
// autonomous parent for inspection and recovery instead of waiting forever. Only evaluated when
|
|
185
|
+
// the caller supplies BOTH a clock reading and a deadline; recovers only once EVERY bound-in-flight
|
|
186
|
+
// requirement has individually timed out, so one fresh binding keeps the goal legitimately waiting.
|
|
188
187
|
if (args.now !== undefined && args.maxWorkerWaitMs !== undefined) {
|
|
189
188
|
const nowMs = Date.parse(args.now);
|
|
190
189
|
const maxWorkerWaitMs = args.maxWorkerWaitMs;
|
|
@@ -198,9 +197,9 @@ export function evaluateGoalContinuation(args) {
|
|
|
198
197
|
if (allTimedOut) {
|
|
199
198
|
return {
|
|
200
199
|
...baseDecision,
|
|
201
|
-
action: "
|
|
200
|
+
action: "continue",
|
|
202
201
|
reasonCode: "worker_wait_timeout",
|
|
203
|
-
message: `A dispatched worker has not completed within the maximum wait of ${maxWorkerWaitMs}ms
|
|
202
|
+
message: `A dispatched worker has not completed within the maximum wait of ${maxWorkerWaitMs}ms. Inspect its authoritative status and evidence, then recover it, reassign the requirement, or use another approach without waiting indefinitely.`,
|
|
204
203
|
};
|
|
205
204
|
}
|
|
206
205
|
}
|
|
@@ -222,9 +221,9 @@ export function evaluateGoalContinuation(args) {
|
|
|
222
221
|
if (args.settings.maxStallTurns > 0 && state.stallTurns >= args.settings.maxStallTurns) {
|
|
223
222
|
return {
|
|
224
223
|
...baseDecision,
|
|
225
|
-
action: "
|
|
224
|
+
action: "continue",
|
|
226
225
|
reasonCode: "stall_limit_reached",
|
|
227
|
-
message: `The goal has reached the
|
|
226
|
+
message: `The goal has reached the recovery threshold of ${args.settings.maxStallTurns} unchanged turns. Do not repeat the same operation: inspect failure evidence, use a different approach, tool, or route, and keep working unless a true owner/approval boundary is proven.`,
|
|
228
227
|
};
|
|
229
228
|
}
|
|
230
229
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"goal-continuation-controller.js","sourceRoot":"","sources":["../../../src/core/goals/goal-continuation-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { getUnprovenGoalRequirementIds } from \"./goal-acceptance.ts\";\nimport type { GoalState } from \"./goal-state.ts\";\n\nexport type GoalContinuationAction = \"continue\" | \"ask-user\" | \"finalize\" | \"stop\" | \"waiting\";\nexport type GoalContinuationReasonCode =\n\t| \"goal_active\"\n\t| \"goal_completed\"\n\t| \"goal_paused\"\n\t| \"goal_blocked\"\n\t| \"goal_usage_limited\"\n\t| \"goal_budget_limited\"\n\t| \"goal_cancelled\"\n\t| \"stall_limit_reached\"\n\t| \"goal_completion_required\"\n\t| \"acceptance_evidence_required\"\n\t| \"blocked_requirements_present\"\n\t| \"missing_goal_state\"\n\t| \"worker_in_flight\"\n\t| \"tool_task_in_flight\"\n\t| \"worker_wait_timeout\"\n\t| \"lane_sync_conflict\"\n\t| \"lane_sync_required\";\n\nexport interface GoalContinuationDecision {\n\taction: GoalContinuationAction;\n\treasonCode: GoalContinuationReasonCode;\n\tmessage: string;\n\tgoalId?: string;\n\tstallTurns?: number;\n\tmaxStallTurns?: number;\n\topenRequirementIds: readonly string[];\n\tblockedRequirementIds: readonly string[];\n\tsatisfiedRequirementIds: readonly string[];\n}\n\nexport interface GoalContinuationSettings {\n\tmaxStallTurns: number;\n}\n\nexport function evaluateGoalContinuation(args: {\n\tstate?: GoalState;\n\tsettings: GoalContinuationSettings;\n\t/**\n\t * LaneIds currently queued/running AND tagged with THIS goal's id (see `LaneRecord.goalId`).\n\t * When an open requirement is bound (`Requirement.boundLaneId`) to one of these lanes, the\n\t * goal is WAITING on that worker rather than stalled or ready for another pass: the loop must not\n\t * submit a hollow continuation prompt (which would waste a turn while no parent work can advance),\n\t * and the idle scheduler must not race a re-dispatch against the same open requirement. Optional\n\t * so every pre-existing (in-flight-unaware) caller keeps compiling and behaving unchanged.\n\t */\n\tinFlightGoalLaneIds?: ReadonlySet<string>;\n\t/**\n\t * Current time as an ISO string, paired with `maxWorkerWaitMs` to detect a bound in-flight\n\t * requirement that has hung past its deadline (see below). Optional so every pre-existing\n\t * caller that omits it keeps behaving byte-identically -- the goal waits indefinitely, exactly\n\t * as before this field existed.\n\t */\n\tnow?: string;\n\t/**\n\t * Maximum milliseconds a bound in-flight requirement (`Requirement.boundAt`) may wait before\n\t * this escalates to `action:\"ask-user\"`/`reasonCode:\"worker_wait_timeout\"` instead of\n\t * `\"waiting\"` -- a worker that is alive-but-hung past its deadline must not wait forever. Only\n\t * takes effect when BOTH `now` and this are supplied; escalation fires only once EVERY\n\t * bound-in-flight open requirement has individually passed `boundAt + maxWorkerWaitMs`, so a\n\t * goal with a mix of fresh and stale bindings keeps waiting on the fresh one.\n\t */\n\tmaxWorkerWaitMs?: number;\n\t/**\n\t * Bound lanes (`Requirement.boundLaneId` -- SAME id-space as `inFlightGoalLaneIds`, not the raw\n\t * worktree-sync `laneKey`) whose worktree-sync lane has a rebase stopped on conflicts\n\t * (`LaneFacts.rebaseInProgress`). The caller (`goal-runtime-snapshot.ts`) is responsible for\n\t * translating live per-worktree-lane status into this id-space by matching each status entry's\n\t * own `boundLaneId` against the requirement -- this function stays pure and never resolves a\n\t * worktree laneKey itself, exactly like `inFlightGoalLaneIds` never resolves a tmux job id.\n\t * Checked BEFORE the waiting branch (see `lane_sync_conflict` below): a stalled-but-conflicted\n\t * worker must get the resolve directive, not silently wait forever. Optional so every\n\t * pre-existing caller keeps compiling and behaving byte-identically when omitted or empty.\n\t */\n\tlaneSyncConflictLaneKeys?: ReadonlySet<string>;\n\t/**\n\t * Bound lanes (`Requirement.boundLaneId`, same id-space note as {@link laneSyncConflictLaneKeys})\n\t * whose worktree-sync lane is stale and must sync with current main before further work\n\t * (`sync_required`, i.e. NOT already covered by `laneSyncConflictLaneKeys` -- a lane with a\n\t * rebase in progress is reported as a conflict, never double-counted here). Checked BEFORE the\n\t * waiting branch, same precedence rationale as above. Optional so every pre-existing caller keeps\n\t * compiling and behaving byte-identically when omitted or empty.\n\t */\n\tsyncRequiredLaneKeys?: ReadonlySet<string>;\n\t/**\n\t * Background tool_task ids that are still running and cited by this goal's evidence or by\n\t * linked open task_steps. The loop must wait for those terminals the same way it waits on\n\t * a bound worker — a handoff stub is not completion.\n\t */\n\tinFlightToolTaskIds?: ReadonlySet<string>;\n}): GoalContinuationDecision {\n\tif (!args.state) {\n\t\treturn {\n\t\t\taction: \"ask-user\",\n\t\t\treasonCode: \"missing_goal_state\",\n\t\t\tmessage: \"No goal state is present.\",\n\t\t\topenRequirementIds: [],\n\t\t\tblockedRequirementIds: [],\n\t\t\tsatisfiedRequirementIds: [],\n\t\t};\n\t}\n\n\tconst state = args.state;\n\tconst openRequirementIds: string[] = [];\n\tconst blockedRequirementIds: string[] = [];\n\tconst satisfiedRequirementIds: string[] = [];\n\n\tfor (const req of state.requirements) {\n\t\tif (req.status === \"open\") openRequirementIds.push(req.id);\n\t\telse if (req.status === \"blocked\") blockedRequirementIds.push(req.id);\n\t\telse if (req.status === \"satisfied\") satisfiedRequirementIds.push(req.id);\n\t}\n\n\tconst baseDecision = {\n\t\tgoalId: state.goalId,\n\t\tstallTurns: state.stallTurns,\n\t\tmaxStallTurns: args.settings.maxStallTurns,\n\t\topenRequirementIds,\n\t\tblockedRequirementIds,\n\t\tsatisfiedRequirementIds,\n\t};\n\n\tif (state.status === \"completed\") {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"finalize\",\n\t\t\treasonCode: \"goal_completed\",\n\t\t\tmessage: \"The goal is marked as completed.\",\n\t\t};\n\t}\n\n\tif (state.status === \"paused\") {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"stop\",\n\t\t\treasonCode: \"goal_paused\",\n\t\t\tmessage: \"The goal is paused by the owner.\",\n\t\t};\n\t}\n\n\tif (state.status === \"blocked\") {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"ask-user\",\n\t\t\treasonCode: \"goal_blocked\",\n\t\t\tmessage: \"The goal is explicitly blocked.\",\n\t\t};\n\t}\n\n\t// Semantic Circuit Breaker: check if any requirement has been repeatedly blocked.\n\t// If a requirement has failed verification / been blocked 3 or more times, the\n\t// subagent loop is stuck. Forcefully retire the goal to prevent infinite orchestrator looping.\n\tconst MAX_REQUIREMENT_BLOCKS = 3;\n\tfor (const reqId of blockedRequirementIds) {\n\t\tconst blockCount = state.events.filter((e) => e.type === \"block_requirement\" && e.id === reqId).length;\n\n\t\tif (blockCount >= MAX_REQUIREMENT_BLOCKS) {\n\t\t\treturn {\n\t\t\t\t...baseDecision,\n\t\t\t\taction: \"stop\",\n\t\t\t\treasonCode: \"stall_limit_reached\",\n\t\t\t\tmessage: `Circuit Breaker: Requirement '${reqId}' has been blocked ${blockCount} times (e.g. repeated verification failures). The task is stuck in a loop and requires human intervention.`,\n\t\t\t};\n\t\t}\n\t}\n\n\tif (state.status === \"usage_limited\") {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"ask-user\",\n\t\t\treasonCode: \"goal_usage_limited\",\n\t\t\tmessage: \"The goal stopped after the active provider reached a usage limit.\",\n\t\t};\n\t}\n\n\tif (state.status === \"budget_limited\") {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"stop\",\n\t\t\treasonCode: \"goal_budget_limited\",\n\t\t\tmessage: \"The goal exhausted its configured budget.\",\n\t\t};\n\t}\n\n\tif (state.status === \"cancelled\") {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"stop\",\n\t\t\treasonCode: \"goal_cancelled\",\n\t\t\tmessage: \"The goal has been cancelled.\",\n\t\t};\n\t}\n\n\tif (openRequirementIds.length === 0) {\n\t\tif (blockedRequirementIds.length > 0) {\n\t\t\treturn {\n\t\t\t\t...baseDecision,\n\t\t\t\taction: \"ask-user\",\n\t\t\t\treasonCode: \"blocked_requirements_present\",\n\t\t\t\tmessage: \"All remaining legacy goal requirements are blocked.\",\n\t\t\t};\n\t\t}\n\t\tif (state.requirements.length === 0) {\n\t\t\treturn {\n\t\t\t\t...baseDecision,\n\t\t\t\taction: \"continue\",\n\t\t\t\treasonCode: \"goal_active\",\n\t\t\t\tmessage: \"The compact goal record is active.\",\n\t\t\t};\n\t\t}\n\t\tconst unprovenRequirementIds = getUnprovenGoalRequirementIds(state);\n\t\tif (unprovenRequirementIds.length > 0) {\n\t\t\treturn {\n\t\t\t\t...baseDecision,\n\t\t\t\taction: \"continue\",\n\t\t\t\treasonCode: \"acceptance_evidence_required\",\n\t\t\t\tmessage: `Requirement(s) ${unprovenRequirementIds.join(\", \")} still need trusted acceptance evidence.`,\n\t\t\t};\n\t\t}\n\t\tif (args.inFlightToolTaskIds && args.inFlightToolTaskIds.size > 0) {\n\t\t\treturn {\n\t\t\t\t...baseDecision,\n\t\t\t\taction: \"waiting\",\n\t\t\t\treasonCode: \"tool_task_in_flight\",\n\t\t\t\tmessage: `Background tool_task(s) ${[...args.inFlightToolTaskIds].join(\", \")} are still running; wait once via tool_task before completing.`,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"continue\",\n\t\t\treasonCode: \"goal_completion_required\",\n\t\t\tmessage: \"All requirements are proven. Mark the goal complete only after confirming no required work remains.\",\n\t\t};\n\t}\n\n\t// Worktree-sync directives take precedence over the \"waiting\" branch below: a worker whose bound\n\t// lane is conflicted or stale is NOT merely in-flight-and-quiet -- it needs an explicit directive\n\t// (resolve conflicts, or sync) delivered through the continuation prompt, and a stalled-but-stale\n\t// worker must never be left waiting indefinitely for a sync it was never told to run. Conflict is\n\t// checked first: a lane with a rebase already stopped on conflicts cannot usefully be told to\n\t// \"sync\" again (that lane's `sync_required` flag is never set while `rebaseInProgress` is true --\n\t// see `goal-runtime-snapshot.ts` -- so the two sets below are disjoint by construction, not by a\n\t// priority check here).\n\tconst laneSyncConflictLaneKeys = args.laneSyncConflictLaneKeys;\n\tconst conflictedRequirements = laneSyncConflictLaneKeys\n\t\t? state.requirements.filter(\n\t\t\t\t(requirement) =>\n\t\t\t\t\trequirement.status === \"open\" &&\n\t\t\t\t\trequirement.boundLaneId !== undefined &&\n\t\t\t\t\tlaneSyncConflictLaneKeys.has(requirement.boundLaneId),\n\t\t\t)\n\t\t: [];\n\tif (conflictedRequirements.length > 0) {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"continue\",\n\t\t\treasonCode: \"lane_sync_conflict\",\n\t\t\tmessage: `Requirement(s) ${conflictedRequirements.map((requirement) => requirement.id).join(\", \")} are bound to a worktree-sync lane with a rebase stopped on conflicts; resolve via worktree_sync action:\"continue\" (or \"abort_sync\") before this goal can progress further.`,\n\t\t};\n\t}\n\n\tconst syncRequiredLaneKeys = args.syncRequiredLaneKeys;\n\tconst syncRequiredRequirements = syncRequiredLaneKeys\n\t\t? state.requirements.filter(\n\t\t\t\t(requirement) =>\n\t\t\t\t\trequirement.status === \"open\" &&\n\t\t\t\t\trequirement.boundLaneId !== undefined &&\n\t\t\t\t\tsyncRequiredLaneKeys.has(requirement.boundLaneId),\n\t\t\t)\n\t\t: [];\n\tif (syncRequiredRequirements.length > 0) {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"continue\",\n\t\t\treasonCode: \"lane_sync_required\",\n\t\t\tmessage: `Requirement(s) ${syncRequiredRequirements.map((requirement) => requirement.id).join(\", \")} are bound to a worktree-sync lane that must rebase current main before further work; deliver worktree_sync action:\"sync\" to the bound worker, or run it directly for an idle lane.`,\n\t\t};\n\t}\n\n\t// A worker is dispatched (queued/running) against an open requirement this goal owns — wait\n\t// for it rather than submit a hollow pass or let the stall counter judge the goal unproductive.\n\t// Checked BEFORE the stall check so an in-flight worker always wins over an accumulated stall\n\t// count: the goal isn't stalled, it's actively being worked by something other than this loop.\n\tconst inFlightGoalLaneIds = args.inFlightGoalLaneIds;\n\tconst boundInFlightRequirements = inFlightGoalLaneIds\n\t\t? state.requirements.filter(\n\t\t\t\t(requirement) =>\n\t\t\t\t\trequirement.status === \"open\" &&\n\t\t\t\t\trequirement.boundLaneId !== undefined &&\n\t\t\t\t\tinFlightGoalLaneIds.has(requirement.boundLaneId),\n\t\t\t)\n\t\t: [];\n\n\tif (boundInFlightRequirements.length > 0) {\n\t\t// Never-hang backstop: a worker alive-but-hung past its deadline must escalate to the owner\n\t\t// instead of waiting forever. Only evaluated when the caller supplies BOTH a clock reading and\n\t\t// a deadline; escalates only once EVERY bound-in-flight requirement has individually timed out,\n\t\t// so one fresh binding keeps the goal legitimately waiting.\n\t\tif (args.now !== undefined && args.maxWorkerWaitMs !== undefined) {\n\t\t\tconst nowMs = Date.parse(args.now);\n\t\t\tconst maxWorkerWaitMs = args.maxWorkerWaitMs;\n\t\t\tconst allTimedOut =\n\t\t\t\tNumber.isFinite(nowMs) &&\n\t\t\t\tboundInFlightRequirements.every((requirement) => {\n\t\t\t\t\tif (requirement.boundAt === undefined) return false;\n\t\t\t\t\tconst boundAtMs = Date.parse(requirement.boundAt);\n\t\t\t\t\treturn Number.isFinite(boundAtMs) && boundAtMs + maxWorkerWaitMs <= nowMs;\n\t\t\t\t});\n\t\t\tif (allTimedOut) {\n\t\t\t\treturn {\n\t\t\t\t\t...baseDecision,\n\t\t\t\t\taction: \"ask-user\",\n\t\t\t\t\treasonCode: \"worker_wait_timeout\",\n\t\t\t\t\tmessage: `A dispatched worker has not completed within the maximum wait of ${maxWorkerWaitMs}ms; escalating to the owner instead of waiting indefinitely.`,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"waiting\",\n\t\t\treasonCode: \"worker_in_flight\",\n\t\t\tmessage: \"A worker is dispatched against an open requirement; waiting for it to finish before continuing.\",\n\t\t};\n\t}\n\n\tif (args.inFlightToolTaskIds && args.inFlightToolTaskIds.size > 0) {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"waiting\",\n\t\t\treasonCode: \"tool_task_in_flight\",\n\t\t\tmessage: `Background tool_task(s) ${[...args.inFlightToolTaskIds].join(\", \")} are still running; wait once via tool_task before continuing or completing.`,\n\t\t};\n\t}\n\n\tif (args.settings.maxStallTurns > 0 && state.stallTurns >= args.settings.maxStallTurns) {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"ask-user\",\n\t\t\treasonCode: \"stall_limit_reached\",\n\t\t\tmessage: `The goal has reached the maximum stall limit of ${args.settings.maxStallTurns} turns.`,\n\t\t};\n\t}\n\n\treturn {\n\t\t...baseDecision,\n\t\taction: \"continue\",\n\t\treasonCode: \"goal_active\",\n\t\tmessage: \"The goal is active and making progress.\",\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"goal-continuation-controller.js","sourceRoot":"","sources":["../../../src/core/goals/goal-continuation-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { getUnprovenGoalRequirementIds } from \"./goal-acceptance.ts\";\nimport type { GoalState } from \"./goal-state.ts\";\n\nexport type GoalContinuationAction = \"continue\" | \"ask-user\" | \"finalize\" | \"stop\" | \"waiting\";\nexport type GoalContinuationReasonCode =\n\t| \"goal_active\"\n\t| \"goal_completed\"\n\t| \"goal_paused\"\n\t| \"goal_blocked\"\n\t| \"goal_usage_limited\"\n\t| \"goal_budget_limited\"\n\t| \"goal_cancelled\"\n\t| \"stall_limit_reached\"\n\t| \"goal_completion_required\"\n\t| \"acceptance_evidence_required\"\n\t| \"blocked_requirements_present\"\n\t| \"missing_goal_state\"\n\t| \"worker_in_flight\"\n\t| \"tool_task_in_flight\"\n\t| \"worker_wait_timeout\"\n\t| \"lane_sync_conflict\"\n\t| \"lane_sync_required\";\n\nexport interface GoalContinuationDecision {\n\taction: GoalContinuationAction;\n\treasonCode: GoalContinuationReasonCode;\n\tmessage: string;\n\tgoalId?: string;\n\tstallTurns?: number;\n\tmaxStallTurns?: number;\n\topenRequirementIds: readonly string[];\n\tblockedRequirementIds: readonly string[];\n\tsatisfiedRequirementIds: readonly string[];\n}\n\nexport interface GoalContinuationSettings {\n\tmaxStallTurns: number;\n}\n\nexport function evaluateGoalContinuation(args: {\n\tstate?: GoalState;\n\tsettings: GoalContinuationSettings;\n\t/**\n\t * LaneIds currently queued/running AND tagged with THIS goal's id (see `LaneRecord.goalId`).\n\t * When an open requirement is bound (`Requirement.boundLaneId`) to one of these lanes, the\n\t * goal is WAITING on that worker rather than stalled or ready for another pass: the loop must not\n\t * submit a hollow continuation prompt (which would waste a turn while no parent work can advance),\n\t * and the idle scheduler must not race a re-dispatch against the same open requirement. Optional\n\t * so every pre-existing (in-flight-unaware) caller keeps compiling and behaving unchanged.\n\t */\n\tinFlightGoalLaneIds?: ReadonlySet<string>;\n\t/**\n\t * Current time as an ISO string, paired with `maxWorkerWaitMs` to detect a bound in-flight\n\t * requirement that has hung past its deadline (see below). Optional so every pre-existing\n\t * caller that omits it keeps behaving byte-identically -- the goal waits indefinitely, exactly\n\t * as before this field existed.\n\t */\n\tnow?: string;\n\t/**\n\t * Maximum milliseconds a bound in-flight requirement (`Requirement.boundAt`) may wait before\n\t * this returns `action:\"continue\"`/`reasonCode:\"worker_wait_timeout\"` for autonomous recovery\n\t * instead of `\"waiting\"` -- a worker that is alive-but-hung past its deadline must not wait\n\t * forever. Only takes effect when BOTH `now` and this are supplied; recovery fires only once EVERY\n\t * bound-in-flight open requirement has individually passed `boundAt + maxWorkerWaitMs`, so a\n\t * goal with a mix of fresh and stale bindings keeps waiting on the fresh one.\n\t */\n\tmaxWorkerWaitMs?: number;\n\t/**\n\t * Bound lanes (`Requirement.boundLaneId` -- SAME id-space as `inFlightGoalLaneIds`, not the raw\n\t * worktree-sync `laneKey`) whose worktree-sync lane has a rebase stopped on conflicts\n\t * (`LaneFacts.rebaseInProgress`). The caller (`goal-runtime-snapshot.ts`) is responsible for\n\t * translating live per-worktree-lane status into this id-space by matching each status entry's\n\t * own `boundLaneId` against the requirement -- this function stays pure and never resolves a\n\t * worktree laneKey itself, exactly like `inFlightGoalLaneIds` never resolves a tmux job id.\n\t * Checked BEFORE the waiting branch (see `lane_sync_conflict` below): a stalled-but-conflicted\n\t * worker must get the resolve directive, not silently wait forever. Optional so every\n\t * pre-existing caller keeps compiling and behaving byte-identically when omitted or empty.\n\t */\n\tlaneSyncConflictLaneKeys?: ReadonlySet<string>;\n\t/**\n\t * Bound lanes (`Requirement.boundLaneId`, same id-space note as {@link laneSyncConflictLaneKeys})\n\t * whose worktree-sync lane is stale and must sync with current main before further work\n\t * (`sync_required`, i.e. NOT already covered by `laneSyncConflictLaneKeys` -- a lane with a\n\t * rebase in progress is reported as a conflict, never double-counted here). Checked BEFORE the\n\t * waiting branch, same precedence rationale as above. Optional so every pre-existing caller keeps\n\t * compiling and behaving byte-identically when omitted or empty.\n\t */\n\tsyncRequiredLaneKeys?: ReadonlySet<string>;\n\t/**\n\t * Background tool_task ids that are still running and cited by this goal's evidence or by\n\t * linked open task_steps. The loop must wait for those terminals the same way it waits on\n\t * a bound worker — a handoff stub is not completion.\n\t */\n\tinFlightToolTaskIds?: ReadonlySet<string>;\n}): GoalContinuationDecision {\n\tif (!args.state) {\n\t\treturn {\n\t\t\taction: \"ask-user\",\n\t\t\treasonCode: \"missing_goal_state\",\n\t\t\tmessage: \"No goal state is present.\",\n\t\t\topenRequirementIds: [],\n\t\t\tblockedRequirementIds: [],\n\t\t\tsatisfiedRequirementIds: [],\n\t\t};\n\t}\n\n\tconst state = args.state;\n\tconst openRequirementIds: string[] = [];\n\tconst blockedRequirementIds: string[] = [];\n\tconst satisfiedRequirementIds: string[] = [];\n\n\tfor (const req of state.requirements) {\n\t\tif (req.status === \"open\") openRequirementIds.push(req.id);\n\t\telse if (req.status === \"blocked\") blockedRequirementIds.push(req.id);\n\t\telse if (req.status === \"satisfied\") satisfiedRequirementIds.push(req.id);\n\t}\n\n\tconst baseDecision = {\n\t\tgoalId: state.goalId,\n\t\tstallTurns: state.stallTurns,\n\t\tmaxStallTurns: args.settings.maxStallTurns,\n\t\topenRequirementIds,\n\t\tblockedRequirementIds,\n\t\tsatisfiedRequirementIds,\n\t};\n\n\tif (state.status === \"completed\") {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"finalize\",\n\t\t\treasonCode: \"goal_completed\",\n\t\t\tmessage: \"The goal is marked as completed.\",\n\t\t};\n\t}\n\n\tif (state.status === \"paused\") {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"stop\",\n\t\t\treasonCode: \"goal_paused\",\n\t\t\tmessage: \"The goal is paused by the owner.\",\n\t\t};\n\t}\n\n\tif (state.status === \"blocked\") {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"ask-user\",\n\t\t\treasonCode: \"goal_blocked\",\n\t\t\tmessage: \"The goal is explicitly blocked.\",\n\t\t};\n\t}\n\n\t// Repeated blockers are recovery evidence, not permission to abandon the goal. Force another\n\t// approach while leaving genuine owner/approval boundaries available through explicit goal state.\n\tconst MAX_REQUIREMENT_BLOCKS = 3;\n\tfor (const reqId of blockedRequirementIds) {\n\t\tconst blockCount = state.events.filter((e) => e.type === \"block_requirement\" && e.id === reqId).length;\n\n\t\tif (blockCount >= MAX_REQUIREMENT_BLOCKS) {\n\t\t\treturn {\n\t\t\t\t...baseDecision,\n\t\t\t\taction: \"continue\",\n\t\t\t\treasonCode: \"stall_limit_reached\",\n\t\t\t\tmessage: `Requirement '${reqId}' has been blocked ${blockCount} times. Inspect the blocker evidence and use a distinct recovery approach; ask the owner only when the blocker is a verified owner/approval boundary.`,\n\t\t\t};\n\t\t}\n\t}\n\n\tif (state.status === \"usage_limited\") {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"ask-user\",\n\t\t\treasonCode: \"goal_usage_limited\",\n\t\t\tmessage: \"The goal stopped after the active provider reached a usage limit.\",\n\t\t};\n\t}\n\n\tif (state.status === \"budget_limited\") {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"stop\",\n\t\t\treasonCode: \"goal_budget_limited\",\n\t\t\tmessage: \"The goal exhausted its configured budget.\",\n\t\t};\n\t}\n\n\tif (state.status === \"cancelled\") {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"stop\",\n\t\t\treasonCode: \"goal_cancelled\",\n\t\t\tmessage: \"The goal has been cancelled.\",\n\t\t};\n\t}\n\n\tif (openRequirementIds.length === 0) {\n\t\tif (blockedRequirementIds.length > 0) {\n\t\t\treturn {\n\t\t\t\t...baseDecision,\n\t\t\t\taction: \"continue\",\n\t\t\t\treasonCode: \"blocked_requirements_present\",\n\t\t\t\tmessage:\n\t\t\t\t\t\"All remaining legacy goal requirements are blocked. Verify each blocker, reopen recoverable work, and ask the owner only for a proven owner/approval boundary.\",\n\t\t\t};\n\t\t}\n\t\tif (state.requirements.length === 0) {\n\t\t\treturn {\n\t\t\t\t...baseDecision,\n\t\t\t\taction: \"continue\",\n\t\t\t\treasonCode: \"goal_active\",\n\t\t\t\tmessage: \"The compact goal record is active.\",\n\t\t\t};\n\t\t}\n\t\tconst unprovenRequirementIds = getUnprovenGoalRequirementIds(state);\n\t\tif (unprovenRequirementIds.length > 0) {\n\t\t\treturn {\n\t\t\t\t...baseDecision,\n\t\t\t\taction: \"continue\",\n\t\t\t\treasonCode: \"acceptance_evidence_required\",\n\t\t\t\tmessage: `Requirement(s) ${unprovenRequirementIds.join(\", \")} still need trusted acceptance evidence.`,\n\t\t\t};\n\t\t}\n\t\tif (args.inFlightToolTaskIds && args.inFlightToolTaskIds.size > 0) {\n\t\t\treturn {\n\t\t\t\t...baseDecision,\n\t\t\t\taction: \"waiting\",\n\t\t\t\treasonCode: \"tool_task_in_flight\",\n\t\t\t\tmessage: `Background tool_task(s) ${[...args.inFlightToolTaskIds].join(\", \")} are still running; wait once via tool_task before completing.`,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"continue\",\n\t\t\treasonCode: \"goal_completion_required\",\n\t\t\tmessage: \"All requirements are proven. Mark the goal complete only after confirming no required work remains.\",\n\t\t};\n\t}\n\n\t// Worktree-sync directives take precedence over the \"waiting\" branch below: a worker whose bound\n\t// lane is conflicted or stale is NOT merely in-flight-and-quiet -- it needs an explicit directive\n\t// (resolve conflicts, or sync) delivered through the continuation prompt, and a stalled-but-stale\n\t// worker must never be left waiting indefinitely for a sync it was never told to run. Conflict is\n\t// checked first: a lane with a rebase already stopped on conflicts cannot usefully be told to\n\t// \"sync\" again (that lane's `sync_required` flag is never set while `rebaseInProgress` is true --\n\t// see `goal-runtime-snapshot.ts` -- so the two sets below are disjoint by construction, not by a\n\t// priority check here).\n\tconst laneSyncConflictLaneKeys = args.laneSyncConflictLaneKeys;\n\tconst conflictedRequirements = laneSyncConflictLaneKeys\n\t\t? state.requirements.filter(\n\t\t\t\t(requirement) =>\n\t\t\t\t\trequirement.status === \"open\" &&\n\t\t\t\t\trequirement.boundLaneId !== undefined &&\n\t\t\t\t\tlaneSyncConflictLaneKeys.has(requirement.boundLaneId),\n\t\t\t)\n\t\t: [];\n\tif (conflictedRequirements.length > 0) {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"continue\",\n\t\t\treasonCode: \"lane_sync_conflict\",\n\t\t\tmessage: `Requirement(s) ${conflictedRequirements.map((requirement) => requirement.id).join(\", \")} are bound to a worktree-sync lane with a rebase stopped on conflicts; resolve via worktree_sync action:\"continue\" (or \"abort_sync\") before this goal can progress further.`,\n\t\t};\n\t}\n\n\tconst syncRequiredLaneKeys = args.syncRequiredLaneKeys;\n\tconst syncRequiredRequirements = syncRequiredLaneKeys\n\t\t? state.requirements.filter(\n\t\t\t\t(requirement) =>\n\t\t\t\t\trequirement.status === \"open\" &&\n\t\t\t\t\trequirement.boundLaneId !== undefined &&\n\t\t\t\t\tsyncRequiredLaneKeys.has(requirement.boundLaneId),\n\t\t\t)\n\t\t: [];\n\tif (syncRequiredRequirements.length > 0) {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"continue\",\n\t\t\treasonCode: \"lane_sync_required\",\n\t\t\tmessage: `Requirement(s) ${syncRequiredRequirements.map((requirement) => requirement.id).join(\", \")} are bound to a worktree-sync lane that must rebase current main before further work; deliver worktree_sync action:\"sync\" to the bound worker, or run it directly for an idle lane.`,\n\t\t};\n\t}\n\n\t// A worker is dispatched (queued/running) against an open requirement this goal owns — wait\n\t// for it rather than submit a hollow pass or let the stall counter judge the goal unproductive.\n\t// Checked BEFORE the stall check so an in-flight worker always wins over an accumulated stall\n\t// count: the goal isn't stalled, it's actively being worked by something other than this loop.\n\tconst inFlightGoalLaneIds = args.inFlightGoalLaneIds;\n\tconst boundInFlightRequirements = inFlightGoalLaneIds\n\t\t? state.requirements.filter(\n\t\t\t\t(requirement) =>\n\t\t\t\t\trequirement.status === \"open\" &&\n\t\t\t\t\trequirement.boundLaneId !== undefined &&\n\t\t\t\t\tinFlightGoalLaneIds.has(requirement.boundLaneId),\n\t\t\t)\n\t\t: [];\n\n\tif (boundInFlightRequirements.length > 0) {\n\t\t// Never-hang backstop: a worker alive-but-hung past its deadline must return control to the\n\t\t// autonomous parent for inspection and recovery instead of waiting forever. Only evaluated when\n\t\t// the caller supplies BOTH a clock reading and a deadline; recovers only once EVERY bound-in-flight\n\t\t// requirement has individually timed out, so one fresh binding keeps the goal legitimately waiting.\n\t\tif (args.now !== undefined && args.maxWorkerWaitMs !== undefined) {\n\t\t\tconst nowMs = Date.parse(args.now);\n\t\t\tconst maxWorkerWaitMs = args.maxWorkerWaitMs;\n\t\t\tconst allTimedOut =\n\t\t\t\tNumber.isFinite(nowMs) &&\n\t\t\t\tboundInFlightRequirements.every((requirement) => {\n\t\t\t\t\tif (requirement.boundAt === undefined) return false;\n\t\t\t\t\tconst boundAtMs = Date.parse(requirement.boundAt);\n\t\t\t\t\treturn Number.isFinite(boundAtMs) && boundAtMs + maxWorkerWaitMs <= nowMs;\n\t\t\t\t});\n\t\t\tif (allTimedOut) {\n\t\t\t\treturn {\n\t\t\t\t\t...baseDecision,\n\t\t\t\t\taction: \"continue\",\n\t\t\t\t\treasonCode: \"worker_wait_timeout\",\n\t\t\t\t\tmessage: `A dispatched worker has not completed within the maximum wait of ${maxWorkerWaitMs}ms. Inspect its authoritative status and evidence, then recover it, reassign the requirement, or use another approach without waiting indefinitely.`,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"waiting\",\n\t\t\treasonCode: \"worker_in_flight\",\n\t\t\tmessage: \"A worker is dispatched against an open requirement; waiting for it to finish before continuing.\",\n\t\t};\n\t}\n\n\tif (args.inFlightToolTaskIds && args.inFlightToolTaskIds.size > 0) {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"waiting\",\n\t\t\treasonCode: \"tool_task_in_flight\",\n\t\t\tmessage: `Background tool_task(s) ${[...args.inFlightToolTaskIds].join(\", \")} are still running; wait once via tool_task before continuing or completing.`,\n\t\t};\n\t}\n\n\tif (args.settings.maxStallTurns > 0 && state.stallTurns >= args.settings.maxStallTurns) {\n\t\treturn {\n\t\t\t...baseDecision,\n\t\t\taction: \"continue\",\n\t\t\treasonCode: \"stall_limit_reached\",\n\t\t\tmessage: `The goal has reached the recovery threshold of ${args.settings.maxStallTurns} unchanged turns. Do not repeat the same operation: inspect failure evidence, use a different approach, tool, or route, and keep working unless a true owner/approval boundary is proven.`,\n\t\t};\n\t}\n\n\treturn {\n\t\t...baseDecision,\n\t\taction: \"continue\",\n\t\treasonCode: \"goal_active\",\n\t\tmessage: \"The goal is active and making progress.\",\n\t};\n}\n"]}
|
|
@@ -12,13 +12,13 @@ export declare const MAX_GOAL_AUTO_CONTINUE_DELAY_MS = 60000;
|
|
|
12
12
|
/**
|
|
13
13
|
* Never-hang backstop for a bound-in-flight worker (`evaluateGoalContinuation`'s
|
|
14
14
|
* `worker_wait_timeout` reasonCode): the maximum time a goal waits on a dispatched worker
|
|
15
|
-
* (`Requirement.boundAt` + this) before
|
|
16
|
-
* worker that is alive-but-hung past its deadline must not silently stall the goal loop.
|
|
15
|
+
* (`Requirement.boundAt` + this) before returning control to autonomous parent recovery instead of
|
|
16
|
+
* waiting forever. A worker that is alive-but-hung past its deadline must not silently stall the goal loop.
|
|
17
17
|
*
|
|
18
18
|
* Deliberately generous relative to the tmux worker runtime's own default session deadline
|
|
19
19
|
* (1200s / 20min, `tmux-agent-manager`'s `DEFAULT_DEADLINE_SECONDS`): 60 minutes gives a
|
|
20
20
|
* legitimately slow worker comfortable headroom above that deadline (plus the reconcile/orphan
|
|
21
|
-
* detection that runs on top of it) before the goal loop
|
|
21
|
+
* detection that runs on top of it) before the goal loop requires inspection and a different approach.
|
|
22
22
|
*/
|
|
23
23
|
export declare const DEFAULT_GOAL_WORKER_WAIT_MS = 3600000;
|
|
24
24
|
//# sourceMappingURL=goal-continuation-defaults.d.ts.map
|
|
@@ -12,13 +12,13 @@ export const MAX_GOAL_AUTO_CONTINUE_DELAY_MS = 60_000;
|
|
|
12
12
|
/**
|
|
13
13
|
* Never-hang backstop for a bound-in-flight worker (`evaluateGoalContinuation`'s
|
|
14
14
|
* `worker_wait_timeout` reasonCode): the maximum time a goal waits on a dispatched worker
|
|
15
|
-
* (`Requirement.boundAt` + this) before
|
|
16
|
-
* worker that is alive-but-hung past its deadline must not silently stall the goal loop.
|
|
15
|
+
* (`Requirement.boundAt` + this) before returning control to autonomous parent recovery instead of
|
|
16
|
+
* waiting forever. A worker that is alive-but-hung past its deadline must not silently stall the goal loop.
|
|
17
17
|
*
|
|
18
18
|
* Deliberately generous relative to the tmux worker runtime's own default session deadline
|
|
19
19
|
* (1200s / 20min, `tmux-agent-manager`'s `DEFAULT_DEADLINE_SECONDS`): 60 minutes gives a
|
|
20
20
|
* legitimately slow worker comfortable headroom above that deadline (plus the reconcile/orphan
|
|
21
|
-
* detection that runs on top of it) before the goal loop
|
|
21
|
+
* detection that runs on top of it) before the goal loop requires inspection and a different approach.
|
|
22
22
|
*/
|
|
23
23
|
export const DEFAULT_GOAL_WORKER_WAIT_MS = 3_600_000; // 60 minutes
|
|
24
24
|
//# sourceMappingURL=goal-continuation-defaults.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"goal-continuation-defaults.js","sourceRoot":"","sources":["../../../src/core/goals/goal-continuation-defaults.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,CAAC;AACjD,MAAM,CAAC,MAAM,qCAAqC,GAAG,EAAE,CAAC;AACxD,MAAM,CAAC,MAAM,4CAA4C,GAAG,CAAC,CAAC;AAC9D,MAAM,CAAC,MAAM,0BAA0B,GAAG,IAAI,CAAC;AAC/C,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,CAAC;AAErD,qGAAqG;AACrG,MAAM,CAAC,MAAM,2BAA2B,GAAG,MAAM,CAAC,gBAAgB,CAAC;AACnE,MAAM,CAAC,MAAM,iCAAiC,GAAG,GAAG,CAAC;AACrD,MAAM,CAAC,MAAM,wCAAwC,GAAG,EAAE,GAAG,EAAE,CAAC;AAChE,MAAM,CAAC,MAAM,+BAA+B,GAAG,MAAM,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,SAAS,CAAC,CAAC,aAAa","sourcesContent":["/** 0 means unbounded. Codex-style goals continue until a real terminal condition by default. */\nexport const DEFAULT_GOAL_CONTINUE_MAX_TURNS = 0;\nexport const DEFAULT_GOAL_CONTINUE_MAX_STALL_TURNS = 20;\nexport const DEFAULT_GOAL_CONTINUE_MAX_WALL_CLOCK_MINUTES = 0;\nexport const DEFAULT_GOAL_AUTO_CONTINUE = true;\nexport const DEFAULT_GOAL_AUTO_CONTINUE_DELAY_MS = 0;\n\n/** User-supplied turn limits are validated as safe integers, not silently clamped by the harness. */\nexport const MAX_GOAL_CONTINUE_MAX_TURNS = Number.MAX_SAFE_INTEGER;\nexport const MAX_GOAL_CONTINUE_MAX_STALL_TURNS = 100;\nexport const MAX_GOAL_CONTINUE_MAX_WALL_CLOCK_MINUTES = 24 * 60;\nexport const MAX_GOAL_AUTO_CONTINUE_DELAY_MS = 60_000;\n\n/**\n * Never-hang backstop for a bound-in-flight worker (`evaluateGoalContinuation`'s\n * `worker_wait_timeout` reasonCode): the maximum time a goal waits on a dispatched worker\n * (`Requirement.boundAt` + this) before
|
|
1
|
+
{"version":3,"file":"goal-continuation-defaults.js","sourceRoot":"","sources":["../../../src/core/goals/goal-continuation-defaults.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,CAAC;AACjD,MAAM,CAAC,MAAM,qCAAqC,GAAG,EAAE,CAAC;AACxD,MAAM,CAAC,MAAM,4CAA4C,GAAG,CAAC,CAAC;AAC9D,MAAM,CAAC,MAAM,0BAA0B,GAAG,IAAI,CAAC;AAC/C,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,CAAC;AAErD,qGAAqG;AACrG,MAAM,CAAC,MAAM,2BAA2B,GAAG,MAAM,CAAC,gBAAgB,CAAC;AACnE,MAAM,CAAC,MAAM,iCAAiC,GAAG,GAAG,CAAC;AACrD,MAAM,CAAC,MAAM,wCAAwC,GAAG,EAAE,GAAG,EAAE,CAAC;AAChE,MAAM,CAAC,MAAM,+BAA+B,GAAG,MAAM,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,SAAS,CAAC,CAAC,aAAa","sourcesContent":["/** 0 means unbounded. Codex-style goals continue until a real terminal condition by default. */\nexport const DEFAULT_GOAL_CONTINUE_MAX_TURNS = 0;\nexport const DEFAULT_GOAL_CONTINUE_MAX_STALL_TURNS = 20;\nexport const DEFAULT_GOAL_CONTINUE_MAX_WALL_CLOCK_MINUTES = 0;\nexport const DEFAULT_GOAL_AUTO_CONTINUE = true;\nexport const DEFAULT_GOAL_AUTO_CONTINUE_DELAY_MS = 0;\n\n/** User-supplied turn limits are validated as safe integers, not silently clamped by the harness. */\nexport const MAX_GOAL_CONTINUE_MAX_TURNS = Number.MAX_SAFE_INTEGER;\nexport const MAX_GOAL_CONTINUE_MAX_STALL_TURNS = 100;\nexport const MAX_GOAL_CONTINUE_MAX_WALL_CLOCK_MINUTES = 24 * 60;\nexport const MAX_GOAL_AUTO_CONTINUE_DELAY_MS = 60_000;\n\n/**\n * Never-hang backstop for a bound-in-flight worker (`evaluateGoalContinuation`'s\n * `worker_wait_timeout` reasonCode): the maximum time a goal waits on a dispatched worker\n * (`Requirement.boundAt` + this) before returning control to autonomous parent recovery instead of\n * waiting forever. A worker that is alive-but-hung past its deadline must not silently stall the goal loop.\n *\n * Deliberately generous relative to the tmux worker runtime's own default session deadline\n * (1200s / 20min, `tmux-agent-manager`'s `DEFAULT_DEADLINE_SECONDS`): 60 minutes gives a\n * legitimately slow worker comfortable headroom above that deadline (plus the reconcile/orphan\n * detection that runs on top of it) before the goal loop requires inspection and a different approach.\n */\nexport const DEFAULT_GOAL_WORKER_WAIT_MS = 3_600_000; // 60 minutes\n"]}
|
|
@@ -5,6 +5,8 @@ export interface GoalStateRevision {
|
|
|
5
5
|
revision: number;
|
|
6
6
|
}
|
|
7
7
|
export declare function getGoalStateRevision(state: GoalState): GoalStateRevision;
|
|
8
|
+
/** True only when a bounded runaway/provider-turn guard caused the block, not owner/model/terminal intent. */
|
|
9
|
+
export declare function isSystemBlockedGoal(state: GoalState | undefined): boolean;
|
|
8
10
|
/** Minimal durable seam shared by CLI, tools, and in-process session restoration. */
|
|
9
11
|
export interface PersistedGoalStateHost {
|
|
10
12
|
getGoalStateSnapshot(): GoalState | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"goal-lifecycle.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,SAAS,EAKd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAmB,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAErG,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,GAAG,iBAAiB,CAExE;AAED,qFAAqF;AACrF,MAAM,WAAW,sBAAsB;IACtC,oBAAoB,IAAI,SAAS,GAAG,SAAS,CAAC;IAC9C,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAAC;IAC9E,sBAAsB,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CAC/D;AAgBD,wBAAgB,SAAS,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAMvF;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CASxF;AAED,wBAAgB,QAAQ,CACvB,OAAO,EAAE,SAAS,GAAG,SAAS,EAC9B,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,EAChD,GAAG,EAAE,MAAM,GACT,gBAAgB,CAiBlB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAMxF;AAED,yFAAyF;AACzF,wBAAgB,WAAW,CAC1B,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,EAChE,GAAG,EAAE,MAAM,GACT,gBAAgB,CAElB;AAED,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,SAAS,GAAG,SAAS,EAC9B,IAAI,EAAE;IAAE,MAAM,EAAE,SAAS,GAAG,eAAe,GAAG,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAChF,GAAG,EAAE,MAAM,GACT,gBAAgB,CAQlB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,sBAAsB,EAAE,GAAG,SAA2B,GAAG,gBAAgB,CAGjH;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,sBAAsB,EAAE,GAAG,SAA2B,GAAG,gBAAgB,CAGlH;AAED,wBAAgB,iBAAiB,CAChC,IAAI,EAAE,sBAAsB,EAC5B,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,EAChD,GAAG,SAA2B,GAC5B,gBAAgB,CAGlB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,sBAAsB,EAAE,GAAG,SAA2B,GAAG,gBAAgB,CAGlH;AAED,MAAM,MAAM,wBAAwB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,iBAAiB,CAAC;AAE1F,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,sBAAsB,EAC5B,GAAG,SAA2B,GAC5B,wBAAwB,CAM1B"}
|
|
1
|
+
{"version":3,"file":"goal-lifecycle.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,SAAS,EAKd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAmB,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAErG,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,GAAG,iBAAiB,CAExE;AAID,8GAA8G;AAC9G,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAsBzE;AAED,qFAAqF;AACrF,MAAM,WAAW,sBAAsB;IACtC,oBAAoB,IAAI,SAAS,GAAG,SAAS,CAAC;IAC9C,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAAC;IAC9E,sBAAsB,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CAC/D;AAgBD,wBAAgB,SAAS,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAMvF;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CASxF;AAED,wBAAgB,QAAQ,CACvB,OAAO,EAAE,SAAS,GAAG,SAAS,EAC9B,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,EAChD,GAAG,EAAE,MAAM,GACT,gBAAgB,CAiBlB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAMxF;AAED,yFAAyF;AACzF,wBAAgB,WAAW,CAC1B,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,EAChE,GAAG,EAAE,MAAM,GACT,gBAAgB,CAElB;AAED,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,SAAS,GAAG,SAAS,EAC9B,IAAI,EAAE;IAAE,MAAM,EAAE,SAAS,GAAG,eAAe,GAAG,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAChF,GAAG,EAAE,MAAM,GACT,gBAAgB,CAQlB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,sBAAsB,EAAE,GAAG,SAA2B,GAAG,gBAAgB,CAGjH;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,sBAAsB,EAAE,GAAG,SAA2B,GAAG,gBAAgB,CAGlH;AAED,wBAAgB,iBAAiB,CAChC,IAAI,EAAE,sBAAsB,EAC5B,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,EAChD,GAAG,SAA2B,GAC5B,gBAAgB,CAGlB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,sBAAsB,EAAE,GAAG,SAA2B,GAAG,gBAAgB,CAGlH;AAED,MAAM,MAAM,wBAAwB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,iBAAiB,CAAC;AAE1F,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,sBAAsB,EAC5B,GAAG,SAA2B,GAC5B,wBAAwB,CAM1B"}
|
|
@@ -3,6 +3,28 @@ import { applyGoalAction } from "./goal-tool-core.js";
|
|
|
3
3
|
export function getGoalStateRevision(state) {
|
|
4
4
|
return { goalId: state.goalId, revision: state.revision ?? 0 };
|
|
5
5
|
}
|
|
6
|
+
const AUTO_RESUMABLE_SYSTEM_STOP_REASON_PREFIXES = ["runaway_tool_loop:", "provider_turn_limit:"];
|
|
7
|
+
/** True only when a bounded runaway/provider-turn guard caused the block, not owner/model/terminal intent. */
|
|
8
|
+
export function isSystemBlockedGoal(state) {
|
|
9
|
+
if (state?.status !== "blocked")
|
|
10
|
+
return false;
|
|
11
|
+
for (let index = state.events.length - 1; index >= 0; index--) {
|
|
12
|
+
const event = state.events[index];
|
|
13
|
+
if (event?.type === "system_stop_goal") {
|
|
14
|
+
return (event.status === "blocked" &&
|
|
15
|
+
AUTO_RESUMABLE_SYSTEM_STOP_REASON_PREFIXES.some((prefix) => event.reason.startsWith(prefix)));
|
|
16
|
+
}
|
|
17
|
+
if (event?.type === "block_goal" ||
|
|
18
|
+
event?.type === "pause_goal" ||
|
|
19
|
+
event?.type === "resume_goal" ||
|
|
20
|
+
event?.type === "complete_goal" ||
|
|
21
|
+
event?.type === "complete_goal_manually" ||
|
|
22
|
+
event?.type === "cancel_goal") {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
6
28
|
function missingGoal(action) {
|
|
7
29
|
return { ok: false, error: `No goal exists to ${action}.` };
|
|
8
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"goal-lifecycle.js","sourceRoot":"","sources":["../../../src/core/goals/goal-lifecycle.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tapplyGoalEvent,\n\ttype GoalState,\n\tisGoalExecutionActive,\n\tisGoalResumableStatus,\n\tisGoalUnfinishedStatus,\n\tMAX_GOAL_OBJECTIVE_LENGTH,\n} from \"./goal-state.ts\";\nimport { applyGoalAction, type GoalActionFailure, type GoalActionResult } from \"./goal-tool-core.ts\";\n\nexport interface GoalStateRevision {\n\tgoalId: string;\n\trevision: number;\n}\n\nexport function getGoalStateRevision(state: GoalState): GoalStateRevision {\n\treturn { goalId: state.goalId, revision: state.revision ?? 0 };\n}\n\n/** Minimal durable seam shared by CLI, tools, and in-process session restoration. */\nexport interface PersistedGoalStateHost {\n\tgetGoalStateSnapshot(): GoalState | undefined;\n\tsaveGoalStateSnapshot(state: GoalState, expected?: GoalStateRevision): string;\n\tclearGoalStateSnapshot?(state: GoalState, now: string): string;\n}\n\nfunction missingGoal(action: string): GoalActionFailure {\n\treturn { ok: false, error: `No goal exists to ${action}.` };\n}\n\nfunction persistResult(\n\thost: PersistedGoalStateHost,\n\tcurrent: GoalState | undefined,\n\tresult: GoalActionResult,\n): GoalActionResult {\n\tif (!result.ok) return result;\n\thost.saveGoalStateSnapshot(result.state, current ? getGoalStateRevision(current) : undefined);\n\treturn result;\n}\n\nexport function pauseGoal(current: GoalState | undefined, now: string): GoalActionResult {\n\tif (!current) return missingGoal(\"pause\");\n\tif (!isGoalExecutionActive(current.status)) {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is ${current.status}; only active goals can be paused.` };\n\t}\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"pause_goal\", now }) };\n}\n\nexport function resumeGoal(current: GoalState | undefined, now: string): GoalActionResult {\n\tif (!current) return missingGoal(\"resume\");\n\tif (!isGoalResumableStatus(current.status)) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: `Goal '${current.goalId}' is ${current.status}; only paused, blocked, or usage-limited goals can be resumed.`,\n\t\t};\n\t}\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"resume_goal\", now }) };\n}\n\nexport function editGoal(\n\tcurrent: GoalState | undefined,\n\targs: { userGoal: string; tokenBudget?: number },\n\tnow: string,\n): GoalActionResult {\n\tif (!current) return missingGoal(\"edit\");\n\tif (current.status === \"cancelled\") {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is cancelled; start a new goal instead.` };\n\t}\n\tconst userGoal = args.userGoal.trim();\n\tif (!userGoal) return { ok: false, error: \"Goal objective must not be empty.\" };\n\tif (userGoal.length > MAX_GOAL_OBJECTIVE_LENGTH) {\n\t\treturn { ok: false, error: `Goal objective must be at most ${MAX_GOAL_OBJECTIVE_LENGTH} characters.` };\n\t}\n\tif (args.tokenBudget !== undefined && (!Number.isSafeInteger(args.tokenBudget) || args.tokenBudget <= 0)) {\n\t\treturn { ok: false, error: \"Goal token budget must be a positive integer when provided.\" };\n\t}\n\treturn {\n\t\tok: true,\n\t\tstate: applyGoalEvent(current, { type: \"edit_goal\", userGoal, tokenBudget: args.tokenBudget, now }),\n\t};\n}\n\nexport function cancelGoal(current: GoalState | undefined, now: string): GoalActionResult {\n\tif (!current) return missingGoal(\"cancel\");\n\tif (!isGoalUnfinishedStatus(current.status)) {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is already ${current.status}.` };\n\t}\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"cancel_goal\", now }) };\n}\n\n/** Explicit owner replacement. The old and new states cross one persistence boundary. */\nexport function replaceGoal(\n\targs: { goalId: string; userGoal: string; tokenBudget?: number },\n\tnow: string,\n): GoalActionResult {\n\treturn applyGoalAction(undefined, { action: \"start\", ...args }, now);\n}\n\nexport function stopGoalFromSystem(\n\tcurrent: GoalState | undefined,\n\targs: { status: \"blocked\" | \"usage_limited\" | \"budget_limited\"; reason: string },\n\tnow: string,\n): GoalActionResult {\n\tif (!current) return missingGoal(\"stop\");\n\tif (!isGoalExecutionActive(current.status)) {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is ${current.status}; no system stop is needed.` };\n\t}\n\tconst reason = args.reason.trim();\n\tif (!reason) return { ok: false, error: \"System goal stop requires a reason.\" };\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"system_stop_goal\", ...args, reason, now }) };\n}\n\nexport function pausePersistedGoal(host: PersistedGoalStateHost, now = new Date().toISOString()): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, pauseGoal(current, now));\n}\n\nexport function resumePersistedGoal(host: PersistedGoalStateHost, now = new Date().toISOString()): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, resumeGoal(current, now));\n}\n\nexport function editPersistedGoal(\n\thost: PersistedGoalStateHost,\n\targs: { userGoal: string; tokenBudget?: number },\n\tnow = new Date().toISOString(),\n): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, editGoal(current, args, now));\n}\n\nexport function cancelPersistedGoal(host: PersistedGoalStateHost, now = new Date().toISOString()): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, cancelGoal(current, now));\n}\n\nexport type ClearPersistedGoalResult = { ok: true; cleared: boolean } | GoalActionFailure;\n\nexport function clearPersistedGoal(\n\thost: PersistedGoalStateHost,\n\tnow = new Date().toISOString(),\n): ClearPersistedGoalResult {\n\tconst current = host.getGoalStateSnapshot();\n\tif (!current) return { ok: true, cleared: false };\n\tif (!host.clearGoalStateSnapshot) return { ok: false, error: \"This session does not support clearing goals.\" };\n\thost.clearGoalStateSnapshot(current, now);\n\treturn { ok: true, cleared: true };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"goal-lifecycle.js","sourceRoot":"","sources":["../../../src/core/goals/goal-lifecycle.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tapplyGoalEvent,\n\ttype GoalState,\n\tisGoalExecutionActive,\n\tisGoalResumableStatus,\n\tisGoalUnfinishedStatus,\n\tMAX_GOAL_OBJECTIVE_LENGTH,\n} from \"./goal-state.ts\";\nimport { applyGoalAction, type GoalActionFailure, type GoalActionResult } from \"./goal-tool-core.ts\";\n\nexport interface GoalStateRevision {\n\tgoalId: string;\n\trevision: number;\n}\n\nexport function getGoalStateRevision(state: GoalState): GoalStateRevision {\n\treturn { goalId: state.goalId, revision: state.revision ?? 0 };\n}\n\nconst AUTO_RESUMABLE_SYSTEM_STOP_REASON_PREFIXES = [\"runaway_tool_loop:\", \"provider_turn_limit:\"] as const;\n\n/** True only when a bounded runaway/provider-turn guard caused the block, not owner/model/terminal intent. */\nexport function isSystemBlockedGoal(state: GoalState | undefined): boolean {\n\tif (state?.status !== \"blocked\") return false;\n\tfor (let index = state.events.length - 1; index >= 0; index--) {\n\t\tconst event = state.events[index];\n\t\tif (event?.type === \"system_stop_goal\") {\n\t\t\treturn (\n\t\t\t\tevent.status === \"blocked\" &&\n\t\t\t\tAUTO_RESUMABLE_SYSTEM_STOP_REASON_PREFIXES.some((prefix) => event.reason.startsWith(prefix))\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tevent?.type === \"block_goal\" ||\n\t\t\tevent?.type === \"pause_goal\" ||\n\t\t\tevent?.type === \"resume_goal\" ||\n\t\t\tevent?.type === \"complete_goal\" ||\n\t\t\tevent?.type === \"complete_goal_manually\" ||\n\t\t\tevent?.type === \"cancel_goal\"\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn false;\n}\n\n/** Minimal durable seam shared by CLI, tools, and in-process session restoration. */\nexport interface PersistedGoalStateHost {\n\tgetGoalStateSnapshot(): GoalState | undefined;\n\tsaveGoalStateSnapshot(state: GoalState, expected?: GoalStateRevision): string;\n\tclearGoalStateSnapshot?(state: GoalState, now: string): string;\n}\n\nfunction missingGoal(action: string): GoalActionFailure {\n\treturn { ok: false, error: `No goal exists to ${action}.` };\n}\n\nfunction persistResult(\n\thost: PersistedGoalStateHost,\n\tcurrent: GoalState | undefined,\n\tresult: GoalActionResult,\n): GoalActionResult {\n\tif (!result.ok) return result;\n\thost.saveGoalStateSnapshot(result.state, current ? getGoalStateRevision(current) : undefined);\n\treturn result;\n}\n\nexport function pauseGoal(current: GoalState | undefined, now: string): GoalActionResult {\n\tif (!current) return missingGoal(\"pause\");\n\tif (!isGoalExecutionActive(current.status)) {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is ${current.status}; only active goals can be paused.` };\n\t}\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"pause_goal\", now }) };\n}\n\nexport function resumeGoal(current: GoalState | undefined, now: string): GoalActionResult {\n\tif (!current) return missingGoal(\"resume\");\n\tif (!isGoalResumableStatus(current.status)) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: `Goal '${current.goalId}' is ${current.status}; only paused, blocked, or usage-limited goals can be resumed.`,\n\t\t};\n\t}\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"resume_goal\", now }) };\n}\n\nexport function editGoal(\n\tcurrent: GoalState | undefined,\n\targs: { userGoal: string; tokenBudget?: number },\n\tnow: string,\n): GoalActionResult {\n\tif (!current) return missingGoal(\"edit\");\n\tif (current.status === \"cancelled\") {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is cancelled; start a new goal instead.` };\n\t}\n\tconst userGoal = args.userGoal.trim();\n\tif (!userGoal) return { ok: false, error: \"Goal objective must not be empty.\" };\n\tif (userGoal.length > MAX_GOAL_OBJECTIVE_LENGTH) {\n\t\treturn { ok: false, error: `Goal objective must be at most ${MAX_GOAL_OBJECTIVE_LENGTH} characters.` };\n\t}\n\tif (args.tokenBudget !== undefined && (!Number.isSafeInteger(args.tokenBudget) || args.tokenBudget <= 0)) {\n\t\treturn { ok: false, error: \"Goal token budget must be a positive integer when provided.\" };\n\t}\n\treturn {\n\t\tok: true,\n\t\tstate: applyGoalEvent(current, { type: \"edit_goal\", userGoal, tokenBudget: args.tokenBudget, now }),\n\t};\n}\n\nexport function cancelGoal(current: GoalState | undefined, now: string): GoalActionResult {\n\tif (!current) return missingGoal(\"cancel\");\n\tif (!isGoalUnfinishedStatus(current.status)) {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is already ${current.status}.` };\n\t}\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"cancel_goal\", now }) };\n}\n\n/** Explicit owner replacement. The old and new states cross one persistence boundary. */\nexport function replaceGoal(\n\targs: { goalId: string; userGoal: string; tokenBudget?: number },\n\tnow: string,\n): GoalActionResult {\n\treturn applyGoalAction(undefined, { action: \"start\", ...args }, now);\n}\n\nexport function stopGoalFromSystem(\n\tcurrent: GoalState | undefined,\n\targs: { status: \"blocked\" | \"usage_limited\" | \"budget_limited\"; reason: string },\n\tnow: string,\n): GoalActionResult {\n\tif (!current) return missingGoal(\"stop\");\n\tif (!isGoalExecutionActive(current.status)) {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is ${current.status}; no system stop is needed.` };\n\t}\n\tconst reason = args.reason.trim();\n\tif (!reason) return { ok: false, error: \"System goal stop requires a reason.\" };\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"system_stop_goal\", ...args, reason, now }) };\n}\n\nexport function pausePersistedGoal(host: PersistedGoalStateHost, now = new Date().toISOString()): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, pauseGoal(current, now));\n}\n\nexport function resumePersistedGoal(host: PersistedGoalStateHost, now = new Date().toISOString()): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, resumeGoal(current, now));\n}\n\nexport function editPersistedGoal(\n\thost: PersistedGoalStateHost,\n\targs: { userGoal: string; tokenBudget?: number },\n\tnow = new Date().toISOString(),\n): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, editGoal(current, args, now));\n}\n\nexport function cancelPersistedGoal(host: PersistedGoalStateHost, now = new Date().toISOString()): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, cancelGoal(current, now));\n}\n\nexport type ClearPersistedGoalResult = { ok: true; cleared: boolean } | GoalActionFailure;\n\nexport function clearPersistedGoal(\n\thost: PersistedGoalStateHost,\n\tnow = new Date().toISOString(),\n): ClearPersistedGoalResult {\n\tconst current = host.getGoalStateSnapshot();\n\tif (!current) return { ok: true, cleared: false };\n\tif (!host.clearGoalStateSnapshot) return { ok: false, error: \"This session does not support clearing goals.\" };\n\thost.clearGoalStateSnapshot(current, now);\n\treturn { ok: true, cleared: true };\n}\n"]}
|
|
@@ -51,6 +51,12 @@ export declare class GoalSessionController {
|
|
|
51
51
|
saveState(state: GoalState, expected?: GoalStateRevision): string;
|
|
52
52
|
clearState(state: GoalState, now: string): string;
|
|
53
53
|
getState(): GoalState | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* A bounded runaway/provider-turn guard stops one autonomous run, not the owner's durable intent.
|
|
56
|
+
* Resume that narrow class immediately or during restoration while preserving deliberate blocks,
|
|
57
|
+
* terminal tool failures, pauses, and quota/budget stops.
|
|
58
|
+
*/
|
|
59
|
+
resumeSystemBlockedGoal(now?: string): string | undefined;
|
|
54
60
|
/**
|
|
55
61
|
* Promote high-confidence natural-language persistence into the same durable state written by the
|
|
56
62
|
* goal tool. This is intentionally narrower than task detection: ordinary work never starts a
|
|
@@ -111,12 +117,12 @@ export declare class GoalSessionController {
|
|
|
111
117
|
private resolveExecutionState;
|
|
112
118
|
private flushPendingExecutionUsage;
|
|
113
119
|
markToolUnavailable(): void;
|
|
114
|
-
|
|
120
|
+
recoverFromHarnessGuard(info: AgentRunawayStopInfo): boolean;
|
|
115
121
|
markTerminalToolFailureBlocked(toolName: string): boolean;
|
|
116
122
|
getRuntimeSnapshot(settings: GoalRuntimeSnapshotSettings): GoalRuntimeSnapshot;
|
|
117
123
|
continueOnce(options: GoalContinuationOnceOptions): Promise<GoalContinuationOnceResult>;
|
|
118
124
|
continueLoop(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult>;
|
|
119
|
-
restoreAfterResume():
|
|
125
|
+
restoreAfterResume(): boolean;
|
|
120
126
|
private recordContinuationFailure;
|
|
121
127
|
private markBudgetLimited;
|
|
122
128
|
private stopActiveGoal;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"goal-session-controller.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-session-controller.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiC,KAAK,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACvG,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC1F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EACN,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAE/B,KAAK,aAAa,EAClB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAGnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAE9E,OAAO,
|
|
1
|
+
{"version":3,"file":"goal-session-controller.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-session-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import { isInterruptedAssistantStopReason, } from "../agent-session-contracts.js
|
|
|
5
5
|
import { GoalLoopController } from "../goal-loop-controller.js";
|
|
6
6
|
import { budgetedTokens } from "../orchestration/capability-gateway.js";
|
|
7
7
|
import { GoalBudgetExhaustedError } from "./goal-execution-errors.js";
|
|
8
|
-
import { getGoalStateRevision, stopGoalFromSystem } from "./goal-lifecycle.js";
|
|
8
|
+
import { getGoalStateRevision, isSystemBlockedGoal, resumeGoal, stopGoalFromSystem, } from "./goal-lifecycle.js";
|
|
9
9
|
import { buildGoalRuntimeSnapshot, } from "./goal-runtime-snapshot.js";
|
|
10
10
|
import { applyGoalEvent, isGoalExecutionActive, isGoalUnfinishedStatus } from "./goal-state.js";
|
|
11
11
|
import { applyGoalAction } from "./goal-tool-core.js";
|
|
@@ -88,6 +88,21 @@ export class GoalSessionController {
|
|
|
88
88
|
getState() {
|
|
89
89
|
return getLatestGoalStateSnapshot(this.deps.getSessionManager());
|
|
90
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* A bounded runaway/provider-turn guard stops one autonomous run, not the owner's durable intent.
|
|
93
|
+
* Resume that narrow class immediately or during restoration while preserving deliberate blocks,
|
|
94
|
+
* terminal tool failures, pauses, and quota/budget stops.
|
|
95
|
+
*/
|
|
96
|
+
resumeSystemBlockedGoal(now = new Date().toISOString()) {
|
|
97
|
+
const current = this.getState();
|
|
98
|
+
if (!current || !isSystemBlockedGoal(current))
|
|
99
|
+
return undefined;
|
|
100
|
+
const resumed = resumeGoal(current, now);
|
|
101
|
+
if (!resumed.ok)
|
|
102
|
+
return undefined;
|
|
103
|
+
this.saveState(resumed.state, getGoalStateRevision(current));
|
|
104
|
+
return resumed.state.goalId;
|
|
105
|
+
}
|
|
91
106
|
/**
|
|
92
107
|
* Promote high-confidence natural-language persistence into the same durable state written by the
|
|
93
108
|
* goal tool. This is intentionally narrower than task detection: ordinary work never starts a
|
|
@@ -385,11 +400,13 @@ export class GoalSessionController {
|
|
|
385
400
|
markToolUnavailable() {
|
|
386
401
|
this.stopActiveGoal("blocked", "goal_tool_unavailable: the active capability surface cannot update durable goal state");
|
|
387
402
|
}
|
|
388
|
-
|
|
403
|
+
recoverFromHarnessGuard(info) {
|
|
389
404
|
const reason = info.reason === "provider_turn_limit"
|
|
390
405
|
? `provider_turn_limit: reached the explicit ${info.repeats}-request provider-turn limit`
|
|
391
406
|
: `runaway_tool_loop: repeated tool-call signature ${info.signature} ${info.repeats} times without progress`;
|
|
392
|
-
|
|
407
|
+
if (!this.stopActiveGoal("blocked", reason))
|
|
408
|
+
return false;
|
|
409
|
+
return this.resumeSystemBlockedGoal() !== undefined;
|
|
393
410
|
}
|
|
394
411
|
markTerminalToolFailureBlocked(toolName) {
|
|
395
412
|
return this.stopActiveGoal("blocked", `terminal_tool_failure: ${toolName} reported an unrecoverable error and terminated the run`);
|
|
@@ -410,7 +427,9 @@ export class GoalSessionController {
|
|
|
410
427
|
return this.loop.continueGoalLoop(options);
|
|
411
428
|
}
|
|
412
429
|
restoreAfterResume() {
|
|
430
|
+
const resumedGoalId = this.resumeSystemBlockedGoal();
|
|
413
431
|
this.deps.scheduleGoalAutoContinueFromIdle();
|
|
432
|
+
return resumedGoalId !== undefined;
|
|
414
433
|
}
|
|
415
434
|
recordContinuationFailure(error) {
|
|
416
435
|
const state = this.getState();
|