killeros 2.1.26 → 2.1.28
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 +38 -0
- package/Killeros.ts +6 -13
- package/README.md +8 -10
- package/killeros/activity.ts +16 -7
- package/killeros/auto-compaction.ts +1 -2
- package/killeros/change-receipt.ts +109 -37
- package/killeros/codex-fast.ts +8 -3
- package/killeros/footer.ts +82 -31
- package/killeros/goal-interface.ts +198 -60
- package/killeros/goal-runtime.ts +192 -49
- package/killeros/goal-settlement.ts +140 -49
- package/killeros/goal-state.ts +250 -34
- package/killeros/handoff.ts +36 -4
- package/killeros/passive-git-status.ts +206 -0
- package/killeros/personal-instructions.ts +2 -3
- package/killeros/runtime.ts +51 -35
- package/killeros/shell-ui.ts +13 -4
- package/killeros/worked-for.ts +4 -3
- package/package.json +1 -1
- package/themes/killeros.json +3 -2
- package/killeros/init-evidence.ts +0 -291
- package/killeros/init-target.ts +0 -309
- package/killeros/init.ts +0 -285
package/killeros/goal-runtime.ts
CHANGED
|
@@ -1,15 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { reportError } from "./errors.ts";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
beginGoalTurnState,
|
|
5
|
+
boundGoalText,
|
|
6
|
+
checkpointActiveGoalState,
|
|
7
|
+
GOAL_VERSION,
|
|
8
|
+
parseGoalState,
|
|
9
|
+
pauseGoalState,
|
|
10
|
+
transitionGoalState,
|
|
11
|
+
type GoalTransitionOptions,
|
|
12
|
+
} from "./goal-state.ts";
|
|
4
13
|
import { resolvePersonalInstructions } from "./personal-instructions.ts";
|
|
5
|
-
import type { GoalRuntime, GoalState, GoalStatus
|
|
14
|
+
import type { GoalRuntime, GoalState, GoalStatus } from "./runtime.ts";
|
|
6
15
|
import { safeTerminalText } from "./safe-terminal-text.ts";
|
|
7
16
|
|
|
8
17
|
export const GOAL_ENTRY_TYPE = "killeros-goal";
|
|
9
18
|
const GOAL_CONTINUATION_TYPE = "killeros-goal-continuation";
|
|
10
19
|
export const GOAL_UPDATE_TOOL = "killeros_goal_update";
|
|
11
20
|
|
|
12
|
-
export type GoalEntryEvent = "set" | "replace" | "limit" | "turn" | "pause" | "resume" | "blocked" | "complete" | "error" | "clear" | "checkpoint" | "blocker-audit";
|
|
21
|
+
export type GoalEntryEvent = "set" | "replace" | "limit" | "turn" | "continue" | "pause" | "resume" | "blocked" | "complete" | "error" | "clear" | "checkpoint" | "blocker-audit";
|
|
13
22
|
export interface GoalEntryData {
|
|
14
23
|
version: 1;
|
|
15
24
|
event: GoalEntryEvent;
|
|
@@ -75,18 +84,32 @@ export function sumGoalTokens(ctx: ExtensionContext): number {
|
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
function setGoalUpdateToolActive(pi: ExtensionAPI, active: boolean): void {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
87
|
+
try {
|
|
88
|
+
const activeTools = pi.getActiveTools();
|
|
89
|
+
const isActive = activeTools.includes(GOAL_UPDATE_TOOL);
|
|
90
|
+
if (active === isActive) return;
|
|
91
|
+
pi.setActiveTools(active
|
|
92
|
+
? [...activeTools, GOAL_UPDATE_TOOL]
|
|
93
|
+
: activeTools.filter((name) => name !== GOAL_UPDATE_TOOL));
|
|
94
|
+
} catch {
|
|
95
|
+
// Availability is checked again immediately before a goal request.
|
|
96
|
+
}
|
|
84
97
|
}
|
|
85
98
|
|
|
86
99
|
export function syncGoalUpdateTool(pi: ExtensionAPI, runtime: GoalRuntime): void {
|
|
87
100
|
setGoalUpdateToolActive(pi, runtime.state?.status === "active");
|
|
88
101
|
}
|
|
89
102
|
|
|
103
|
+
function goalUpdateToolIsAvailable(pi: ExtensionAPI): boolean {
|
|
104
|
+
try {
|
|
105
|
+
const active = pi.getActiveTools();
|
|
106
|
+
if (!active.includes(GOAL_UPDATE_TOOL)) pi.setActiveTools([...active, GOAL_UPDATE_TOOL]);
|
|
107
|
+
return pi.getActiveTools().includes(GOAL_UPDATE_TOOL);
|
|
108
|
+
} catch {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
90
113
|
export function persistGoalState(
|
|
91
114
|
pi: ExtensionAPI,
|
|
92
115
|
runtime: GoalRuntime,
|
|
@@ -94,7 +117,6 @@ export function persistGoalState(
|
|
|
94
117
|
state: GoalState | undefined,
|
|
95
118
|
): void {
|
|
96
119
|
const data: GoalEntryData = { version: GOAL_VERSION, event, state: state ?? null };
|
|
97
|
-
runtime.automaticCompaction = undefined;
|
|
98
120
|
pi.appendEntry(GOAL_ENTRY_TYPE, data);
|
|
99
121
|
runtime.state = state;
|
|
100
122
|
syncGoalUpdateTool(pi, runtime);
|
|
@@ -117,6 +139,15 @@ export function transitionGoal(
|
|
|
117
139
|
if (status !== "active") {
|
|
118
140
|
runtime.continuationScheduled = false;
|
|
119
141
|
runtime.automaticCompaction = undefined;
|
|
142
|
+
if (!options.keepTurnForRecovery) {
|
|
143
|
+
runtime.goalTurn = undefined;
|
|
144
|
+
runtime.goalTurnInFlight = false;
|
|
145
|
+
runtime.agentEndObserved = false;
|
|
146
|
+
}
|
|
147
|
+
} else if (!options.resumeInterruptedTurn) {
|
|
148
|
+
runtime.goalTurn = undefined;
|
|
149
|
+
runtime.goalTurnInFlight = false;
|
|
150
|
+
runtime.agentEndObserved = false;
|
|
120
151
|
}
|
|
121
152
|
return next;
|
|
122
153
|
}
|
|
@@ -141,6 +172,7 @@ function clearGoalExecutionFlags(runtime: GoalRuntime): void {
|
|
|
141
172
|
runtime.continuationScheduled = false;
|
|
142
173
|
runtime.goalTurnInFlight = false;
|
|
143
174
|
runtime.agentEndObserved = false;
|
|
175
|
+
runtime.goalTurn = undefined;
|
|
144
176
|
runtime.automaticCompaction = undefined;
|
|
145
177
|
runtime.lastStopReason = undefined;
|
|
146
178
|
runtime.lastError = undefined;
|
|
@@ -156,6 +188,10 @@ export async function stopGoalRun(runtime: GoalRuntime, ctx: ExtensionCommandCon
|
|
|
156
188
|
}
|
|
157
189
|
}
|
|
158
190
|
|
|
191
|
+
function safeFailureReason(reason: string): string {
|
|
192
|
+
return boundGoalText(reason) || "an unspecified goal failure";
|
|
193
|
+
}
|
|
194
|
+
|
|
159
195
|
export function pauseGoalAfterFailure(
|
|
160
196
|
pi: ExtensionAPI,
|
|
161
197
|
runtime: GoalRuntime,
|
|
@@ -165,7 +201,11 @@ export function pauseGoalAfterFailure(
|
|
|
165
201
|
notify = true,
|
|
166
202
|
): void {
|
|
167
203
|
if (runtime.state?.status !== "active") return;
|
|
168
|
-
const safeReason =
|
|
204
|
+
const safeReason = safeFailureReason(reason);
|
|
205
|
+
const safeRecoveryInstruction = safeReason === "no turn decision"
|
|
206
|
+
&& recoveryInstruction === "Run /goal resume after resolving the problem."
|
|
207
|
+
? "The agent ended without choosing continue, complete, or blocked. Run /goal resume only after choosing to continue."
|
|
208
|
+
: safeTerminalText(recoveryInstruction);
|
|
169
209
|
try {
|
|
170
210
|
transitionGoal(pi, runtime, "error", "paused", safeReason);
|
|
171
211
|
} catch {
|
|
@@ -173,11 +213,34 @@ export function pauseGoalAfterFailure(
|
|
|
173
213
|
runtime.state = current ? pauseGoalState(current, safeReason, Date.now()) : undefined;
|
|
174
214
|
syncGoalUpdateTool(pi, runtime);
|
|
175
215
|
runtime.persistenceRetryNeeded = true;
|
|
176
|
-
runtime
|
|
177
|
-
runtime.
|
|
216
|
+
clearGoalExecutionFlags(runtime);
|
|
217
|
+
runtime.requestRender?.();
|
|
218
|
+
}
|
|
219
|
+
if (notify) ctx.ui.notify(`Goal paused: ${safeReason}\n${safeRecoveryInstruction}`, "error");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function pauseGoalBeforeTurn(
|
|
223
|
+
pi: ExtensionAPI,
|
|
224
|
+
runtime: GoalRuntime,
|
|
225
|
+
ctx: ExtensionContext,
|
|
226
|
+
): void {
|
|
227
|
+
const state = runtime.state;
|
|
228
|
+
if (state?.status !== "active") return;
|
|
229
|
+
const nextTurn = state.turns + 1;
|
|
230
|
+
const reason = "killeros_goal_update is unavailable";
|
|
231
|
+
try {
|
|
232
|
+
transitionGoal(pi, runtime, "error", "paused", reason);
|
|
233
|
+
} catch {
|
|
234
|
+
runtime.state = pauseGoalState(state, reason, Date.now());
|
|
235
|
+
syncGoalUpdateTool(pi, runtime);
|
|
236
|
+
runtime.persistenceRetryNeeded = true;
|
|
237
|
+
clearGoalExecutionFlags(runtime);
|
|
178
238
|
runtime.requestRender?.();
|
|
179
239
|
}
|
|
180
|
-
|
|
240
|
+
ctx.ui.notify(
|
|
241
|
+
`Goal paused before turn ${nextTurn}: ${reason}\nEnable the goal tool, then run /goal resume.`,
|
|
242
|
+
"error",
|
|
243
|
+
);
|
|
181
244
|
}
|
|
182
245
|
|
|
183
246
|
function beginGoalTurn(
|
|
@@ -186,13 +249,15 @@ function beginGoalTurn(
|
|
|
186
249
|
ctx: ExtensionContext,
|
|
187
250
|
current: Extract<GoalState, { status: "active" }>,
|
|
188
251
|
): GoalState | undefined {
|
|
189
|
-
|
|
252
|
+
let next: GoalState;
|
|
190
253
|
try {
|
|
254
|
+
next = beginGoalTurnState(current, Date.now());
|
|
191
255
|
persistGoalState(pi, runtime, "turn", next);
|
|
192
256
|
} catch (error) {
|
|
193
257
|
pauseGoalAfterFailure(pi, runtime, ctx, `turn state could not be saved: ${error instanceof Error ? error.message : String(error)}`);
|
|
194
258
|
return undefined;
|
|
195
259
|
}
|
|
260
|
+
runtime.goalTurn = { revision: next.revision, turn: next.turns };
|
|
196
261
|
runtime.goalTurnInFlight = true;
|
|
197
262
|
runtime.agentEndObserved = false;
|
|
198
263
|
runtime.lastStopReason = undefined;
|
|
@@ -200,42 +265,85 @@ function beginGoalTurn(
|
|
|
200
265
|
return next;
|
|
201
266
|
}
|
|
202
267
|
|
|
203
|
-
|
|
204
|
-
export function scheduleGoalContinuation(
|
|
268
|
+
function sendGoalTurn(
|
|
205
269
|
pi: ExtensionAPI,
|
|
206
270
|
runtime: GoalRuntime,
|
|
207
|
-
initState: InitRuntime,
|
|
208
271
|
ctx: ExtensionContext,
|
|
272
|
+
state: Extract<GoalState, { status: "active" }>,
|
|
209
273
|
): boolean {
|
|
210
|
-
if (isGoalModeSupported(ctx) && isSavedSession(ctx) && pauseGoalAtTurnLimit(pi, runtime, ctx)) return false;
|
|
211
|
-
if (!isGoalModeSupported(ctx)
|
|
212
|
-
|| !isSavedSession(ctx)
|
|
213
|
-
|| runtime.state?.status !== "active"
|
|
214
|
-
|| runtime.continuationScheduled
|
|
215
|
-
|| runtime.continuationHeld
|
|
216
|
-
|| runtime.goalTurnInFlight
|
|
217
|
-
|| initState.active
|
|
218
|
-
|| !ctx.isIdle()
|
|
219
|
-
|| ctx.hasPendingMessages()) return false;
|
|
220
274
|
runtime.continuationScheduled = true;
|
|
221
|
-
const next = beginGoalTurn(pi, runtime, ctx, runtime.state);
|
|
222
|
-
if (!next) return false;
|
|
223
275
|
try {
|
|
224
276
|
pi.sendMessage({
|
|
225
277
|
customType: GOAL_CONTINUATION_TYPE,
|
|
226
|
-
content: goalContinuationMessage(
|
|
278
|
+
content: goalContinuationMessage(state, ctx),
|
|
227
279
|
display: false,
|
|
228
280
|
}, { triggerTurn: true, deliverAs: "followUp" });
|
|
229
281
|
return true;
|
|
230
282
|
} catch (error) {
|
|
231
283
|
runtime.continuationScheduled = false;
|
|
232
284
|
runtime.goalTurnInFlight = false;
|
|
285
|
+
runtime.goalTurn = undefined;
|
|
233
286
|
pauseGoalAfterFailure(pi, runtime, ctx, `continuation could not start: ${error instanceof Error ? error.message : String(error)}`);
|
|
234
287
|
return false;
|
|
235
288
|
}
|
|
236
289
|
}
|
|
237
290
|
|
|
291
|
+
export function resumeInterruptedGoalTurn(
|
|
292
|
+
pi: ExtensionAPI,
|
|
293
|
+
runtime: GoalRuntime,
|
|
294
|
+
ctx: ExtensionContext,
|
|
295
|
+
): boolean {
|
|
296
|
+
const state = runtime.state;
|
|
297
|
+
if (state?.status !== "active"
|
|
298
|
+
|| (state.turnPhase !== "in-flight" && state.turnPhase !== "authorized")
|
|
299
|
+
|| !runtime.goalTurnInFlight) return false;
|
|
300
|
+
if (!goalUpdateToolIsAvailable(pi)) {
|
|
301
|
+
pauseGoalBeforeTurn(pi, runtime, ctx);
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
return sendGoalTurn(pi, runtime, ctx, state);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** Starts one goal turn only after Pi is idle and all competing workflow gates are clear. */
|
|
308
|
+
export function scheduleGoalContinuation(
|
|
309
|
+
pi: ExtensionAPI,
|
|
310
|
+
runtime: GoalRuntime,
|
|
311
|
+
ctx: ExtensionContext,
|
|
312
|
+
guard?: { generation: number; state: GoalState },
|
|
313
|
+
): boolean {
|
|
314
|
+
if (guard && (guard.generation !== runtime.lifecycleGeneration || runtime.state !== guard.state)) return false;
|
|
315
|
+
if (isGoalModeSupported(ctx) && isSavedSession(ctx) && pauseGoalAtTurnLimit(pi, runtime, ctx)) return false;
|
|
316
|
+
if (!isGoalModeSupported(ctx)
|
|
317
|
+
|| !isSavedSession(ctx)
|
|
318
|
+
|| runtime.state?.status !== "active"
|
|
319
|
+
|| runtime.continuationScheduled
|
|
320
|
+
|| runtime.continuationHeld
|
|
321
|
+
|| runtime.goalTurnInFlight
|
|
322
|
+
|| !ctx.isIdle()
|
|
323
|
+
|| ctx.hasPendingMessages()) return false;
|
|
324
|
+
|
|
325
|
+
const current = runtime.state;
|
|
326
|
+
const phase = current.turnPhase;
|
|
327
|
+
const canStart = phase === "ready"
|
|
328
|
+
|| phase === "authorized"
|
|
329
|
+
|| phase === undefined && current.turns === 0;
|
|
330
|
+
if (!canStart || phase === "authorized" && current.turnDecision === undefined) return false;
|
|
331
|
+
if (!goalUpdateToolIsAvailable(pi)) {
|
|
332
|
+
pauseGoalBeforeTurn(pi, runtime, ctx);
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
const next = beginGoalTurn(pi, runtime, ctx, current);
|
|
336
|
+
return next !== undefined && sendGoalTurn(pi, runtime, ctx, next as Extract<GoalState, { status: "active" }>);
|
|
337
|
+
}
|
|
338
|
+
|
|
238
339
|
function goalInstructions(state: GoalState, heading: string): string {
|
|
340
|
+
const previous = state.lastDecision;
|
|
341
|
+
const continuation = previous?.kind === "continue"
|
|
342
|
+
? [
|
|
343
|
+
"The previous turn's accepted next action was model-reported (not independently verified):",
|
|
344
|
+
previous.nextAction,
|
|
345
|
+
]
|
|
346
|
+
: [];
|
|
239
347
|
return [
|
|
240
348
|
`# ${heading}`,
|
|
241
349
|
`Status: active · Turn: ${state.turns}`,
|
|
@@ -244,10 +352,18 @@ function goalInstructions(state: GoalState, heading: string): string {
|
|
|
244
352
|
"",
|
|
245
353
|
"Treat the exact objective above from /goal as authoritative; a compaction summary may describe it but does not replace it.",
|
|
246
354
|
"If the current context contains a compaction summary, take its first concrete next step after checking the current repository state.",
|
|
355
|
+
...continuation,
|
|
247
356
|
"Continue making concrete progress toward this unchanged objective. Re-check repository state and prior results instead of repeating work.",
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
357
|
+
...(state.turnDecision === undefined
|
|
358
|
+
? [
|
|
359
|
+
"Before ending this turn, choose exactly one accepted goal decision.",
|
|
360
|
+
"After auditing and verifying the whole objective, call killeros_goal_update with status complete and concise evidence.",
|
|
361
|
+
"If useful work remains, call killeros_goal_update with status continue, concrete evidence from this turn, and one concrete nextAction toward the unchanged objective.",
|
|
362
|
+
"If one external impasse persists, call killeros_goal_update with status blocked, the same lowercase blockerKey, and current evidence; attempts one and two record audits and attempt three marks the goal blocked.",
|
|
363
|
+
]
|
|
364
|
+
: ["This logical turn already has one accepted decision. Do not call killeros_goal_update again; finish the interrupted request, then let KillerOS start the authorized next turn after settlement."]),
|
|
365
|
+
"A normal response without one accepted decision pauses the goal. Do not restate a previous result as progress.",
|
|
366
|
+
"Goal evidence and nextAction are model-reported; KillerOS does not verify progress from prose or tool activity.",
|
|
251
367
|
"Never use the goal tool to pause, resume, edit, replace, or clear the objective. Those transitions belong to the user.",
|
|
252
368
|
].join("\n");
|
|
253
369
|
}
|
|
@@ -260,9 +376,7 @@ function goalContinuationMessage(state: GoalState, ctx: ExtensionContext): strin
|
|
|
260
376
|
const sections = [goalInstructions(state, "KillerOS long-running goal turn")];
|
|
261
377
|
if (ctx.isProjectTrusted()) {
|
|
262
378
|
const personal = resolvePersonalInstructions(ctx.cwd);
|
|
263
|
-
if (personal)
|
|
264
|
-
sections.push(personal);
|
|
265
|
-
}
|
|
379
|
+
if (personal) sections.push(personal);
|
|
266
380
|
}
|
|
267
381
|
return sections.join("\n\n");
|
|
268
382
|
}
|
|
@@ -282,30 +396,40 @@ export function isSavedSession(ctx: ExtensionContext): boolean {
|
|
|
282
396
|
export function registerGoalRuntime(
|
|
283
397
|
pi: ExtensionAPI,
|
|
284
398
|
runtime: GoalRuntime,
|
|
285
|
-
initState: InitRuntime,
|
|
286
399
|
): void {
|
|
287
400
|
const restoreGoal = (ctx: ExtensionContext): void => {
|
|
401
|
+
runtime.lifecycleGeneration += 1;
|
|
402
|
+
const generation = runtime.lifecycleGeneration;
|
|
288
403
|
const restored = restoreGoalState(ctx);
|
|
289
404
|
runtime.state = isGoalModeSupported(ctx) ? restored.state : undefined;
|
|
290
405
|
syncGoalUpdateTool(pi, runtime);
|
|
291
406
|
runtime.continuationScheduled = false;
|
|
292
407
|
runtime.continuationHeld = false;
|
|
293
408
|
runtime.goalTurnInFlight = false;
|
|
409
|
+
runtime.goalTurn = undefined;
|
|
294
410
|
runtime.agentEndObserved = false;
|
|
295
411
|
runtime.automaticCompaction = undefined;
|
|
296
412
|
runtime.persistenceRetryNeeded = false;
|
|
297
413
|
runtime.lastStopReason = undefined;
|
|
298
414
|
runtime.lastError = undefined;
|
|
299
415
|
runtime.requestRender?.();
|
|
300
|
-
|
|
301
|
-
|
|
416
|
+
const state = runtime.state;
|
|
417
|
+
if (state?.status !== "active") return;
|
|
418
|
+
if ((state.turnPhase === "in-flight") || (state.turnPhase === undefined && state.turns > 0)) {
|
|
419
|
+
pauseGoalAfterFailure(pi, runtime, ctx, "no turn decision");
|
|
420
|
+
return;
|
|
302
421
|
}
|
|
422
|
+
setImmediate(() => {
|
|
423
|
+
if (runtime.lifecycleGeneration !== generation || runtime.state !== state) return;
|
|
424
|
+
scheduleGoalContinuation(pi, runtime, ctx, { generation, state });
|
|
425
|
+
});
|
|
303
426
|
};
|
|
304
427
|
|
|
305
428
|
pi.on("session_start", (_event, ctx) => restoreGoal(ctx));
|
|
306
429
|
pi.on("session_tree", (_event, ctx) => restoreGoal(ctx));
|
|
307
430
|
|
|
308
431
|
pi.on("session_shutdown", (_event, ctx) => {
|
|
432
|
+
runtime.lifecycleGeneration += 1;
|
|
309
433
|
if (runtime.state?.status === "active") {
|
|
310
434
|
const checkpoint = checkpointActiveGoalState(runtime.state, Date.now());
|
|
311
435
|
try {
|
|
@@ -316,22 +440,41 @@ export function registerGoalRuntime(
|
|
|
316
440
|
}
|
|
317
441
|
runtime.state = undefined;
|
|
318
442
|
syncGoalUpdateTool(pi, runtime);
|
|
319
|
-
runtime
|
|
443
|
+
clearGoalExecutionFlags(runtime);
|
|
320
444
|
runtime.continuationHeld = false;
|
|
321
|
-
runtime.goalTurnInFlight = false;
|
|
322
|
-
runtime.agentEndObserved = false;
|
|
323
|
-
runtime.automaticCompaction = undefined;
|
|
324
445
|
runtime.persistenceRetryNeeded = false;
|
|
325
|
-
runtime.lastStopReason = undefined;
|
|
326
|
-
runtime.lastError = undefined;
|
|
327
446
|
});
|
|
328
447
|
|
|
329
448
|
pi.on("before_agent_start", (event, ctx) => {
|
|
330
449
|
runtime.continuationScheduled = false;
|
|
331
450
|
if (!runtime.goalTurnInFlight && isGoalModeSupported(ctx) && isSavedSession(ctx) && pauseGoalAtTurnLimit(pi, runtime, ctx)) return;
|
|
332
451
|
const current = runtime.state;
|
|
333
|
-
if (!isGoalModeSupported(ctx) || !isSavedSession(ctx) || !current || current.status !== "active"
|
|
334
|
-
if (runtime.goalTurnInFlight)
|
|
452
|
+
if (!isGoalModeSupported(ctx) || !isSavedSession(ctx) || !current || current.status !== "active") return;
|
|
453
|
+
if (runtime.goalTurnInFlight) {
|
|
454
|
+
if (!goalUpdateToolIsAvailable(pi)) {
|
|
455
|
+
pauseGoalBeforeTurn(pi, runtime, ctx);
|
|
456
|
+
try {
|
|
457
|
+
ctx.abort();
|
|
458
|
+
} catch {
|
|
459
|
+
// The state is already paused; a host abort may be unavailable during startup.
|
|
460
|
+
}
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
return { systemPrompt: `${event.systemPrompt}\n\n${goalSystemPrompt(current)}` };
|
|
464
|
+
}
|
|
465
|
+
if (current.turnPhase === "in-flight") {
|
|
466
|
+
pauseGoalAfterFailure(pi, runtime, ctx, "no turn decision");
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
if (!goalUpdateToolIsAvailable(pi)) {
|
|
470
|
+
pauseGoalBeforeTurn(pi, runtime, ctx);
|
|
471
|
+
try {
|
|
472
|
+
ctx.abort();
|
|
473
|
+
} catch {
|
|
474
|
+
// See the in-flight branch above.
|
|
475
|
+
}
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
335
478
|
const next = beginGoalTurn(pi, runtime, ctx, current);
|
|
336
479
|
if (!next) return;
|
|
337
480
|
return { systemPrompt: `${event.systemPrompt}\n\n${goalSystemPrompt(next)}` };
|