Revert "fix: Spawn chat agent in background to avoid blocking event loop"

This reverts commit 8ee02f6013.
This commit is contained in:
Lukas May
2026-03-04 12:07:00 +01:00
parent 8ee02f6013
commit 70fd996fa1

View File

@@ -8,6 +8,8 @@ import type { ProcedureBuilder } from '../trpc.js';
import { import {
requireAgentManager, requireAgentManager,
requireInitiativeRepository, requireInitiativeRepository,
requirePhaseRepository,
requirePageRepository,
requireTaskRepository, requireTaskRepository,
requireChatSessionRepository, requireChatSessionRepository,
} from './_helpers.js'; } from './_helpers.js';
@@ -81,12 +83,22 @@ export function chatSessionProcedures(publicProcedure: ProcedureBuilder) {
} }
} }
// Gather data needed for spawn (fast DB reads) before returning // Spawn fresh agent with chat history + context
const messages = await chatRepo.findMessagesBySessionId(session.id); const messages = await chatRepo.findMessagesBySessionId(session.id);
const chatHistory: ChatHistoryEntry[] = messages const chatHistory: ChatHistoryEntry[] = messages
.slice(-MAX_HISTORY_MESSAGES) .slice(-MAX_HISTORY_MESSAGES)
.map(m => ({ role: m.role as 'user' | 'assistant' | 'system', content: m.content })); .map(m => ({ role: m.role as 'user' | 'assistant' | 'system', content: m.content }));
const context = await gatherInitiativeContext(
ctx.phaseRepository,
ctx.taskRepository,
ctx.pageRepository,
input.initiativeId,
);
const prompt = buildChatPrompt(input.targetType, input.targetId, chatHistory, input.message);
// Create a task for the chat agent
const targetName = input.targetType === 'phase' const targetName = input.targetType === 'phase'
? (await ctx.phaseRepository?.findById(input.targetId))?.name ?? input.targetId ? (await ctx.phaseRepository?.findById(input.targetId))?.name ?? input.targetId
: (await ctx.taskRepository?.findById(input.targetId))?.name ?? input.targetId; : (await ctx.taskRepository?.findById(input.targetId))?.name ?? input.targetId;
@@ -99,68 +111,34 @@ export function chatSessionProcedures(publicProcedure: ProcedureBuilder) {
status: 'in_progress', status: 'in_progress',
}); });
const prompt = buildChatPrompt(input.targetType, input.targetId, chatHistory, input.message); // Determine target phase/task for input context
const targetPhase = input.targetType === 'phase'
? await ctx.phaseRepository?.findById(input.targetId)
: undefined;
const targetTask = input.targetType === 'task'
? await ctx.taskRepository?.findById(input.targetId)
: undefined;
// Spawn agent in background — worktree creation + file I/O is heavy const agent = await agentManager.spawn({
// and blocks the event loop, causing ECONNREFUSED on the SSE connection. taskId: task.id,
// The UI detects the agent via SSE events (agent:spawned) + query invalidation. prompt,
const sessionId = session.id; mode: 'chat',
void (async () => { provider: input.provider,
try { initiativeId: input.initiativeId,
const context = await gatherInitiativeContext( inputContext: {
ctx.phaseRepository, initiative,
ctx.taskRepository, phase: targetPhase ?? undefined,
ctx.pageRepository, task: targetTask ?? undefined,
input.initiativeId, pages: context.pages.length > 0 ? context.pages : undefined,
); phases: context.phases.length > 0 ? context.phases : undefined,
tasks: context.tasks.length > 0 ? context.tasks : undefined,
},
});
const targetPhase = input.targetType === 'phase' // Link agent to session
? await ctx.phaseRepository?.findById(input.targetId) await chatRepo.updateSession(session.id, { agentId: agent.id });
: undefined;
const targetTask = input.targetType === 'task'
? await ctx.taskRepository?.findById(input.targetId)
: undefined;
const agent = await agentManager.spawn({ return { sessionId: session.id, agentId: agent.id, action: 'spawned' as const };
taskId: task.id,
prompt,
mode: 'chat',
provider: input.provider,
initiativeId: input.initiativeId,
inputContext: {
initiative,
phase: targetPhase ?? undefined,
task: targetTask ?? undefined,
pages: context.pages.length > 0 ? context.pages : undefined,
phases: context.phases.length > 0 ? context.phases : undefined,
tasks: context.tasks.length > 0 ? context.tasks : undefined,
},
});
await chatRepo.updateSession(sessionId, { agentId: agent.id });
ctx.eventBus.emit({
type: 'chat:message_created' as const,
timestamp: new Date(),
payload: { chatSessionId: sessionId, role: 'system' as const },
});
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
// Store error as system message so the UI can display it
await chatRepo.createMessage({
chatSessionId: sessionId,
role: 'system',
content: `Failed to start agent: ${msg}`,
});
ctx.eventBus.emit({
type: 'chat:message_created' as const,
timestamp: new Date(),
payload: { chatSessionId: sessionId, role: 'system' as const },
});
}
})();
return { sessionId: session.id, agentId: null, action: 'spawned' as const };
}), }),
getChatSession: publicProcedure getChatSession: publicProcedure