mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-07 06:52:28 +00:00
Stop active Codex child agents on abort (#615)
* fix(cli): stop active codex child agents * chore: refresh bun lockfile for deploy * fix(web): enable stop for active codex child agents * test(cli): cover aborting active codex child agents
This commit is contained in:
@@ -84,6 +84,7 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
|
||||
private abortController: AbortController = new AbortController();
|
||||
private currentThreadId: string | null = null;
|
||||
private currentTurnId: string | null = null;
|
||||
private readonly activeChildTurns = new Map<string, string>();
|
||||
|
||||
constructor(session: CodexSession) {
|
||||
super(process.env.DEBUG ? session.logPath : undefined);
|
||||
@@ -95,19 +96,50 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
|
||||
return React.createElement(CodexDisplay, context);
|
||||
}
|
||||
|
||||
private async interruptActiveTurns(reason: string): Promise<void> {
|
||||
const turnsToInterrupt = [
|
||||
...(this.currentThreadId && this.currentTurnId
|
||||
? [{ threadId: this.currentThreadId, turnId: this.currentTurnId, role: 'parent' as const }]
|
||||
: []),
|
||||
...Array.from(this.activeChildTurns, ([threadId, turnId]) => ({
|
||||
threadId,
|
||||
turnId,
|
||||
role: 'child' as const
|
||||
}))
|
||||
];
|
||||
|
||||
if (turnsToInterrupt.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await Promise.allSettled(
|
||||
turnsToInterrupt.map((target) => this.appServerClient.interruptTurn({
|
||||
threadId: target.threadId,
|
||||
turnId: target.turnId
|
||||
}))
|
||||
);
|
||||
|
||||
results.forEach((result, index) => {
|
||||
const target = turnsToInterrupt[index];
|
||||
if (result.status === 'fulfilled') {
|
||||
if (target.role === 'child') {
|
||||
this.activeChildTurns.delete(target.threadId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug(
|
||||
`[Codex] Error interrupting ${target.role} app-server turn ` +
|
||||
`for ${reason}; threadId=${target.threadId} turnId=${target.turnId}:`,
|
||||
result.reason
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private async handleAbort(): Promise<void> {
|
||||
logger.debug('[Codex] Abort requested - stopping current task');
|
||||
try {
|
||||
if (this.currentThreadId && this.currentTurnId) {
|
||||
try {
|
||||
await this.appServerClient.interruptTurn({
|
||||
threadId: this.currentThreadId,
|
||||
turnId: this.currentTurnId
|
||||
});
|
||||
} catch (error) {
|
||||
logger.debug('[Codex] Error interrupting app-server turn:', error);
|
||||
}
|
||||
}
|
||||
await this.interruptActiveTurns('abort');
|
||||
this.currentTurnId = null;
|
||||
|
||||
this.abortController.abort();
|
||||
@@ -1635,6 +1667,15 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
|
||||
`[Codex] Routing event from non-active thread into agent trace; ` +
|
||||
`type=${msgType}, eventThreadId=${eventThreadId}, activeThread=${this.currentThreadId}`
|
||||
);
|
||||
if (msgType === 'task_started') {
|
||||
if (eventTurnId) {
|
||||
this.activeChildTurns.set(eventThreadId, eventTurnId);
|
||||
} else {
|
||||
logger.debug(`[Codex] Child task_started missing turn id; threadId=${eventThreadId}`);
|
||||
}
|
||||
} else if (isTerminalEvent) {
|
||||
this.activeChildTurns.delete(eventThreadId);
|
||||
}
|
||||
handleChildCodexEvent(eventThreadId, msg);
|
||||
return;
|
||||
}
|
||||
@@ -2176,17 +2217,7 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
|
||||
};
|
||||
|
||||
const interruptActiveTurn = async () => {
|
||||
const threadId = this.currentThreadId;
|
||||
const turnId = this.currentTurnId;
|
||||
if (!threadId || !turnId) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await appServerClient.interruptTurn({ threadId, turnId });
|
||||
} catch (error) {
|
||||
logger.debug('[Codex] Error interrupting app-server turn for slash command:', error);
|
||||
}
|
||||
await this.interruptActiveTurns('slash command');
|
||||
};
|
||||
|
||||
const resumeExistingThreadForCompact = async (mode: EnhancedMode): Promise<string | null> => {
|
||||
@@ -2475,6 +2506,7 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
|
||||
this.permissionHandler = null;
|
||||
this.reasoningProcessor = null;
|
||||
this.diffProcessor = null;
|
||||
this.activeChildTurns.clear();
|
||||
|
||||
logger.debug('[codex-remote]: cleanup done');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user