killeros 2.1.27 → 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 +18 -0
- package/README.md +3 -3
- package/killeros/activity.ts +16 -7
- package/killeros/footer.ts +6 -4
- package/killeros/goal-interface.ts +195 -48
- package/killeros/goal-runtime.ts +190 -44
- package/killeros/goal-settlement.ts +129 -30
- package/killeros/goal-state.ts +205 -32
- package/killeros/runtime.ts +54 -0
- package/killeros/worked-for.ts +1 -1
- package/package.json +1 -1
- package/themes/killeros.json +3 -2
package/killeros/goal-runtime.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
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
14
|
import type { GoalRuntime, GoalState, GoalStatus } from "./runtime.ts";
|
|
6
15
|
import { safeTerminalText } from "./safe-terminal-text.ts";
|
|
@@ -9,7 +18,7 @@ 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,40 +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
271
|
ctx: ExtensionContext,
|
|
272
|
+
state: Extract<GoalState, { status: "active" }>,
|
|
208
273
|
): boolean {
|
|
209
|
-
if (isGoalModeSupported(ctx) && isSavedSession(ctx) && pauseGoalAtTurnLimit(pi, runtime, ctx)) return false;
|
|
210
|
-
if (!isGoalModeSupported(ctx)
|
|
211
|
-
|| !isSavedSession(ctx)
|
|
212
|
-
|| runtime.state?.status !== "active"
|
|
213
|
-
|| runtime.continuationScheduled
|
|
214
|
-
|| runtime.continuationHeld
|
|
215
|
-
|| runtime.goalTurnInFlight
|
|
216
|
-
|| !ctx.isIdle()
|
|
217
|
-
|| ctx.hasPendingMessages()) return false;
|
|
218
274
|
runtime.continuationScheduled = true;
|
|
219
|
-
const next = beginGoalTurn(pi, runtime, ctx, runtime.state);
|
|
220
|
-
if (!next) return false;
|
|
221
275
|
try {
|
|
222
276
|
pi.sendMessage({
|
|
223
277
|
customType: GOAL_CONTINUATION_TYPE,
|
|
224
|
-
content: goalContinuationMessage(
|
|
278
|
+
content: goalContinuationMessage(state, ctx),
|
|
225
279
|
display: false,
|
|
226
280
|
}, { triggerTurn: true, deliverAs: "followUp" });
|
|
227
281
|
return true;
|
|
228
282
|
} catch (error) {
|
|
229
283
|
runtime.continuationScheduled = false;
|
|
230
284
|
runtime.goalTurnInFlight = false;
|
|
285
|
+
runtime.goalTurn = undefined;
|
|
231
286
|
pauseGoalAfterFailure(pi, runtime, ctx, `continuation could not start: ${error instanceof Error ? error.message : String(error)}`);
|
|
232
287
|
return false;
|
|
233
288
|
}
|
|
234
289
|
}
|
|
235
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
|
+
|
|
236
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
|
+
: [];
|
|
237
347
|
return [
|
|
238
348
|
`# ${heading}`,
|
|
239
349
|
`Status: active · Turn: ${state.turns}`,
|
|
@@ -242,10 +352,18 @@ function goalInstructions(state: GoalState, heading: string): string {
|
|
|
242
352
|
"",
|
|
243
353
|
"Treat the exact objective above from /goal as authoritative; a compaction summary may describe it but does not replace it.",
|
|
244
354
|
"If the current context contains a compaction summary, take its first concrete next step after checking the current repository state.",
|
|
355
|
+
...continuation,
|
|
245
356
|
"Continue making concrete progress toward this unchanged objective. Re-check repository state and prior results instead of repeating work.",
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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.",
|
|
249
367
|
"Never use the goal tool to pause, resume, edit, replace, or clear the objective. Those transitions belong to the user.",
|
|
250
368
|
].join("\n");
|
|
251
369
|
}
|
|
@@ -258,9 +376,7 @@ function goalContinuationMessage(state: GoalState, ctx: ExtensionContext): strin
|
|
|
258
376
|
const sections = [goalInstructions(state, "KillerOS long-running goal turn")];
|
|
259
377
|
if (ctx.isProjectTrusted()) {
|
|
260
378
|
const personal = resolvePersonalInstructions(ctx.cwd);
|
|
261
|
-
if (personal)
|
|
262
|
-
sections.push(personal);
|
|
263
|
-
}
|
|
379
|
+
if (personal) sections.push(personal);
|
|
264
380
|
}
|
|
265
381
|
return sections.join("\n\n");
|
|
266
382
|
}
|
|
@@ -282,27 +398,38 @@ export function registerGoalRuntime(
|
|
|
282
398
|
runtime: GoalRuntime,
|
|
283
399
|
): void {
|
|
284
400
|
const restoreGoal = (ctx: ExtensionContext): void => {
|
|
401
|
+
runtime.lifecycleGeneration += 1;
|
|
402
|
+
const generation = runtime.lifecycleGeneration;
|
|
285
403
|
const restored = restoreGoalState(ctx);
|
|
286
404
|
runtime.state = isGoalModeSupported(ctx) ? restored.state : undefined;
|
|
287
405
|
syncGoalUpdateTool(pi, runtime);
|
|
288
406
|
runtime.continuationScheduled = false;
|
|
289
407
|
runtime.continuationHeld = false;
|
|
290
408
|
runtime.goalTurnInFlight = false;
|
|
409
|
+
runtime.goalTurn = undefined;
|
|
291
410
|
runtime.agentEndObserved = false;
|
|
292
411
|
runtime.automaticCompaction = undefined;
|
|
293
412
|
runtime.persistenceRetryNeeded = false;
|
|
294
413
|
runtime.lastStopReason = undefined;
|
|
295
414
|
runtime.lastError = undefined;
|
|
296
415
|
runtime.requestRender?.();
|
|
297
|
-
|
|
298
|
-
|
|
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;
|
|
299
421
|
}
|
|
422
|
+
setImmediate(() => {
|
|
423
|
+
if (runtime.lifecycleGeneration !== generation || runtime.state !== state) return;
|
|
424
|
+
scheduleGoalContinuation(pi, runtime, ctx, { generation, state });
|
|
425
|
+
});
|
|
300
426
|
};
|
|
301
427
|
|
|
302
428
|
pi.on("session_start", (_event, ctx) => restoreGoal(ctx));
|
|
303
429
|
pi.on("session_tree", (_event, ctx) => restoreGoal(ctx));
|
|
304
430
|
|
|
305
431
|
pi.on("session_shutdown", (_event, ctx) => {
|
|
432
|
+
runtime.lifecycleGeneration += 1;
|
|
306
433
|
if (runtime.state?.status === "active") {
|
|
307
434
|
const checkpoint = checkpointActiveGoalState(runtime.state, Date.now());
|
|
308
435
|
try {
|
|
@@ -313,14 +440,9 @@ export function registerGoalRuntime(
|
|
|
313
440
|
}
|
|
314
441
|
runtime.state = undefined;
|
|
315
442
|
syncGoalUpdateTool(pi, runtime);
|
|
316
|
-
runtime
|
|
443
|
+
clearGoalExecutionFlags(runtime);
|
|
317
444
|
runtime.continuationHeld = false;
|
|
318
|
-
runtime.goalTurnInFlight = false;
|
|
319
|
-
runtime.agentEndObserved = false;
|
|
320
|
-
runtime.automaticCompaction = undefined;
|
|
321
445
|
runtime.persistenceRetryNeeded = false;
|
|
322
|
-
runtime.lastStopReason = undefined;
|
|
323
|
-
runtime.lastError = undefined;
|
|
324
446
|
});
|
|
325
447
|
|
|
326
448
|
pi.on("before_agent_start", (event, ctx) => {
|
|
@@ -328,7 +450,31 @@ export function registerGoalRuntime(
|
|
|
328
450
|
if (!runtime.goalTurnInFlight && isGoalModeSupported(ctx) && isSavedSession(ctx) && pauseGoalAtTurnLimit(pi, runtime, ctx)) return;
|
|
329
451
|
const current = runtime.state;
|
|
330
452
|
if (!isGoalModeSupported(ctx) || !isSavedSession(ctx) || !current || current.status !== "active") return;
|
|
331
|
-
if (runtime.goalTurnInFlight)
|
|
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
|
+
}
|
|
332
478
|
const next = beginGoalTurn(pi, runtime, ctx, current);
|
|
333
479
|
if (!next) return;
|
|
334
480
|
return { systemPrompt: `${event.systemPrompt}\n\n${goalSystemPrompt(next)}` };
|