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:
2026-03-02 22:23:54 +08:00
parent 71d32d11ee
commit aadceb5cde
24 changed files with 2694 additions and 56 deletions

View File

@@ -43,6 +43,7 @@ import { ClarificationCard } from './ClarificationCard';
import { AskUserCard } from './AskUserCard';
import type { AskUserResponseData } from './AskUserCard';
import { ThinkingBlock } from '@/shared/components/Chat';
import { ModeToggle } from './ModeToggle';
import type { ClarificationCardData, IntentResult } from '../types';
export const SSAChatPane: React.FC = () => {
@@ -285,14 +286,17 @@ export const SSAChatPane: React.FC = () => {
{currentSession?.title || '新的统计分析'}
</span>
</div>
<EngineStatus
isExecuting={isExecuting}
isLoading={isLoading || isPlanLoading}
isUploading={uploadStatus === 'uploading' || uploadStatus === 'parsing'}
isProfileLoading={isProfileLoading || dataProfileLoading}
isStreaming={isGenerating}
streamIntent={currentIntent}
/>
<div className="chat-header-right">
{currentSession && <ModeToggle />}
<EngineStatus
isExecuting={isExecuting}
isLoading={isLoading || isPlanLoading}
isUploading={uploadStatus === 'uploading' || uploadStatus === 'parsing'}
isProfileLoading={isProfileLoading || dataProfileLoading}
isStreaming={isGenerating}
streamIntent={currentIntent}
/>
</div>
</header>
{/* Chat Messages */}