Repository navigation
Conversation
|
I just lost half my monthly credits due to this, while some of the linked issues date back to Feb. Any ideas how to expedite the PR? Resorting back to custom loop-detection hooks in the meantime, I guess. |
|
feel your pain, been hitting this too. hopefully someone from the team sees this soon |
|
hey team, just a friendly bump on this one. the doom loop issue is still causing issues for users (see comment above) and the fix is pretty small. happy to make any changes if needed, just let me know. |
…urrent message Count repeated identical tool calls across the full (compaction-filtered) message history rather than only the trailing parts of the current assistant message, so a doom loop is detected even when the repeats span multiple assistant messages. Ported from anomalyco#32089 (adapted for the Effect layer). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
Would love this fixed, it's pretty much the only flaw im having with Qwen models, so being able to kill it would be huge. |
| @@ -350,21 +516,18 @@ const layer = Layer.effect( | |||
| : value.providerMetadata, | |||
| })) | |||
|
|
|||
| const parts = yield* MessageV2.parts(ctx.assistantMessage.id).pipe( | |||
| const msgs = yield* MessageV2.filterCompactedEffect(ctx.sessionID).pipe( | |||
There was a problem hiding this comment.
Unsure of this, but I think filterCompactedEffect() loads all messages for the session, so it might be better to query the last X number of messages instead:
yield* MessageV2.page({
sessionID: ctx.sessionID,
limit: DOOM_LOOP_MESSAGES,
})
Issue for this PR
Closes #25254
Type of change
What does this PR do?
The doom loop detection in processor.ts had two bugs:
Scope limited to current message only: MessageV2.parts(ctx.assistantMessage.id) only returns parts from the current assistant message. When a model repeats the same tool call across multiple messages (e.g. three separate turns each calling
ead_file with the same path), the doom loop check silently passes because each individual message has fewer than 3 matching parts.
Slice before filter inverts the logic: parts.slice(-3).every(...) takes the last 3 parts regardless of type, then checks if all 3 match. If any text or reasoning part appears in the tail, every returns false and the check passes even when there are plenty of repeated tool calls in the message.
Fix: use MessageV2.filterCompactedEffect(ctx.sessionID) to search all messages in the session (same function already used by the prompt loop), filter matching tool parts first, then check if the count reaches DOOM_LOOP_THRESHOLD.
How did you verify your code works?
Screenshots / recordings
Not applicable; logic-only change with no UI impact.
Checklist