feat(ssa): Agent channel UX optimization (Solution B) + Plan-and-Execute architecture design

SSA Agent channel improvements (12 code files, +931/-203 lines):
- Solution B: left/right separation of concerns (gaze guiding + state mutex + time-travel)
- JWT token refresh mechanism (ensureFreshToken) to fix HTTP 401 during pipeline
- Code truncation fix: LLM maxTokens 4000->8000 + CSS max-height 60vh
- Retry streaming code generation with generateCodeStream()
- R Docker structured errors: 20+ pattern matching + format_agent_error + line extraction
- Prompt iron rules: strict output format in CoderAgent System Prompt
- parseCode robustness: XML/Markdown/inference 3-tier matching + length validation
- consoleOutput type defense: handle both array and scalar from R Docker unboxedJSON
- Agent progress bar sync: derive phase from agentExecution.status
- Export report / view code buttons restored for Agent mode
- ExecutingProgress component: real-time timer + dynamic tips + step pulse animation

Architecture design (3 review reports):
- Plan-and-Execute step-by-step execution architecture approved
- Code accumulation strategy (R Docker stays stateless)
- 5 engineering guardrails: XML tags, AST pre-check, defensive prompts, high-fidelity schema, error classification circuit breaker

Docs: update SSA module status v4.1, system status v6.7, deployment changelist
Made-with: Cursor
This commit is contained in:
2026-03-07 22:32:32 +08:00
parent 87655ea7e6
commit 52989cd03f
18 changed files with 1334 additions and 230 deletions

View File

@@ -14,6 +14,8 @@ export const SSACodeModal: React.FC = () => {
addToast,
currentRecordId,
analysisHistory,
executionMode,
agentExecution,
} = useSSAStore();
const [code, setCode] = useState<string>('');
@@ -27,26 +29,31 @@ export const SSACodeModal: React.FC = () => {
if (!codeModalVisible) return;
setIsLoading(true);
try {
const steps = record?.steps ?? [];
const successSteps = steps.filter(
(s) => (s.status === 'success' || s.status === 'warning') && s.result
);
if (successSteps.length > 0) {
const allCode = successSteps
.map((s) => {
const stepCode = (s.result as any)?.reproducible_code;
const header = `# ========================================\n# 步骤 ${s.step_number}: ${s.tool_name}\n# ========================================\n`;
return header + (stepCode || '# 该步骤暂无可用代码');
})
.join('\n\n');
setCode(allCode);
if (executionMode === 'agent' && agentExecution?.generatedCode) {
const header = `# ========================================\n# Agent 生成的 R 代码\n# 分析任务: ${agentExecution.query || '统计分析'}\n# ========================================\n`;
setCode(header + agentExecution.generatedCode);
} else {
setCode('# 暂无可用代码\n# 请先执行分析');
const steps = record?.steps ?? [];
const successSteps = steps.filter(
(s) => (s.status === 'success' || s.status === 'warning') && s.result
);
if (successSteps.length > 0) {
const allCode = successSteps
.map((s) => {
const stepCode = (s.result as any)?.reproducible_code;
const header = `# ========================================\n# 步骤 ${s.step_number}: ${s.tool_name}\n# ========================================\n`;
return header + (stepCode || '# 该步骤暂无可用代码');
})
.join('\n\n');
setCode(allCode);
} else {
setCode('# 暂无可用代码\n# 请先执行分析');
}
}
} finally {
setIsLoading(false);
}
}, [codeModalVisible, record]);
}, [codeModalVisible, record, executionMode, agentExecution]);
if (!codeModalVisible) return null;
@@ -56,7 +63,10 @@ export const SSACodeModal: React.FC = () => {
const now = new Date();
const pad = (n: number) => n.toString().padStart(2, '0');
const ts = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}_${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
const title = (record?.plan?.title || 'analysis')
const rawTitle = executionMode === 'agent'
? (agentExecution?.query || 'agent_analysis')
: (record?.plan?.title || 'analysis');
const title = rawTitle
.replace(/[^a-zA-Z0-9\u4e00-\u9fa5_-]/g, '_')
.slice(0, 30);
return `SSA_${title}_${ts}.R`;