feat(ssa): Implement dual-channel architecture Phase 1-3 (QPER + LLM Agent pipeline)
Completed: - Phase 1: DB schema (execution_mode + ssa_agent_executions), ModeToggle component, Session PATCH API - Phase 2: AgentPlannerService + AgentCoderService (streaming) + CodeRunnerService + R Docker /execute-code endpoint - Phase 3: AgentCodePanel (3-step confirmation UI), SSE event handling (7 agent events), streaming code display - Three-step confirmation pipeline: plan -> user confirm -> stream code -> user confirm -> execute R code -> results - R Docker sandbox /execute-code endpoint with 120s timeout + block_helpers preloaded - E2E dual-channel test script (8 tests) - Updated R engine architecture doc (v1.5) and SSA module status doc (v4.0) Technical details: - AgentCoderService uses LLM streaming (chatStream) for real-time code generation feedback - ReviewerAgent temporarily disabled, prioritizing Plan -> Code -> Execute flow - CodeRunnerService wraps user code with auto data loading (df variable injection) - Frontend handles agent_planning, agent_plan_ready, code_generating, code_generated, code_executing, code_result events - ask_user mechanism used for plan and code confirmation steps Files: 24 files (4 new services, 2 new components, 1 migration, 1 E2E test, 16 modified) Made-with: Cursor
This commit is contained in:
@@ -257,6 +257,88 @@ export function useSSAChat(): UseSSAChatReturn {
|
||||
continue;
|
||||
}
|
||||
|
||||
// ── Agent 通道 SSE 事件 ──
|
||||
|
||||
if (parsed.type === 'agent_planning') {
|
||||
const { setAgentExecution, setWorkspaceOpen, setActivePane } = useSSAStore.getState();
|
||||
setAgentExecution({
|
||||
id: parsed.executionId || crypto.randomUUID(),
|
||||
sessionId: '',
|
||||
query: content,
|
||||
retryCount: 0,
|
||||
status: 'planning',
|
||||
});
|
||||
setActivePane('execution');
|
||||
setWorkspaceOpen(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parsed.type === 'agent_plan_ready') {
|
||||
const { updateAgentExecution } = useSSAStore.getState();
|
||||
updateAgentExecution({
|
||||
planText: parsed.planText,
|
||||
planSteps: parsed.plan?.steps,
|
||||
status: 'plan_pending',
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parsed.type === 'code_generating') {
|
||||
const { updateAgentExecution } = useSSAStore.getState();
|
||||
updateAgentExecution({
|
||||
partialCode: parsed.partialCode,
|
||||
status: 'coding',
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parsed.type === 'code_generated') {
|
||||
const { updateAgentExecution } = useSSAStore.getState();
|
||||
updateAgentExecution({
|
||||
generatedCode: parsed.code,
|
||||
partialCode: undefined,
|
||||
status: parsed.code ? 'code_pending' : 'coding',
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parsed.type === 'code_executing') {
|
||||
const { updateAgentExecution } = useSSAStore.getState();
|
||||
updateAgentExecution({ status: 'executing' });
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parsed.type === 'code_result') {
|
||||
const { updateAgentExecution } = useSSAStore.getState();
|
||||
updateAgentExecution({
|
||||
reportBlocks: parsed.reportBlocks,
|
||||
generatedCode: parsed.code || useSSAStore.getState().agentExecution?.generatedCode,
|
||||
status: 'completed',
|
||||
durationMs: parsed.durationMs,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parsed.type === 'code_error') {
|
||||
const { updateAgentExecution } = useSSAStore.getState();
|
||||
updateAgentExecution({
|
||||
status: 'error',
|
||||
errorMessage: parsed.message,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parsed.type === 'code_retry') {
|
||||
const { updateAgentExecution } = useSSAStore.getState();
|
||||
updateAgentExecution({
|
||||
status: 'coding',
|
||||
retryCount: parsed.retryCount || 0,
|
||||
generatedCode: parsed.code,
|
||||
errorMessage: undefined,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// 错误事件
|
||||
if (parsed.type === 'error') {
|
||||
const errMsg = parsed.message || '处理消息时发生错误';
|
||||
|
||||
Reference in New Issue
Block a user