* Summarize the combined history (base messages + this run's new messages), * collapsing all but the most recent turns into one summary system message. * * Returns the NEW combined message list, or null if compaction didn't run * (below threshold, or summarization failed — caller keeps t
(
combined: Message[],
ctxWindow: number,
signal: AbortSignal | undefined,
)
| 2485 | // first. Advisory only (doesn't skip execution); the soft-failure loop detector is the real |
| 2486 | // circuit-breaker if the model ignores this and starts thrashing. |
| 2487 | if (!userAskedExecution && !scopeNudged) { |
| 2488 | const wandering = toolCalls.find(tc => |
| 2489 | isExecutionAction(tc.function.name, tc.function.arguments ?? ''), |
| 2490 | ); |
| 2491 | if (wandering) { |
| 2492 | scopeNudged = true; |
| 2493 | const smsg: Message = { |
| 2494 | role: 'user', |
| 2495 | content: |
| 2496 | '[SYSTEM] The user asked you to write/redesign code, not to run a dev server or install ' + |
| 2497 | 'packages. Finish and save the file changes, then report what you changed in a short ' + |
| 2498 | 'summary. Do NOT start dev servers, install dependencies, or debug the environment unless ' + |
| 2499 | 'the user explicitly asks — those steps are out of scope and waste time.', |
| 2500 | }; |
| 2501 | newMessages.push(smsg); |
| 2502 | sessionStore.recordTurn(sessionId, [smsg], { input: 0, output: 0, costUsd: 0 }); |
| 2503 | } |
| 2504 | } |
| 2505 | |
| 2506 | const errLoop = detectErrorLoop(recentErrors); |
| 2507 | if (errLoop) { |
| 2508 | let advice = ' Change approach instead of repeating the same kind of call.'; |
| 2509 | if (errLoop.code === 'FILE_NOT_FOUND') { |
| 2510 | advice = |
| 2511 | ' STOP guessing file paths. The "did you mean …" suggestions in the errors show the REAL ' + |
| 2512 | 'names — this project likely uses different extensions than you assume (e.g. .jsx, not .tsx). ' + |
| 2513 | 'Run `glob` or `ls` to get exact paths, then read those. Do not keep trying filename variations.'; |
| 2514 | } |
| 2515 | const msg: Message = { |
| 2516 | role: 'user', |
| 2517 | content: |
| 2518 | `[SYSTEM] \`${errLoop.name}\` has returned ${errLoop.code} ${errLoop.count} times with different ` + |
| 2519 | `arguments.${advice} If you genuinely can't proceed, say so in ONE sentence and stop. Do not loop.`, |
| 2520 | }; |
| 2521 | // Answer the just-emitted tool_calls before skipping execution, or the assistant's |
| 2522 | // tool_calls are orphaned and OpenAI-format providers 400 on the next request. |
| 2523 | if (toolCalls.length > 0) { |
| 2524 | const skipped = skippedToolResults(toolCalls, 'loop guard: same error kind repeated'); |
no test coverage detected