From c3de9d6e4d927ffa14ed4db5f83f92b81c25b5a1 Mon Sep 17 00:00:00 2001 From: lyon Date: Sat, 20 Jun 2026 10:26:50 +0800 Subject: [PATCH] fix: allow provider profile recovery after thread resume failure --- internal/cloud/server-code-agent-http.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/internal/cloud/server-code-agent-http.ts b/internal/cloud/server-code-agent-http.ts index 0db441c7..cf5a93b8 100644 --- a/internal/cloud/server-code-agent-http.ts +++ b/internal/cloud/server-code-agent-http.ts @@ -377,7 +377,8 @@ async function prepareManualCodeAgentSession({ params, options, traceId, respons sendJson(response, 404, manualSessionErrorPayload({ code: "session_not_found", message: "Code Agent session is not visible to the current actor.", traceId, sessionId })); return { blocked: true }; } - if (!manualSessionUsable(session.status)) { + const profileRecovery = manualSessionProfileRecoveryAllowed(session, params); + if (!manualSessionUsable(session.status) && !profileRecovery) { sendJson(response, 409, manualSessionErrorPayload({ code: "session_not_usable", message: `Code Agent session ${sessionId} is ${session.status}; create a new session before continuing.`, traceId, sessionId, session })); return { blocked: true }; } @@ -401,10 +402,25 @@ async function prepareManualCodeAgentSession({ params, options, traceId, respons params.conversationId = conversationId; params.sessionId = sessionId; params.projectId = requestedProjectId || sessionProjectId || DEFAULT_CODE_AGENT_PROJECT_ID; - params.threadId = safeOpaqueId(params.threadId) || safeOpaqueId(session.threadId) || undefined; + params.threadId = profileRecovery ? undefined : safeOpaqueId(params.threadId) || safeOpaqueId(session.threadId) || undefined; return { session }; } +function manualSessionProfileRecoveryAllowed(session, params = {}) { + const status = String(session?.status ?? "").trim().toLowerCase().replace(/_/gu, "-"); + if (status !== "thread-resume-failed") return false; + const requestedProfile = manualSessionProviderProfileToken(params.providerProfile ?? params.codeAgentProviderProfile); + const sessionProfile = manualSessionProviderProfileToken(session?.session?.providerProfile); + return Boolean(requestedProfile && sessionProfile && requestedProfile !== sessionProfile); +} + +function manualSessionProviderProfileToken(value) { + const profile = String(value ?? "").trim().toLowerCase(); + if (!profile || profile === "runtime-default") return ""; + if (profile === "codex-api") return "codex"; + return profile; +} + async function getVisibleManualAgentSession(options, sessionId) { if (!safeSessionId(sessionId) || !options.actor?.id || !options.accessController?.getAgentSession) return null; const session = await options.accessController.getAgentSession(sessionId);