test: add stage a prototype contracts

This commit is contained in:
hailin
2026-07-10 15:14:07 +08:00
parent ef55b97a0f
commit bbf32f94b4
7 changed files with 1464 additions and 3 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,9 @@
"dev": "vite",
"build": "tsc -b && vite build",
"typecheck": "tsc -b",
"lint": "eslint src --ext ts,tsx"
"lint": "eslint src --ext ts,tsx",
"test": "vitest",
"test:run": "vitest run"
},
"dependencies": {
"@fontsource-variable/geist": "^5.2.9",
@@ -27,14 +29,19 @@
"vite": "^6.0.0"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
"@types/node": "^26.0.1",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@vitejs/plugin-react": "^4.3.0",
"autoprefixer": "^10.4.20",
"eslint": "^9.16.0",
"jsdom": "^26.1.0",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.16",
"typescript": "^5.7.0"
"typescript": "^5.7.0",
"vitest": "^3.2.7"
}
}

View File

@@ -0,0 +1,26 @@
import { describe, expect, it } from 'vitest'
import {
agentRuns,
agents,
dashboardMetrics,
knowledgeReferences,
mcpTools,
modelProviders,
skills
} from './mockData'
describe('Stage A 演示数据', () => {
it('提供所有产品模块所需数据', () => {
expect(dashboardMetrics).toHaveLength(4)
expect(modelProviders.length).toBeGreaterThanOrEqual(2)
expect(agents).toHaveLength(3)
expect(skills.length).toBeGreaterThanOrEqual(3)
expect(agentRuns.every((run) => run.steps.length > 0)).toBe(true)
})
it('保持可信边界和引用完整性', () => {
expect(mcpTools.filter((tool) => tool.access_mode === 'write').every((tool) => tool.requires_human_confirm)).toBe(true)
expect(knowledgeReferences.every((reference) => reference.score >= 0 && reference.score <= 1)).toBe(true)
})
})

View File

