feat(ssa): Complete Phase V-A editable analysis plan variables
Features: - Add editable variable selection in workflow plan (SingleVarSelect + MultiVarTags) - Implement 3-layer flexible interception (warning bar + icon + blocking dialog) - Add tool_param_constraints.json for 12 statistical tools parameter validation - Add PATCH /workflow/:id/params API with Zod structural validation - Implement synchronous parameter sync before execution (Promise chaining) - Fix LLM hallucination by strict system prompt constraints - Fix DynamicReport object-based rows compatibility (R baseline_table) - Fix Word export row.map error with same normalization logic - Restore inferGroupingVar for smart default variable selection - Add ReactMarkdown rendering in SSAChatPane - Update SSA module status document to v3.5 Modified files: - backend: workflow.routes, ChatHandlerService, SystemPromptService, FlowTemplateService - frontend: WorkflowTimeline, SSAWorkspacePane, DynamicReport, SSAChatPane, ssaStore, ssa.css - config: tool_param_constraints.json (new) - docs: SSA status doc, team review reports Tested: Cohort study end-to-end execution + report export verified Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -35,6 +35,8 @@ import { useWorkflow } from '../hooks/useWorkflow';
|
||||
import { useSSAChat } from '../hooks/useSSAChat';
|
||||
import type { ChatMessage, ChatIntentType } from '../hooks/useSSAChat';
|
||||
import type { SSAMessage } from '../types';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import { TypeWriter } from './TypeWriter';
|
||||
import { DataProfileCard } from './DataProfileCard';
|
||||
import { ClarificationCard } from './ClarificationCard';
|
||||
@@ -65,13 +67,12 @@ export const SSAChatPane: React.FC = () => {
|
||||
} = useSSAStore();
|
||||
|
||||
const { uploadData, generatePlan, isUploading, uploadProgress } = useAnalysis();
|
||||
const { generateDataProfile, handleClarify, executeWorkflow, isProfileLoading, isPlanLoading } = useWorkflow();
|
||||
const { generateDataProfile, handleClarify, isProfileLoading, isPlanLoading } = useWorkflow();
|
||||
const {
|
||||
chatMessages,
|
||||
isGenerating,
|
||||
currentIntent,
|
||||
pendingQuestion,
|
||||
pendingPlanConfirm,
|
||||
sendChatMessage,
|
||||
respondToQuestion,
|
||||
skipQuestion,
|
||||
@@ -91,15 +92,6 @@ export const SSAChatPane: React.FC = () => {
|
||||
const chatEndRef = useRef<HTMLDivElement>(null);
|
||||
const messagesContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Phase IV: plan_confirmed → 自动触发 executeWorkflow
|
||||
useEffect(() => {
|
||||
if (pendingPlanConfirm?.workflowId && currentSession?.id) {
|
||||
executeWorkflow(currentSession.id, pendingPlanConfirm.workflowId).catch((err: any) => {
|
||||
addToast(err?.message || '执行失败', 'error');
|
||||
});
|
||||
}
|
||||
}, [pendingPlanConfirm, currentSession?.id, executeWorkflow, addToast]);
|
||||
|
||||
// Phase II: session 切换时加载对话历史
|
||||
useEffect(() => {
|
||||
if (currentSession?.id) {
|
||||
@@ -417,7 +409,11 @@ export const SSAChatPane: React.FC = () => {
|
||||
<span>{msg.content}</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="chat-msg-content">{msg.content}</div>
|
||||
<div className="chat-msg-content">
|
||||
<ReactMarkdown remarkPlugins={[remarkGfm]}>
|
||||
{msg.content}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user