From d1ea285bc4fe2ff2867b5e55e9a10a5329be10db Mon Sep 17 00:00:00 2001 From: SaladDay <1203511142@qq.com> Date: Wed, 7 Oct 2026 17:38:12 +0000 Subject: [PATCH] Reach the live cold continuations the way Core does The MCP bearer test released the Executor with execution_release after the Run had started, which never retires it, so the cold step failed. It now drops the connection and binds again, so the daemon's Router closes the Executor on shutdown and the next Run starts a fresh native process. The registered Claude SDK test failed on the non-terminal preparing and starting statuses, and resumed with require_existing_native_session, which Core sends only to recover a Turn whose native identity is unknown. It now fails only on terminal statuses and resumes by native identity. Both pass live against MiniMax. --- .../cli/claude_sdk_live_linux_test.go | 5 ++- .../mcp_bearer_live_linux_test.go | 32 +++++++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/apps/daemon/internal/cli/claude_sdk_live_linux_test.go b/apps/daemon/internal/cli/claude_sdk_live_linux_test.go index c2e8dd5a7..ad0bb7948 100644 --- a/apps/daemon/internal/cli/claude_sdk_live_linux_test.go +++ b/apps/daemon/internal/cli/claude_sdk_live_linux_test.go @@ -90,7 +90,7 @@ func TestLiveRegisteredClaudeSDK(t *testing.T) { ctx, cancel := context.WithTimeout(t.Context(), 120*time.Second) defer cancel() id := uuid.NewString() - request := proto.PromptRequestPayload{AgentKind: "claude_sdk", AgentStateKey: prototest.StateKey, AgentSessionID: resume, RequireExistingNativeSession: resume != "", ObserveMessages: true, DisableExecutionEnvironment: true, DisableSubagents: true, ExecutionControls: &proto.ExecutionControls{WebSearch: "disabled", TextVerbosity: "medium"}, Model: "MiniMax-M3", ModelProvider: provider} + request := proto.PromptRequestPayload{AgentKind: "claude_sdk", AgentStateKey: prototest.StateKey, AgentSessionID: resume, ObserveMessages: true, DisableExecutionEnvironment: true, DisableSubagents: true, ExecutionControls: &proto.ExecutionControls{WebSearch: "disabled", TextVerbosity: "medium"}, Model: "MiniMax-M3", ModelProvider: provider} if callFunction { request.FunctionTools = []proto.FunctionTool{{Name: "lookup", Description: "Return a verification value.", Parameters: json.RawMessage(`{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}`)}} } @@ -134,8 +134,7 @@ func TestLiveRegisteredClaudeSDK(t *testing.T) { switch status.State { case "ready": send(proto.TypeExecutionStart, "prepare", proto.ExecutionStartPayload{Handle: status.Handle, ExecutorID: status.ExecutorID, RunID: id, Input: proto.TextInput(prompt)}) - case "started": - default: + case "rejected", "failed", "expired", "released": t.Fatal("registered preparation failed", status) } continue diff --git a/services/core/internal/runtimegateway/mcp_bearer_live_linux_test.go b/services/core/internal/runtimegateway/mcp_bearer_live_linux_test.go index cff41637b..f33f76206 100644 --- a/services/core/internal/runtimegateway/mcp_bearer_live_linux_test.go +++ b/services/core/internal/runtimegateway/mcp_bearer_live_linux_test.go @@ -87,6 +87,27 @@ func TestLiveMCPBearerGatewayColdContinuation(t *testing.T) { if err := peer.Bind(ctx, assignment, ""); err != nil { t.Fatal("built daemon did not bind the Session's assignment") } + // reconnect drops the connection: the daemon's Router closes the Session's + // Executor on shutdown, so the next Run starts a fresh native process. + reconnect := func() { + t.Helper() + old := peer + old.Close("cold continuation") + for peer == old { + next, err := registry.WaitForDevice(ctx, id, 30*time.Second) + if err != nil { + t.Fatal("built daemon did not reconnect through the real gateway") + } + if next == old { + time.Sleep(50 * time.Millisecond) + continue + } + peer = next + } + if err := peer.Bind(ctx, assignment, ""); err != nil { + t.Fatal("built daemon did not bind the Session's assignment again") + } + } run := func(prompt, resume string, expected map[string]string) *mcpBearerTurn { t.Helper() turn := &mcpBearerTurn{} @@ -100,7 +121,8 @@ func TestLiveMCPBearerGatewayColdContinuation(t *testing.T) { defer peer.Unsubscribe(runID) control := mcpBearerStart(t, ctx, peer, assignment, request, runID, proto.TextInput(prompt)) mcpBearerCollectTurn(t, ctx, sub, runID, turn, expected, token, provider) - control.release() + peer.UnsubscribePreparation(control.id) + reconnect() turn.NativeLaunches = mcpBearerReleased(t, root) turn.BearerEnvironmentReference = mcpBearerConfigReference(t, root, token) return turn @@ -180,14 +202,6 @@ func (c *mcpBearerControl) await(state string) { } } -// release closes the Executor, so the next Run starts a fresh native process. -func (c *mcpBearerControl) release() { - c.t.Helper() - defer c.peer.UnsubscribePreparation(c.id) - c.send(proto.TypeExecutionRelease, proto.ExecutionReleasePayload{Handle: c.status.Handle}) - c.await("released") -} - func mcpBearerCollectTurn(t *testing.T, ctx context.Context, sub *Subscription, runID string, turn *mcpBearerTurn, expected map[string]string, secrets ...string) { t.Helper() before, after := make(map[string]string), make(map[string]int)