fix: thread AbortSignal through LLM calls so stop_goal cancels immediately

The agent loop checked signal.aborted only at the top of each iteration,
but the LLM fetch() call (which takes seconds) never received the signal.
Now the signal is passed to fetch() and checked after LLM errors and
before the inter-step sleep, so aborting takes effect mid-step.
This commit is contained in:
Somasundaram Mahesh
2026-02-18 18:49:13 +05:30
parent 011e2be291
commit 0b36d92fef
2 changed files with 11 additions and 4 deletions

View File

@@ -22,7 +22,8 @@ export interface LLMProvider {
getAction(
systemPrompt: string,
userPrompt: string,
imageBase64?: string
imageBase64?: string,
signal?: AbortSignal
): Promise<string>;
}
@@ -381,7 +382,8 @@ export function getLlmProvider(config: LLMConfig): LLMProvider {
async getAction(
systemPrompt: string,
userPrompt: string,
imageBase64?: string
imageBase64?: string,
signal?: AbortSignal
): Promise<string> {
const messages: Array<{ role: string; content: unknown }> = [
{ role: "system", content: systemPrompt },
@@ -418,6 +420,7 @@ export function getLlmProvider(config: LLMConfig): LLMProvider {
max_tokens: 1024,
response_format: { type: "json_object" },
}),
signal,
});
if (!response.ok) {

View File

@@ -489,9 +489,11 @@ export async function runAgentLoop(
rawResponse = await llm.getAction(
systemPrompt,
userPrompt,
useScreenshot ? screenshot : undefined
useScreenshot ? screenshot : undefined,
signal
);
} catch (err) {
if (signal?.aborted) break;
console.error(
`[Agent ${sessionId}] LLM error at step ${step + 1}: ${(err as Error).message}`
);
@@ -510,7 +512,8 @@ export async function runAgentLoop(
rawResponse = await llm.getAction(
systemPrompt,
userPrompt + "\n\nIMPORTANT: Your previous response was not valid JSON. You MUST respond with ONLY a valid JSON object.",
useScreenshot ? screenshot : undefined
useScreenshot ? screenshot : undefined,
signal
);
parsed = parseJsonResponse(rawResponse);
} catch {
@@ -634,6 +637,7 @@ export async function runAgentLoop(
}
// ── 10. Brief pause for UI to settle ────────────────────
if (signal?.aborted) break;
await new Promise((r) => setTimeout(r, 500));
}
} catch (error) {