import assert from 'node:assert/strict'; import test from 'node:test'; import { createAgentRunGateway } from './agent-run-gateway.mjs'; import { buildAgentOrchestrationAgentText } from './chat-intent-router.mjs'; function createGoalRunPool() { const runs = new Map(); const events = []; return { runs, events, async query(sql, params = []) { if (sql.includes('SELECT * FROM h5_agent_runs WHERE user_id = ? AND request_id = ?')) { const [userId, requestId] = params; const row = [...runs.values()].find( (item) => item.user_id === userId && item.request_id === requestId, ); return [[row].filter(Boolean)]; } if (sql.includes('agent_session_id = ?') && sql.includes("status NOT IN ('succeeded', 'failed')")) { return [[]]; } if (sql.includes('INSERT INTO h5_agent_runs')) { const [ id, userId, sessionId, goalRunId, goalCheckpointId, requestId, userMessageJson, createdAt, updatedAt, ] = params; runs.set(id, { id, user_id: userId, agent_session_id: sessionId, goal_run_id: goalRunId, goal_checkpoint_id: goalCheckpointId, request_id: requestId, status: 'queued', attempts: 0, user_message_json: userMessageJson, created_at: createdAt, updated_at: updatedAt, }); return [{ affectedRows: 1 }]; } if (sql.includes('INSERT INTO h5_agent_run_events')) { events.push({ runId: params[1], eventType: params[2], dataJson: params[3], }); return [{ affectedRows: 1 }]; } if (sql.includes('SELECT * FROM h5_agent_runs WHERE id = ? LIMIT 1')) { return [[runs.get(params[0])].filter(Boolean)]; } if (sql.includes('INSERT INTO h5_agent_run_snapshots')) { return [{ affectedRows: 1 }]; } throw new Error(`Unexpected SQL: ${sql.slice(0, 120)}`); }, }; } test('createRun persists goal_run_id and goal_checkpoint_id', async () => { const pool = createGoalRunPool(); const attachCalls = []; const gateway = createAgentRunGateway({ pool, userAuth: {}, tkmindProxy: {}, autoDispatch: false, goalRunService: { async attachAgentRunToCheckpoint(input) { attachCalls.push(input); return true; }, }, }); const run = await gateway.createRun('user-1', { requestId: 'req-goal-1', userMessage: { role: 'user', content: [{ type: 'text', text: '分阶段任务' }] }, goalRunId: 'goal-1', goalCheckpointId: 'cp-1', }); assert.equal(run.requestId, 'req-goal-1'); const stored = [...pool.runs.values()][0]; assert.equal(stored.goal_run_id, 'goal-1'); assert.equal(stored.goal_checkpoint_id, 'cp-1'); assert.deepEqual(attachCalls, [{ checkpointId: 'cp-1', agentRunId: stored.id, }]); const queuedEvent = pool.events.find((event) => event.eventType === 'queued'); assert.match(String(queuedEvent?.dataJson ?? ''), /"goalRunId":"goal-1"/); }); test('buildAgentOrchestrationAgentText injects goal context before memory context', () => { const text = buildAgentOrchestrationAgentText({ displayText: '继续推进', classification: { reason: '长期任务续作' }, goalContext: { injectionEnabled: true, envelope: '【Goal Context】\n目标:产品规划\n当前阶段:调研(进行中)', }, memoryContext: { injectionEnabled: true, memories: [{ label: '偏好', text: '简洁中文' }], }, }); const goalIndex = text.indexOf('【Goal Context】'); const memoryIndex = text.indexOf('[Memory Context]'); assert.ok(goalIndex >= 0); assert.ok(memoryIndex > goalIndex); assert.match(text, /目标:产品规划/); });