feat(ssa): Complete Phase I-IV intelligent dialogue and tool system development
Phase I - Session Blackboard + READ Layer: - SessionBlackboardService with Postgres-Only cache - DataProfileService for data overview generation - PicoInferenceService for LLM-driven PICO extraction - Frontend DataContextCard and VariableDictionaryPanel - E2E tests: 31/31 passed Phase II - Conversation Layer LLM + Intent Router: - ConversationService with SSE streaming - IntentRouterService (rule-first + LLM fallback, 6 intents) - SystemPromptService with 6-segment dynamic assembly - TokenTruncationService for context management - ChatHandlerService as unified chat entry - Frontend SSAChatPane and useSSAChat hook - E2E tests: 38/38 passed Phase III - Method Consultation + AskUser Standardization: - ToolRegistryService with Repository Pattern - MethodConsultService with DecisionTable + LLM enhancement - AskUserService with global interrupt handling - Frontend AskUserCard component - E2E tests: 13/13 passed Phase IV - Dialogue-Driven Analysis + QPER Integration: - ToolOrchestratorService (plan/execute/report) - analysis_plan SSE event for WorkflowPlan transmission - Dual-channel confirmation (ask_user card + workspace button) - PICO as optional hint for LLM parsing - E2E tests: 25/25 passed R Statistics Service: - 5 new R tools: anova_one, baseline_table, fisher, linear_reg, wilcoxon - Enhanced guardrails and block helpers - Comprehensive test suite (run_all_tools_test.js) Documentation: - Updated system status document (v5.9) - Updated SSA module status and development plan (v1.8) Total E2E: 107/107 passed (Phase I: 31, Phase II: 38, Phase III: 13, Phase IV: 25) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
102
backend/src/modules/ssa/routes/blackboard.routes.ts
Normal file
102
backend/src/modules/ssa/routes/blackboard.routes.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Phase I — Session Blackboard + READ Layer 路由
|
||||
*
|
||||
* 路由前缀: /sessions/:sessionId/blackboard
|
||||
*
|
||||
* GET / — 获取完整 SessionBlackboard
|
||||
* POST /data-overview — 触发 get_data_overview 工具
|
||||
* POST /variable-detail — 触发 get_variable_detail 工具
|
||||
* PATCH /variables/:name — 用户确认/修改变量类型
|
||||
*/
|
||||
|
||||
import { FastifyInstance, FastifyRequest } from 'fastify';
|
||||
import { logger } from '../../../common/logging/index.js';
|
||||
import { sessionBlackboardService } from '../services/SessionBlackboardService.js';
|
||||
import { executeGetDataOverview } from '../services/tools/GetDataOverviewTool.js';
|
||||
import { executeGetVariableDetail } from '../services/tools/GetVariableDetailTool.js';
|
||||
import type { ColumnType, PicoRole, VariableDictPatch } from '../types/session-blackboard.types.js';
|
||||
|
||||
export default async function blackboardRoutes(app: FastifyInstance) {
|
||||
|
||||
// GET /sessions/:sessionId/blackboard — 获取完整黑板
|
||||
app.get('/', async (req, reply) => {
|
||||
const { sessionId } = req.params as { sessionId: string };
|
||||
|
||||
const blackboard = await sessionBlackboardService.get(sessionId);
|
||||
if (!blackboard) {
|
||||
return reply.status(404).send({ error: 'Blackboard not found for this session' });
|
||||
}
|
||||
|
||||
const report = blackboard.dataOverview
|
||||
? sessionBlackboardService.generateFiveSectionReport(
|
||||
blackboard.dataOverview,
|
||||
blackboard.variableDictionary,
|
||||
)
|
||||
: null;
|
||||
|
||||
return reply.send({ blackboard, report });
|
||||
});
|
||||
|
||||
// POST /sessions/:sessionId/blackboard/data-overview — 执行 get_data_overview
|
||||
app.post('/data-overview', async (req, reply) => {
|
||||
const { sessionId } = req.params as { sessionId: string };
|
||||
|
||||
logger.info('[SSA:Route] Triggering data overview', { sessionId });
|
||||
|
||||
const result = await executeGetDataOverview(sessionId);
|
||||
|
||||
if (!result.success) {
|
||||
return reply.status(400).send({ error: result.error });
|
||||
}
|
||||
|
||||
return reply.send({
|
||||
success: true,
|
||||
report: result.report,
|
||||
});
|
||||
});
|
||||
|
||||
// POST /sessions/:sessionId/blackboard/variable-detail — 执行 get_variable_detail
|
||||
app.post('/variable-detail', async (req, reply) => {
|
||||
const { sessionId } = req.params as { sessionId: string };
|
||||
const { variableName, confirmedType, label } = req.body as {
|
||||
variableName: string;
|
||||
confirmedType?: ColumnType;
|
||||
label?: string;
|
||||
};
|
||||
|
||||
if (!variableName) {
|
||||
return reply.status(400).send({ error: 'variableName is required' });
|
||||
}
|
||||
|
||||
logger.info('[SSA:Route] Triggering variable detail', { sessionId, variableName });
|
||||
|
||||
const result = await executeGetVariableDetail(sessionId, variableName, confirmedType, label);
|
||||
|
||||
if (!result.success) {
|
||||
return reply.status(400).send({ error: result.error });
|
||||
}
|
||||
|
||||
return reply.send(result);
|
||||
});
|
||||
|
||||
// PATCH /sessions/:sessionId/blackboard/variables/:name — 更新变量字典条目
|
||||
app.patch('/variables/:name', async (req, reply) => {
|
||||
const { sessionId, name } = req.params as { sessionId: string; name: string };
|
||||
const body = req.body as {
|
||||
confirmedType?: ColumnType;
|
||||
label?: string;
|
||||
picoRole?: PicoRole | null;
|
||||
};
|
||||
|
||||
logger.info('[SSA:Route] Updating variable dictionary entry', { sessionId, name, body });
|
||||
|
||||
const dictPatch: VariableDictPatch = {};
|
||||
if (body.confirmedType !== undefined) dictPatch.confirmedType = body.confirmedType;
|
||||
if (body.label !== undefined) dictPatch.label = body.label;
|
||||
if (body.picoRole !== undefined) dictPatch.picoRole = body.picoRole;
|
||||
|
||||
await sessionBlackboardService.updateVariable(sessionId, name, dictPatch);
|
||||
|
||||
return reply.send({ success: true });
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user