import { describe, it, expect } from 'vitest'; const { Parser } = require('../../core/parser'); describe('Parser', () => { // ── parseCalls: 正则解析(向后兼容) ── describe('parseCalls (regex)', () => { it('should parse single agent call', () => { const input = ` 一些分析内容... [CALL: coder] 实现一个 add 函数 [/CALL] 其他内容... `; const result = Parser.parseCalls(input); expect(result).toHaveLength(1); expect(result[0]).toEqual({ agent: 'coder', task: '实现一个 add 函数' }); }); it('should return only the last call when multiple calls exist (serial decision constraint)', () => { const input = ` [CALL: coder] 写代码 [/CALL] [CALL: verifier] 验证代码 [/CALL] `; const result = Parser.parseCalls(input); // 串行决策约束:只返回最后一个 CALL expect(result).toHaveLength(1); expect(result[0].agent).toBe('verifier'); }); it('should return empty array when no calls', () => { const input = '没有任何调用标记的内容'; const result = Parser.parseCalls(input); expect(result).toEqual([]); }); it('should handle agent name with spaces', () => { const input = '[CALL: frontend-tester ]\n测试任务\n[/CALL]'; const result = Parser.parseCalls(input); expect(result[0].agent).toBe('frontend-tester'); }); it('should preserve multiline task content', () => { const input = `[CALL: coder] 第一行 第二行 第三行 [/CALL]`; const result = Parser.parseCalls(input); expect(result[0].task).toBe('第一行\n第二行\n第三行'); }); it('should skip placeholder agent names', () => { const input = ` [CALL: agent_name] 这是示例 [/CALL] [CALL: coder] 真实任务 [/CALL] `; const result = Parser.parseCalls(input); expect(result).toHaveLength(1); expect(result[0].agent).toBe('coder'); }); }); // ── parseCalls: JSON 解析 (3.1) ── describe('parseCalls (JSON)', () => { it('should parse single call from JSON code block', () => { const input = ` 分析完成,调用 coder 执行: \`\`\`json { "agent": "coder", "task": "实现一个 add 函数" } \`\`\` `; const result = Parser.parseCalls(input); expect(result).toHaveLength(1); expect(result[0].agent).toBe('coder'); expect(result[0].task).toBe('实现一个 add 函数'); }); it('should parse multiple calls from JSON code block', () => { const input = ` \`\`\`json { "calls": [ { "agent": "coder", "task": "写代码" }, { "agent": "verifier", "task": "验证" } ] } \`\`\` `; // 无 agents 配置时仍然串行约束 const result = Parser.parseCalls(input); expect(result).toHaveLength(1); expect(result[0].agent).toBe('verifier'); }); it('should prefer JSON over regex when both present', () => { const input = ` \`\`\`json { "agent": "coder", "task": "JSON 任务" } \`\`\` [CALL: verifier] 正则任务 [/CALL] `; const result = Parser.parseCalls(input); // JSON 优先 expect(result).toHaveLength(1); expect(result[0].agent).toBe('coder'); expect(result[0].task).toBe('JSON 任务'); }); it('should fallback to regex when JSON is invalid', () => { const input = ` \`\`\`json { invalid json content \`\`\` [CALL: coder] 正则任务 [/CALL] `; const result = Parser.parseCalls(input); expect(result).toHaveLength(1); expect(result[0].agent).toBe('coder'); expect(result[0].task).toBe('正则任务'); }); }); // ── parseCalls: parallelGroup (3.5) ── describe('parseCalls (parallelGroup)', () => { const agentsWithParallel = { coder: { type: 'executor' }, 'validator-style': { type: 'validator', parallelGroup: 'audit' }, 'validator-test': { type: 'validator', parallelGroup: 'audit' }, 'validator-security': { type: 'validator', parallelGroup: 'audit' }, }; it('should allow parallel calls for same parallelGroup', () => { const input = ` [CALL: validator-style] 检查样式 [/CALL] [CALL: validator-test] 运行测试 [/CALL] [CALL: validator-security] 安全审计 [/CALL] `; const result = Parser.parseCalls(input, { agents: agentsWithParallel }); // 同一个 parallelGroup,允许全部返回 expect(result).toHaveLength(3); }); it('should still enforce serial constraint for ungrouped agents', () => { const input = ` [CALL: coder] 写代码 [/CALL] [CALL: validator-style] 检查样式 [/CALL] `; const result = Parser.parseCalls(input, { agents: agentsWithParallel }); // coder 没有 parallelGroup,严格串行 expect(result).toHaveLength(1); expect(result[0].agent).toBe('validator-style'); }); it('should enforce serial when no agents config provided', () => { const input = ` [CALL: validator-style] 检查样式 [/CALL] [CALL: validator-test] 运行测试 [/CALL] `; const result = Parser.parseCalls(input); // 没有 agents 参数 expect(result).toHaveLength(1); expect(result[0].agent).toBe('validator-test'); }); it('should work with JSON format and parallelGroup', () => { const input = ` \`\`\`json { "calls": [ { "agent": "validator-style", "task": "检查样式" }, { "agent": "validator-test", "task": "运行测试" } ] } \`\`\` `; const result = Parser.parseCalls(input, { agents: agentsWithParallel }); // 同 parallelGroup,允许并行 expect(result).toHaveLength(2); }); }); // ── parseResult ── describe('parseResult', () => { it('should parse DONE status', () => { const input = ` 执行完成 [RESULT: DONE] 已创建 src/add.js 文件 [/RESULT] `; const result = Parser.parseResult(input); expect(result).toEqual({ status: 'DONE', message: '已创建 src/add.js 文件' }); }); it('should parse PASS status', () => { const input = '[RESULT: PASS]\n所有测试通过\n[/RESULT]'; const result = Parser.parseResult(input); expect(result.status).toBe('PASS'); expect(result.message).toBe('所有测试通过'); }); it('should parse FAIL status', () => { const input = '[RESULT: FAIL]\n测试失败:add(1,2) 返回 null\n[/RESULT]'; const result = Parser.parseResult(input); expect(result.status).toBe('FAIL'); expect(result.message).toContain('测试失败'); }); it('should parse ERROR status', () => { const input = '[RESULT: ERROR]\n文件不存在\n[/RESULT]'; const result = Parser.parseResult(input); expect(result.status).toBe('ERROR'); }); it('should return ERROR when no result marker', () => { const input = '没有结果标记的输出'; const result = Parser.parseResult(input); expect(result.status).toBe('ERROR'); expect(result.message).toContain('No result marker'); }); it('should handle status with extra spaces', () => { const input = '[RESULT: PASS ]\n通过\n[/RESULT]'; const result = Parser.parseResult(input); expect(result.status).toBe('PASS'); }); }); // ── parseResult: JSON 解析 (3.1) ── describe('parseResult (JSON)', () => { it('should parse result from JSON code block', () => { const input = ` 执行完成: \`\`\`json { "status": "DONE", "message": "已创建文件" } \`\`\` `; const result = Parser.parseResult(input); expect(result.status).toBe('DONE'); expect(result.message).toBe('已创建文件'); }); it('should prefer JSON over regex for result', () => { const input = ` \`\`\`json { "status": "PASS", "message": "JSON 结果" } \`\`\` [RESULT: FAIL] 正则结果 [/RESULT] `; const result = Parser.parseResult(input); // JSON 优先 expect(result.status).toBe('PASS'); expect(result.message).toBe('JSON 结果'); }); it('should fallback to regex when JSON result is invalid', () => { const input = ` \`\`\`json { "invalid": "no status field" } \`\`\` [RESULT: DONE] 正则兜底 [/RESULT] `; const result = Parser.parseResult(input); expect(result.status).toBe('DONE'); expect(result.message).toBe('正则兜底'); }); it('should reject invalid status values in JSON', () => { const input = ` \`\`\`json { "status": "RUNNING", "message": "非法状态" } \`\`\` [RESULT: DONE] 正则兜底 [/RESULT] `; const result = Parser.parseResult(input); // RUNNING 不是合法状态,JSON 解析应忽略 expect(result.status).toBe('DONE'); }); }); });