Files
Agent-System-Frontend/test/contracts.test.ts
weichen fd3c3dbe32 Implement the three-column workbench frontend: resizable/collapsible nav with overshorthand collapse
Details (original message):
Implement the three-column workbench frontend: resizable/collapsible nav with overshorthand collapse, streaming chat with part renderers and process collapse, HITL choice cards with impact display and free-input pivot, plan/todos/artifacts/agents tabs, subagent tracker modal, schema-driven settings center with effect badges and masked secrets, profile management with import/export, plugin panel rendering, doc viewer with edit-save; contract shape tests.
2026-09-29 18:00:10 +00:00

71 lines
3.4 KiB
TypeScript

// 契约形状测试:前端类型对黄金样本的运行时断言(三态一致的第三态验证)。
import { describe, expect, it } from 'vitest'
import type { Message, Part, StreamEvent, HITLCard, AgentProfile } from '../src/contracts'
const goldenMessage = {
id: 'msg_abc123def456', conversationId: 'cnv_abc123def456', runId: 'run_abc123def456',
role: 'assistant',
parts: [
{ type: 'thinking', text: '考虑先检索…', process: true },
{ type: 'tool_call', process: true, toolCall: { id: 'call_1', name: 'history_search', arguments: '{"q":"部署"}', durationMs: 12.5 } },
{ type: 'tool_result', process: true, toolResult: { callId: 'call_1', status: 'ok', summary: '3 条命中' } },
{ type: 'text', text: '根据历史记录……' },
{ type: 'artifact_ref', artifact: { artifactId: 'art_abc123def456', name: '报告.md', kind: 'document' } },
],
}
describe('契约形状(Core 黄金样本)', () => {
it('message 判别联合按 type 解析', () => {
const m = goldenMessage as unknown as Message
expect(m.role).toBe('assistant')
expect(m.parts.length).toBe(5)
const parts = m.parts as Part[]
expect(parts[1].toolCall?.name).toBe('history_search')
expect(parts[2].toolResult?.status).toBe('ok')
expect(parts[3].text).toContain('历史')
expect(parts[0].process).toBe(true)
})
it('stream event 信封字段', () => {
const e = JSON.parse(`{"seq":42,"runId":"run_1","conversationId":"cnv_1","ts":"2026-09-29T10:00:00Z","v":1,"type":"message.delta","payload":{"index":0,"text":"你"}}`) as StreamEvent
expect(e.seq).toBe(42)
expect(e.type).toBe('message.delta')
expect((e.payload as { text: string }).text).toBe('你')
})
it('hitl 卡片:选项含 impact(决策上下文契约)', () => {
const c = JSON.parse(`{"id":"hitl_1","runId":"run_1","conversationId":"cnv_1","question":"格式?","kind":"choice","choices":[{"id":"md","label":"Markdown 文档","description":"可版本管理","impact":"写入 artifacts","recommended":true}],"allowFreeInput":true,"createdAt":"2026-09-29T10:00:00Z","resolved":false}`) as HITLCard
expect(c.choices?.[0].impact).toBeTruthy()
expect(c.kind).toBe('choice')
})
it('profile 工具三清单', () => {
const p = JSON.parse(`{"id":"default","name":"通用助手","builtin":true,"source":"builtin","systemPrompt":"x","model":{},"tools":{"allow":["*"],"deny":["http.admin."],"confirm":["http."]},"context":{"maxHistoryMessages":40},"hitl":{"askOnAmbiguity":true},"budget":{}}`) as AgentProfile
expect(p.tools.allow).toEqual(['*'])
expect(p.tools.confirm).toEqual(['http.'])
})
})
// 事件应用逻辑的纯函数级验证(store 分支的样本驱动)。
describe('SSE 事件解析(api.ts handle 逻辑样本)', () => {
it('解析 data 帧并推进游标', () => {
let since = 0
const frames = [
'id: 41\nevent: message.delta\ndata: {"seq":41,"type":"message.delta","conversationId":"c1"}',
'id: 42\nevent: run.completed\ndata: {"seq":42,"type":"run.completed","conversationId":"c1"}',
]
const seen: string[] = []
for (const f of frames) {
for (const line of f.split('\n')) {
if (line.startsWith('data: ')) {
const e = JSON.parse(line.slice(6)) as StreamEvent
since = Math.max(since, e.seq)
seen.push(e.type)
}
}
}
expect(seen).toEqual(['message.delta', 'run.completed'])
expect(since).toBe(42)
})
})