mirror of
https://github.com/multica-ai/multica.git
synced 2026-08-02 18:13:27 +02:00
A conversation whose resume kept failing could only be recognised by matching the provider's error text. That works for Anthropic's own 400 invalid_request_error shape and for the empty-message wordings added since, but the compatible-gateway ecosystem has no contract on error text: vendor codes live in the vendor's namespace, HTTP 400 covers both a poisoned transcript and plain misconfiguration, and any of it can be reworded or localised at will. So an unrecognised rejection meant "safe to resume" by omission, and the (agent, issue) pair was bricked permanently — every later trigger resumed the same dead conversation. Manual rerun did not help either: that path resolves its session from the source task and applies the same text-based predicate. Deleting the task's workdir on the host was the only way out (GH #6143). This is the fourth report of this shape after GH #5975, #6066 and #5760, each previously closed by adding another pattern. Conclude it from behaviour instead. Two consecutive non-transient failures on one (agent, issue) pair with no success in between retire the conversation, so the next run starts clean. No error text is parsed, which is what makes it hold for a wording nobody has seen yet. The first failure still resumes: an unrecognised error is not yet evidence that the transcript is at fault, and restarting on every first stumble would discard context whenever a provider hiccupped. Transient reasons (daemon offline, rate limit, provider 5xx, queue expiry) are skipped without resetting the count, so a flaky daemon can neither trip the breaker nor mask a genuinely dead session. Counting is keyed on (agent, issue) rather than session_id because ACP backends may answer a resume with a different id, and a run that dies early records none; keying on the id would restart the count in exactly the case this exists for. Every id seen in the window is retired together. Decided server-side, in FailTask, ahead of the retry pre-compute and the chat-pointer writes so both observe the upgraded reason. Daemons upgrade on their own cadence, and the sibling fixes above have already been reissued once for hosts that never picked them up. Reuses the existing retired_session_id mechanism, so no migration. Also closes two gaps the same behaviour would otherwise widen: the manual-rerun path never consulted the retired-session set, and the breaker would have dropped conversations silently — it now raises the same PriorSessionResumeUnavailable disclosure as MUL-5305. Scoped to issue tasks; chat sessions keep their existing handling. Co-authored-by: multica-agent <github@multica.ai>