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:
@@ -239,7 +239,8 @@ export class ChatHandlerService {
|
||||
const toolOutputs = [
|
||||
guardToolOutput,
|
||||
planSummary,
|
||||
'[系统提示] 你刚刚为用户制定了上述分析方案。请用自然语言向用户解释这个方案:包括为什么选这些方法、分析步骤的逻辑。不要重复列步骤编号和工具代码,要用用户能理解的语言说明。最后提示用户确认方案后即可执行。',
|
||||
'[系统指令] 你刚刚为用户制定了上述分析方案。请用自然语言向用户解释这个方案:包括为什么选这些方法、分析步骤的逻辑。不要重复列步骤编号和工具代码,要用用户能理解的语言说明。最后提示用户确认方案后即可执行。',
|
||||
'【禁止事项】不要预测、模拟或编造任何分析结果、数值或表格。方案只是计划,R 引擎尚未执行,你不知道结果是什么。',
|
||||
].filter(Boolean).join('\n\n');
|
||||
|
||||
const messages = await conversationService.buildContext(
|
||||
@@ -397,7 +398,9 @@ export class ChatHandlerService {
|
||||
writer: StreamWriter,
|
||||
placeholderMessageId: string,
|
||||
): Promise<HandleResult> {
|
||||
// 清除 pending 状态
|
||||
// 先读取 pending 元数据(含 workflowId),再清除
|
||||
const pending = await askUserService.getPending(sessionId);
|
||||
const pendingMeta = pending?.metadata || {};
|
||||
await askUserService.clearPending(sessionId);
|
||||
|
||||
if (response.action === 'skip') {
|
||||
@@ -423,15 +426,21 @@ export class ChatHandlerService {
|
||||
const selectedValue = response.selectedValues?.[0];
|
||||
|
||||
if (selectedValue === 'confirm_plan') {
|
||||
// Phase IV: 确认分析方案 → 前端将触发 executeWorkflow
|
||||
const workflowId = response.metadata?.workflowId || '';
|
||||
// Phase IV: 确认分析方案 → 前端打开工作区,用户手动点击执行
|
||||
const workflowId = pendingMeta.workflowId || response.metadata?.workflowId || '';
|
||||
const messages = await conversationService.buildContext(
|
||||
sessionId, conversationId, 'analyze',
|
||||
`[系统提示] 用户已确认分析方案(workflow: ${workflowId})。请简要确认:"好的,方案已确认,正在准备执行分析..."。`,
|
||||
[
|
||||
`[系统指令——严格遵守] 用户已确认分析方案(workflow: ${workflowId})。`,
|
||||
'你只需回复一句简短的确认消息,例如:"好的,方案已确认。请在右侧工作区点击「开始执行分析」启动 R 引擎。"',
|
||||
'【铁律】禁止在此回复中生成任何分析结果、表格、P值、统计量、数值。',
|
||||
'你不是计算引擎,所有数值结果将由 R 统计引擎独立计算后返回。',
|
||||
'你的回复不得超过 2 句话。',
|
||||
].join('\n'),
|
||||
);
|
||||
|
||||
const result = await conversationService.streamToSSE(messages, writer, {
|
||||
temperature: 0.3, maxTokens: 300,
|
||||
temperature: 0.1, maxTokens: 150,
|
||||
});
|
||||
|
||||
await conversationService.finalizeAssistantMessage(
|
||||
@@ -451,12 +460,12 @@ export class ChatHandlerService {
|
||||
// Phase III: 确认使用推荐方法 → 提示可以开始分析
|
||||
const messages = await conversationService.buildContext(
|
||||
sessionId, conversationId, 'analyze',
|
||||
'[系统提示] 用户已确认使用推荐的统计方法。请简要确认方案,告知用户可以在对话中说"开始分析"或在右侧面板触发执行。',
|
||||
'[系统指令] 用户已确认使用推荐的统计方法。请简要确认方案,告知用户可以在对话中说"开始分析"或在右侧面板触发执行。禁止生成任何数值或假设的分析结果。',
|
||||
);
|
||||
|
||||
const result = await conversationService.streamToSSE(messages, writer, {
|
||||
temperature: 0.5,
|
||||
maxTokens: 800,
|
||||
temperature: 0.3,
|
||||
maxTokens: 500,
|
||||
});
|
||||
|
||||
await conversationService.finalizeAssistantMessage(
|
||||
|
||||
Reference in New Issue
Block a user