mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:10:44 +00:00
fix(agents): classify connection-mismatch replay errors as replay-invalid (#66475)
Merged via squash.
Prepared head SHA: 97738583de
Co-authored-by: dallylee <132358482+dallylee@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
This commit is contained in:
@@ -9,6 +9,7 @@ Docs: https://docs.openclaw.ai
|
||||
### Fixes
|
||||
|
||||
- Gateway/tools: anchor trusted local `MEDIA:` tool-result passthrough on the exact raw name of this run's registered built-in tools, and reject client tool definitions whose names normalize-collide with a built-in or with another client tool in the same request (`400 invalid_request_error` on both JSON and SSE paths), so a client-supplied tool named like a built-in can no longer inherit its local-media trust. (#67303)
|
||||
- Agents/replay recovery: classify the provider wording `401 input item ID does not belong to this connection` as replay-invalid, so users get the existing `/new` session reset guidance instead of a raw 401-style failure. (#66475) Thanks @dallylee.
|
||||
|
||||
## 2026.4.15-beta.1
|
||||
|
||||
|
||||
@@ -70,6 +70,12 @@ describe("formatAssistantErrorText", () => {
|
||||
expect(result).toContain("Session history looks corrupted");
|
||||
expect(result).toContain("/new");
|
||||
});
|
||||
it("returns a recovery hint for replay-invalid connection mismatch errors", () => {
|
||||
const msg = makeAssistantError("401 input item ID does not belong to this connection");
|
||||
const result = formatAssistantErrorText(msg);
|
||||
expect(result).toContain("Session history or replay state is invalid");
|
||||
expect(result).toContain("/new");
|
||||
});
|
||||
it("handles JSON-wrapped role errors", () => {
|
||||
const msg = makeAssistantError('{"error":{"message":"400 Incorrect role information"}}');
|
||||
const result = formatAssistantErrorText(msg);
|
||||
|
||||
@@ -1195,6 +1195,9 @@ describe("classifyProviderRuntimeFailureKind", () => {
|
||||
expect(classifyProviderRuntimeFailureKind("tool_use.input: Field required")).toBe(
|
||||
"replay_invalid",
|
||||
);
|
||||
expect(
|
||||
classifyProviderRuntimeFailureKind("401 input item ID does not belong to this connection"),
|
||||
).toBe("replay_invalid");
|
||||
});
|
||||
|
||||
it("does not classify generic config errors that mention proxy settings as proxy failures", () => {
|
||||
|
||||
@@ -320,7 +320,7 @@ const DNS_ERROR_RE = /\benotfound\b|\beai_again\b|\bgetaddrinfo\b|\bno such host
|
||||
const INTERRUPTED_NETWORK_ERROR_RE =
|
||||
/\beconnrefused\b|\beconnreset\b|\beconnaborted\b|\benetreset\b|\behostunreach\b|\behostdown\b|\benetunreach\b|\bepipe\b|\bsocket hang up\b|\bconnection refused\b|\bconnection reset\b|\bconnection aborted\b|\bnetwork is unreachable\b|\bhost is unreachable\b|\bfetch failed\b|\bconnection error\b|\bnetwork request failed\b/i;
|
||||
const REPLAY_INVALID_RE =
|
||||
/\bprevious_response_id\b.*\b(?:invalid|unknown|not found|does not exist|expired|mismatch)\b|\btool_(?:use|call)\.(?:input|arguments)\b.*\b(?:missing|required)\b|\bincorrect role information\b|\broles must alternate\b/i;
|
||||
/\bprevious_response_id\b.*\b(?:invalid|unknown|not found|does not exist|expired|mismatch)\b|\btool_(?:use|call)\.(?:input|arguments)\b.*\b(?:missing|required)\b|\bincorrect role information\b|\broles must alternate\b|\binput item id does not belong to this connection\b/i;
|
||||
const SANDBOX_BLOCKED_RE =
|
||||
/\bapproval is required\b|\bapproval timed out\b|\bapproval was denied\b|\bblocked by sandbox\b|\bsandbox\b.*\b(?:blocked|denied|forbidden|disabled|not allowed)\b/i;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user