Merge pull request #9 from ai-workspace-lab/fix/gateway-turn-stability-day1

fix(acp): session.prepare falls back on numeric gateway unknown-method codes
This commit is contained in:
Haitao Pan 2026-06-26 17:56:41 +08:00 committed by GitHub
commit 311db31e03
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 56 additions and 3 deletions

View File

@ -613,13 +613,19 @@ func (o *SessionOrchestrator) openClawArtifactPrepare(
func isOpenClawUnknownMethodError(errorPayload map[string]any, method string) bool {
message := strings.ToLower(strings.TrimSpace(shared.StringArg(errorPayload, "message", "")))
code := strings.ToUpper(strings.TrimSpace(shared.StringArg(errorPayload, "code", "")))
if message == "" {
return false
}
// 消息形如「unknown method: <method>」已明确指向「网关不认识该方法」,足以判定,
// 据此走 graceful fallback如 openClawFallbackSessionPreparePayload
//
// 注意:不能再用严格的 code 白名单来 gate。真实网关常以数字 JSON-RPC code
// (-32601 method not found / -32600 invalid request / -32002 等) 回传,
// 经 shared.StringArg(fmt.Sprint) 会被字符串化为 "-32601"/"-32002"
// 旧实现只接受 {"", INVALID_REQUEST, METHOD_NOT_FOUND},导致 fallback 失效、
// session.prepare 直接以 -32002 硬失败整轮任务。
return strings.Contains(message, "unknown method") &&
strings.Contains(message, strings.ToLower(strings.TrimSpace(method))) &&
(code == "" || code == "INVALID_REQUEST" || code == "METHOD_NOT_FOUND")
strings.Contains(message, strings.ToLower(strings.TrimSpace(method)))
}
func openClawFallbackSessionPreparePayload(params map[string]any) map[string]any {

View File

@ -282,3 +282,50 @@ func TestTaskGetArtifactExportReceivesRequiredArtifactExtensions(t *testing.T) {
t.Fatalf("expected expectedFileCountByExtension to reach export, got %#v", exportParams)
}
}
func TestIsOpenClawUnknownMethodErrorAcceptsNumericGatewayCodes(t *testing.T) {
const method = "xworkmate.session.prepare"
cases := []struct {
name string
payload map[string]any
want bool
}{
{
name: "string invalid_request code",
payload: map[string]any{"code": "INVALID_REQUEST", "message": "unknown method: xworkmate.session.prepare"},
want: true,
},
{
name: "numeric -32002 (real gateway shape that previously hard-failed)",
payload: map[string]any{"code": float64(-32002), "message": "unknown method: xworkmate.session.prepare"},
want: true,
},
{
name: "numeric -32601 method not found",
payload: map[string]any{"code": float64(-32601), "message": "Unknown method: xworkmate.session.prepare"},
want: true,
},
{
name: "empty code",
payload: map[string]any{"message": "unknown method: xworkmate.session.prepare"},
want: true,
},
{
name: "unrelated error must not be swallowed",
payload: map[string]any{"code": float64(-32002), "message": "gateway socket closed"},
want: false,
},
{
name: "unknown method for a different method name",
payload: map[string]any{"code": float64(-32601), "message": "unknown method: chat.send"},
want: false,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
if got := isOpenClawUnknownMethodError(tc.payload, method); got != tc.want {
t.Fatalf("isOpenClawUnknownMethodError(%v) = %v, want %v", tc.payload, got, tc.want)
}
})
}
}