仿真测试台(后端):节点指派 + 全链 Trace —— 起单定向到指定账号,真实任务落工作台
用户定的形态:测试台是**后端检测活动与流程**的,真实任务照旧到工作台
(不然指定账号干嘛)—— 所以测试台只管「起单 + 看穿」,人那一环还是真的。
**节点指派**(迁移 0016 workflow.assignments):
- StartWorkflowInput 增 `assignments {节点id → 员工id}`;分派改三级取人:
①节点指派(点名的人在岗就是他)②员工组轮值 ③全员轮值 —— 指派是加法不是替换,
点名的人不在岗退回轮值(单不能没人接);事件里如实记 `(节点指派)`
- **顺带修一个真 bug**:`node_instance.assignee_id` 写了但 `listInstances` 从没读回来
(审批箱收件、员工面链条、治理列表全按它认人 —— 写了不读等于没写)
**全链 Trace**(新模块 trace,L2;迁移 0017 sys.trace_span):
- span 由 **Mastra Observability 组件**产出(执行不经 Mastra 图,所以手动打点),
一开就落库、一收就补 —— 观测面不该比被观测的事晚(不走 exporter 的批量异步路)
- 打点覆盖:工作流 root → 节点(记着派给了谁)→ 活动内每次工具调用 / 模型调用 / 人卡
- **root span 挂在 `runtime.begin`**:那是「单已建好、还没进第一个节点」那一刻 ——
挂在 start 返回之后就晚了,起单同步走到第一个节点,节点 span 会先出生、另起孤树(实测)
- 观测尽力而为:写 span 失败吞掉,不掀翻业务
- 三样东西各管各的:trace(机器读时间轴)/ 任务记忆(人读留痕)/
**工作区报告(活动自持的 HTML)** —— 谁也不替代谁
路由:`POST /api/gov/testbed/run`(带指派起单)、`GET /api/gov/workflows/:id/trace`。
端到端六例(真库):指派生效 / 任务真落到被指派人手上并由他答单 / 下游节点同样生效 /
全链 span 逐层挂得上且耗时齐备 / 一条流一个 traceId / 不指派照旧轮值。五闸全过。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -507,6 +507,52 @@ export const listApprovalsRoute = {
|
||||
|
||||
/* ── 工作流下钻:实例 × 节点 ──────────────────────────────────────────── */
|
||||
|
||||
/* ── 设计台 · 仿真测试台 ─────────────────────────────────────────────── */
|
||||
|
||||
/**
|
||||
* 起一条流(测试台专用):**带节点指派**把整条流定向到指定账号 ——
|
||||
* 真实任务照旧落到那个人的工作台,测试台只管起单与观测。
|
||||
*/
|
||||
export const testRunRoute = {
|
||||
method: 'POST',
|
||||
path: '/api/gov/testbed/run',
|
||||
body: z.object({
|
||||
packageId: z.string(),
|
||||
subject: z.string().min(1),
|
||||
/** 调用接口入参 —— 按流程包的 callInterface.input 填 */
|
||||
data: z.record(z.string(), z.unknown()),
|
||||
/** 节点指派 `{ 节点id → 员工id }`;不指的节点照旧轮值 */
|
||||
assignments: z.record(z.string(), z.string()).default({}),
|
||||
}),
|
||||
output: z.object({ workflowId: z.string(), state: workflowStateSchema }),
|
||||
} as const satisfies RouteContract;
|
||||
|
||||
/** 全链 Trace:一条工作流的 span 树(节点 → 步骤 / 工具 / 模型 / 人卡) */
|
||||
export const traceOfWorkflowRoute = {
|
||||
method: 'GET',
|
||||
path: '/api/gov/workflows/:id/trace',
|
||||
params: z.object({ id: z.string() }),
|
||||
output: z.object({
|
||||
spans: z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
traceId: z.string(),
|
||||
parentId: z.string().optional(),
|
||||
name: z.string(),
|
||||
kind: z.enum(['workflow', 'node', 'step', 'tool', 'model', 'human']),
|
||||
nodeId: z.string().optional(),
|
||||
taskId: z.string().optional(),
|
||||
input: z.record(z.string(), z.unknown()).optional(),
|
||||
output: z.record(z.string(), z.unknown()).optional(),
|
||||
error: z.object({ message: z.string() }).optional(),
|
||||
attributes: z.record(z.string(), z.unknown()).optional(),
|
||||
startedAt: z.string(),
|
||||
endedAt: z.string().optional(),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
} as const satisfies RouteContract;
|
||||
|
||||
export const govWorkflowRoute = {
|
||||
method: 'GET',
|
||||
path: '/api/gov/workflows/:id',
|
||||
|
||||
Reference in New Issue
Block a user