@@ -0,0 +1,81 @@
import type {
AgentDefinition,
AgentRun,
DashboardMetric,
KnowledgeReference,
McpServer,
McpTool,
ModelProvider,
ModelTestResult,
SimilarTicket,
SkillDefinition,
ToolCall
} from './types'
export const dashboardMetrics: DashboardMetric[] = [
{ id: 'pending', label: '待处理工单', value: '18', change: '较昨日增加 3 单', trend: 'up', tone: 'warning' },
{ id: 'resolved', label: '今日已完成', value: '42', change: '完成率 78%', trend: 'up', tone: 'success' },
{ id: 'knowledge', label: '可复用方案', value: '126', change: '本周新增 8 条', trend: 'up', tone: 'default' },
{ id: 'agent', label: '智能体成功率', value: '96.4%', change: '最近 24 小时', trend: 'flat', tone: 'ai' }
]
export const modelProviders: ModelProvider[] = [
{ id: 1, name: '企业 OpenAI 兼容渠道', protocol: 'OpenAI-compatible', base_url: 'https://llm.example.com/v1', credential_masked: 'sk-****82F1', enabled: true, health: 'healthy', model_count: 4, last_checked_at: '2026-07-10T08:32:00+08:00' },
{ id: 2, name: '内部推理服务', protocol: 'OpenAI-compatible', base_url: 'http://model-gateway.internal/v1', credential_masked: 'token-****19AC', enabled: true, health: 'degraded', model_count: 2, last_checked_at: '2026-07-10T08:28:00+08:00' }
]
export const modelTestResults: ModelTestResult[] = [
{ id: 1, provider_name: '企业 OpenAI 兼容渠道', model_name: 'support-large', prompt: '分析采集进度长期不更新的可能原因', output: '建议先核对任务状态、最近一次采集日志和税局接口响应。', latency_ms: 1280, input_tokens: 86, output_tokens: 42, status: 'success', created_at: '2026-07-10T09:10:00+08:00' },
{ id: 2, provider_name: '内部推理服务', model_name: 'support-small', prompt: '生成客户回复草稿', output: '已确认任务仍在采集中,我们会继续关注上游接口状态。', latency_ms: 760, input_tokens: 64, output_tokens: 31, status: 'success', created_at: '2026-07-10T09:06:00+08:00' }
]
export const agents: AgentDefinition[] = [
{ id: 1, code: 'ticket_intake', name: '建单智能体', purpose: '补全工单字段、识别分类并追问缺失信息', enabled: true, model_name: 'support-small', knowledge_scopes: ['客户支持知识库'], skill_count: 2, tool_count: 0, updated_at: '2026-07-10T08:20:00+08:00' },
{ id: 2, code: 'support_analysis', name: '支持分析智能体', purpose: '检索知识、推荐方案并生成排查步骤', enabled: true, model_name: 'support-large', knowledge_scopes: ['客户支持知识库', '解决方案库'], skill_count: 3, tool_count: 2, updated_at: '2026-07-10T08:24:00+08:00' },
{ id: 3, code: 'knowledge_draft', name: '知识沉淀智能体', purpose: '从已解决工单生成待审核知识草稿', enabled: false, model_name: 'support-large', knowledge_scopes: ['解决方案库'], skill_count: 1, tool_count: 0, updated_at: '2026-07-10T08:26:00+08:00' }
]
export const agentRuns: AgentRun[] = [
{ id: 1001, agent_name: '支持分析智能体', ticket_no: 'T202607100006', trigger_user: '张工', status: 'waiting_confirm', output_summary: '已生成 3 条排查建议和 1 份客户回复草稿。', duration_ms: 2180, created_at: '2026-07-10T09:18:00+08:00', steps: [
{ id: 1, step_name: '检索相关知识', step_type: 'retrieval', status: 'success', input_summary: '采集进度长期不更新', output_summary: '命中 2 条知识和 1 个解决方案', latency_ms: 180 },
{ id: 2, step_name: '查询采集任务', step_type: 'tool', status: 'success', input_summary: '任务编号 TASK-8821', output_summary: '任务运行中,上游接口最近一次返回超时', latency_ms: 420 },
{ id: 3, step_name: '生成支持分析', step_type: 'model', status: 'success', input_summary: '工单、知识引用与工具结果', output_summary: '生成原因分析、排查步骤和回复草稿', latency_ms: 1580 },
{ id: 4, step_name: '等待人工采纳', step_type: 'approval', status: 'waiting', input_summary: 'AI 支持分析结果', output_summary: '等待技术人员确认', latency_ms: 0 }
] },
{ id: 1002, agent_name: '建单智能体', ticket_no: '草稿', trigger_user: '李娜', status: 'success', output_summary: '已识别为快速咨询并补全问题对象。', duration_ms: 940, created_at: '2026-07-10T09:12:00+08:00', steps: [
{ id: 5, step_name: '抽取工单字段', step_type: 'skill', status: 'success', input_summary: '客户自然语言描述', output_summary: '识别分类、对象和环境', latency_ms: 120 },
{ id: 6, step_name: '生成字段草稿', step_type: 'model', status: 'success', input_summary: '结构化字段', output_summary: '生成可确认的建单草稿', latency_ms: 820 }
] }
]
export const skills: SkillDefinition[] = [
{ id: 1, name: '工单字段抽取', scenario: 'field_extract', version: 'v1.3', enabled: true, prompt_template: '从用户描述中抽取工单分类、问题对象、问题表现、环境和关联系统。', input_schema: '{ "description": "string" }', output_schema: '{ "category_code": "string", "problem_object": "string" }', updated_at: '2026-07-10T08:00:00+08:00' },
{ id: 2, name: '缺失信息追问', scenario: 'missing_info', version: 'v1.1', enabled: true, prompt_template: '根据已填写字段判断处理工单仍缺少哪些必要信息。', input_schema: '{ "ticket_draft": "object" }', output_schema: '{ "questions": "string[]" }', updated_at: '2026-07-10T08:02:00+08:00' },
{ id: 3, name: '解决方案推荐', scenario: 'solution_recommend', version: 'v1.5', enabled: true, prompt_template: '根据工单内容和检索结果推荐可复用解决方案,并说明匹配原因。', input_schema: '{ "ticket": "object", "references": "object[]" }', output_schema: '{ "recommendations": "object[]" }', updated_at: '2026-07-10T08:04:00+08:00' }
]
export const mcpServers: McpServer[] = [
{ id: 1, name: '采集任务查询服务', endpoint: 'http://collector-mcp.internal', auth_type: '令牌', connection_state: 'connected', tool_count: 3, last_sync_at: '2026-07-10T08:40:00+08:00' },
{ id: 2, name: '日志检索服务', endpoint: 'http://logs-mcp.internal', auth_type: '令牌', connection_state: 'connected', tool_count: 2, last_sync_at: '2026-07-10T08:36:00+08:00' }
]
export const mcpTools: McpTool[] = [
{ id: 1, server_name: '采集任务查询服务', name: '查询采集进度', description: '按任务编号查询当前阶段和最近更新时间', access_mode: 'read', risk_level: 'low', requires_human_confirm: false, enabled: true },
{ id: 2, server_name: '日志检索服务', name: '检索任务日志', description: '按任务编号读取脱敏日志摘要', access_mode: 'read', risk_level: 'medium', requires_human_confirm: false, enabled: true },
{ id: 3, server_name: '采集任务查询服务', name: '重启采集任务', description: '重新触发指定采集任务', access_mode: 'write', risk_level: 'high', requires_human_confirm: true, enabled: false }
]
export const toolCalls: ToolCall[] = [
{ id: 1, tool_name: '查询采集进度', agent_name: '支持分析智能体', input_summary: 'TASK-8821', output_summary: '运行中,最近更新时间 09:16', status: 'success', duration_ms: 420, created_at: '2026-07-10T09:18:20+08:00' },
{ id: 2, tool_name: '重启采集任务', agent_name: '支持分析智能体', input_summary: 'TASK-8821', output_summary: '非只读工具不允许自动执行', status: 'blocked', duration_ms: 8, created_at: '2026-07-10T09:18:40+08:00' }
]
export const knowledgeReferences: KnowledgeReference[] = [
{ id: 1, title: '采集任务长时间无进度的排查步骤', source_type: 'knowledge_item', content: '先检查任务状态、上游接口响应和最近一次有效日志,再判断是否需要人工重试。', score: 0.93, source_label: '客户支持知识库' },
{ id: 2, title: '税局接口不稳定时的客户回复模板', source_type: 'solution', content: '确认任务仍在执行后,向客户说明上游接口状态并持续关注采集进度。', score: 0.87, source_label: '解决方案库' }
]
export const similarTickets: SimilarTicket[] = [
{ id: 5, ticket_no: 'T202607030005', title: '税局采集任务停留在初始化阶段', status: 'closed', similarity: 0.91, resolution: '确认税局接口波动,任务恢复后回复客户并关闭。' },
{ id: 2, ticket_no: 'T202607010002', title: '查询申报数据采集进度', status: 'resolved', similarity: 0.84, resolution: '查询任务日志后确认仍在采集中。' }
]

