Skip to content

Commit fd2fc5c

Browse files
raphaeltmclaude
andcommitted
fix: prime message reporter on session restore so wake replies persist
The normal agent-session-create path (handleCreateAgentSession) sets runtime.ProjectID and creates/binds the per-workspace message reporter via getOrCreateReporter before the agent runs. The restore path only recreated the session host + SelectAgent, so the restored agent's streamed output had no reporter to enqueue to — replies were generated (ACP prompt completed) but never POSTed to /messages, so no answer appeared after wake. Restore now primes the reporter with the workspace's projectID (from the runtime or PROJECT_ID env) and the restored chatSessionID. Diagnosed from staging Worker logs: message POSTs present during setup, zero after wake despite ACP prompt completing with no auth errors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 44e8166 commit fd2fc5c

1 file changed

Lines changed: 32 additions & 0 deletions

File tree

packages/vm-agent/internal/server/session_snapshot.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,11 @@ func (s *Server) restoreSessionSnapshot(ctx context.Context, runtime *WorkspaceR
305305
if strings.TrimSpace(agentType) == "" {
306306
return nil, fmt.Errorf("agent type is required to restore a standalone session")
307307
}
308+
// Prime the per-workspace message reporter before the agent starts.
309+
// handleCreateAgentSession does this on the normal path; the restore path
310+
// skipped it, so the restored agent's output had no reporter to enqueue
311+
// to and chat replies were silently dropped after a wake.
312+
s.primeRestoredMessageReporter(runtime, chatSessionID)
308313
session, _, createErr := s.agentSessions.Create(runtime.ID, sessionID, "Restored session", "restore:"+sessionID)
309314
if createErr != nil {
310315
return nil, fmt.Errorf("recreate restored agent session: %w", createErr)
@@ -323,6 +328,33 @@ func (s *Server) restoreSessionSnapshot(ctx context.Context, runtime *WorkspaceR
323328
return map[string]interface{}{"status": "restored", "degradation": restore.Degradation}, nil
324329
}
325330

331+
// primeRestoredMessageReporter ensures the per-workspace message reporter exists
332+
// and is bound to the restored chat session before the agent starts producing
333+
// output. handleCreateAgentSession does this on the normal path; the restore
334+
// path must replicate it or the restored agent's replies are never enqueued and
335+
// are silently dropped after a wake.
336+
func (s *Server) primeRestoredMessageReporter(runtime *WorkspaceRuntime, chatSessionID string) {
337+
if runtime == nil {
338+
return
339+
}
340+
chatSessionID = strings.TrimSpace(chatSessionID)
341+
projectID := strings.TrimSpace(runtime.ProjectID)
342+
if projectID == "" {
343+
projectID = strings.TrimSpace(s.config.ProjectID)
344+
}
345+
if projectID == "" || chatSessionID == "" {
346+
return
347+
}
348+
s.workspaceMu.Lock()
349+
if rt, ok := s.workspaces[runtime.ID]; ok && strings.TrimSpace(rt.ProjectID) == "" {
350+
rt.ProjectID = projectID
351+
}
352+
s.workspaceMu.Unlock()
353+
if reporter := s.getOrCreateReporter(runtime.ID, projectID, chatSessionID); reporter != nil {
354+
reporter.SetSessionID(chatSessionID)
355+
}
356+
}
357+
326358
func (s *Server) prepareSnapshot(ctx context.Context, workspaceID, sessionID, chatSessionID, runtimeName, token string) (*snapshotPrepareResponse, error) {
327359
payload := map[string]string{"chatSessionId": chatSessionID, "agentSessionId": sessionID, "runtime": runtimeName}
328360
var out snapshotPrepareResponse

0 commit comments

Comments
 (0)