View File

@@ -0,0 +1,130 @@
export type DashboardMetric = {
id: string
label: string
value: string
change: string
trend: 'up' | 'down' | 'flat'
tone: 'default' | 'success' | 'warning' | 'danger' | 'ai'
}
export type ModelProvider = {
id: number
name: string
protocol: 'OpenAI-compatible'
base_url: string
credential_masked: string
enabled: boolean
health: 'healthy' | 'degraded' | 'unchecked'
model_count: number
last_checked_at: string
}
export type ModelTestResult = {
id: number
provider_name: string
model_name: string
prompt: string
output: string
latency_ms: number
input_tokens: number
output_tokens: number
status: 'success' | 'failed'
created_at: string
}
export type AgentDefinition = {
id: number
code: 'ticket_intake' | 'support_analysis' | 'knowledge_draft'
name: string
purpose: string
enabled: boolean
model_name: string
knowledge_scopes: string[]
skill_count: number
tool_count: number
updated_at: string
}
export type AgentStep = {
id: number
step_name: string
step_type: 'model' | 'retrieval' | 'skill' | 'tool' | 'approval'
status: 'success' | 'failed' | 'waiting'
input_summary: string
output_summary: string
latency_ms: number
}
export type AgentRun = {
id: number
agent_name: string
ticket_no: string
trigger_user: string
status: 'success' | 'failed' | 'running' | 'waiting_confirm'
output_summary: string
duration_ms: number
created_at: string
steps: AgentStep[]
}
export type SkillDefinition = {
id: number
name: string
scenario: 'field_extract' | 'missing_info' | 'solution_recommend' | 'reply_draft' | 'knowledge_draft'
version: string
enabled: boolean
prompt_template: string
input_schema: string
output_schema: string
updated_at: string
}
export type McpServer = {
id: number
name: string
endpoint: string
auth_type: '无认证' | '令牌'
connection_state: 'connected' | 'disconnected' | 'error'
tool_count: number
last_sync_at: string
}
export type McpTool = {
id: number
server_name: string
name: string
description: string
access_mode: 'read' | 'write'
risk_level: 'low' | 'medium' | 'high'
requires_human_confirm: boolean
enabled: boolean
}
export type ToolCall = {
id: number
tool_name: string
agent_name: string
input_summary: string
output_summary: string
status: 'success' | 'failed' | 'blocked'
duration_ms: number
created_at: string
}
export type KnowledgeReference = {
id: number
title: string
source_type: 'knowledge_item' | 'solution' | 'ticket' | 'document'
content: string
score: number
source_label: string
}
export type SimilarTicket = {
id: number
ticket_no: string
title: string
status: 'resolved' | 'closed'
similarity: number
resolution: string
}

View File

@@ -0,0 +1 @@
import '@testing-library/jest-dom/vitest'

15
frontend/vitest.config.ts Normal file
View File

@@ -0,0 +1,15 @@
import path from 'node:path'
import { defineConfig } from 'vitest/config'
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
},
test: {
environment: 'jsdom',
setupFiles: ['./src/test/setup.ts'],
css: true
}
})