@mickorz/opencode-agentic-workflow 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +406 -0
- package/dist/metrics/collector.d.ts +98 -0
- package/dist/metrics/collector.js +246 -0
- package/dist/metrics/collector.js.map +1 -0
- package/dist/observability/events.d.ts +99 -0
- package/dist/observability/events.js +55 -0
- package/dist/observability/events.js.map +1 -0
- package/dist/observability/observe.d.ts +7 -0
- package/dist/observability/observe.js +29 -0
- package/dist/observability/observe.js.map +1 -0
- package/dist/observability/trace.d.ts +26 -0
- package/dist/observability/trace.js +52 -0
- package/dist/observability/trace.js.map +1 -0
- package/dist/plugin/checkpoint-rpc.d.ts +74 -0
- package/dist/plugin/checkpoint-rpc.js +73 -0
- package/dist/plugin/checkpoint-rpc.js.map +1 -0
- package/dist/plugin/index.d.ts +24 -0
- package/dist/plugin/index.js +271 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/plugin/interactive-checkpoint-gate.d.ts +35 -0
- package/dist/plugin/interactive-checkpoint-gate.js +86 -0
- package/dist/plugin/interactive-checkpoint-gate.js.map +1 -0
- package/dist/plugin/opencode-v2-executor.d.ts +55 -0
- package/dist/plugin/opencode-v2-executor.js +92 -0
- package/dist/plugin/opencode-v2-executor.js.map +1 -0
- package/dist/plugin/policy-checkpoint-gate.d.ts +18 -0
- package/dist/plugin/policy-checkpoint-gate.js +27 -0
- package/dist/plugin/policy-checkpoint-gate.js.map +1 -0
- package/dist/plugin/price-table.d.ts +46 -0
- package/dist/plugin/price-table.js +44 -0
- package/dist/plugin/price-table.js.map +1 -0
- package/dist/plugin/tui.d.ts +12 -0
- package/dist/plugin/tui.js +53 -0
- package/dist/plugin/tui.js.map +1 -0
- package/dist/quality/check.d.ts +30 -0
- package/dist/quality/check.js +51 -0
- package/dist/quality/check.js.map +1 -0
- package/dist/quality/checkpoint.d.ts +44 -0
- package/dist/quality/checkpoint.js +55 -0
- package/dist/quality/checkpoint.js.map +1 -0
- package/dist/quality/json.d.ts +10 -0
- package/dist/quality/json.js +31 -0
- package/dist/quality/json.js.map +1 -0
- package/dist/quality/predicates.d.ts +17 -0
- package/dist/quality/predicates.js +44 -0
- package/dist/quality/predicates.js.map +1 -0
- package/dist/quality/verify.d.ts +50 -0
- package/dist/quality/verify.js +110 -0
- package/dist/quality/verify.js.map +1 -0
- package/dist/registry/definition.d.ts +66 -0
- package/dist/registry/definition.js +19 -0
- package/dist/registry/definition.js.map +1 -0
- package/dist/registry/errors.d.ts +31 -0
- package/dist/registry/errors.js +48 -0
- package/dist/registry/errors.js.map +1 -0
- package/dist/registry/index.d.ts +9 -0
- package/dist/registry/index.js +9 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/registry.d.ts +45 -0
- package/dist/registry/registry.js +117 -0
- package/dist/registry/registry.js.map +1 -0
- package/dist/registry/runner.d.ts +56 -0
- package/dist/registry/runner.js +199 -0
- package/dist/registry/runner.js.map +1 -0
- package/dist/registry/schema.d.ts +18 -0
- package/dist/registry/schema.js +73 -0
- package/dist/registry/schema.js.map +1 -0
- package/dist/runtime/command.d.ts +38 -0
- package/dist/runtime/command.js +61 -0
- package/dist/runtime/command.js.map +1 -0
- package/dist/runtime/engine.d.ts +17 -0
- package/dist/runtime/engine.js +31 -0
- package/dist/runtime/engine.js.map +1 -0
- package/dist/runtime/errors.d.ts +56 -0
- package/dist/runtime/errors.js +88 -0
- package/dist/runtime/errors.js.map +1 -0
- package/dist/runtime/executor.d.ts +46 -0
- package/dist/runtime/executor.js +16 -0
- package/dist/runtime/executor.js.map +1 -0
- package/dist/runtime/semaphore.d.ts +24 -0
- package/dist/runtime/semaphore.js +57 -0
- package/dist/runtime/semaphore.js.map +1 -0
- package/dist/state/file-store.d.ts +25 -0
- package/dist/state/file-store.js +138 -0
- package/dist/state/file-store.js.map +1 -0
- package/dist/state/journal.d.ts +83 -0
- package/dist/state/journal.js +59 -0
- package/dist/state/journal.js.map +1 -0
- package/dist/state/recorder.d.ts +63 -0
- package/dist/state/recorder.js +138 -0
- package/dist/state/recorder.js.map +1 -0
- package/dist/state/store.d.ts +23 -0
- package/dist/state/store.js +14 -0
- package/dist/state/store.js.map +1 -0
- package/dist/workflow/agent.d.ts +8 -0
- package/dist/workflow/agent.js +38 -0
- package/dist/workflow/agent.js.map +1 -0
- package/dist/workflow/fallback.d.ts +15 -0
- package/dist/workflow/fallback.js +32 -0
- package/dist/workflow/fallback.js.map +1 -0
- package/dist/workflow/parallel.d.ts +14 -0
- package/dist/workflow/parallel.js +62 -0
- package/dist/workflow/parallel.js.map +1 -0
- package/dist/workflow/phase.d.ts +7 -0
- package/dist/workflow/phase.js +12 -0
- package/dist/workflow/phase.js.map +1 -0
- package/dist/workflow/reliable.d.ts +50 -0
- package/dist/workflow/reliable.js +92 -0
- package/dist/workflow/reliable.js.map +1 -0
- package/dist/workflow/retry.d.ts +28 -0
- package/dist/workflow/retry.js +53 -0
- package/dist/workflow/retry.js.map +1 -0
- package/dist/workflow/sequence.d.ts +40 -0
- package/dist/workflow/sequence.js +100 -0
- package/dist/workflow/sequence.js.map +1 -0
- package/dist/workflow/smoke.d.ts +17 -0
- package/dist/workflow/smoke.js +38 -0
- package/dist/workflow/smoke.js.map +1 -0
- package/dist/workflows/artifact.d.ts +24 -0
- package/dist/workflows/artifact.js +71 -0
- package/dist/workflows/artifact.js.map +1 -0
- package/dist/workflows/index.d.ts +19 -0
- package/dist/workflows/index.js +40 -0
- package/dist/workflows/index.js.map +1 -0
- package/dist/workflows/reliable.d.ts +18 -0
- package/dist/workflows/reliable.js +32 -0
- package/dist/workflows/reliable.js.map +1 -0
- package/dist/workflows/smoke.d.ts +13 -0
- package/dist/workflows/smoke.js +26 -0
- package/dist/workflows/smoke.js.map +1 -0
- package/dist/workspace/ambient.d.ts +12 -0
- package/dist/workspace/ambient.js +17 -0
- package/dist/workspace/ambient.js.map +1 -0
- package/dist/workspace/git-worktree.d.ts +29 -0
- package/dist/workspace/git-worktree.js +110 -0
- package/dist/workspace/git-worktree.js.map +1 -0
- package/dist/workspace/index.d.ts +6 -0
- package/dist/workspace/index.js +6 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/provider.d.ts +61 -0
- package/dist/workspace/provider.js +15 -0
- package/dist/workspace/provider.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MetricsCollector(P2.6)—— 纯事件总线消费者
|
|
3
|
+
*
|
|
4
|
+
* EventBus ─→ MetricsCollector ─→ snapshot(内存聚合,随时可查)
|
|
5
|
+
*
|
|
6
|
+
* 设计约束(与 P2.4 一脉相承):
|
|
7
|
+
* - 零侵入:不改动 agent()/sequence()/verify() 等原语的任何逻辑,
|
|
8
|
+
* 只订阅事件流;token/cost 经 agent.completed 事件透传(数据源是
|
|
9
|
+
* 宿主 executor 提取的 AgentResult.usage/costUSD)。
|
|
10
|
+
* - 只聚合、不采样:计数与求和,不保存明细(明细在 journal/trace)。
|
|
11
|
+
* - 按 workflowId / 模型维度聚合;单 run 的明细数据以 journal 为准
|
|
12
|
+
* (journal 有每步时间戳与状态,run 级 rollup 未来可由 store 派生)。
|
|
13
|
+
*/
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import { promises as fs } from "node:fs";
|
|
16
|
+
import { getEventBus } from "../observability/events.js";
|
|
17
|
+
function emptyDuration() {
|
|
18
|
+
return { count: 0, totalMs: 0, minMs: Number.POSITIVE_INFINITY, maxMs: 0, lastMs: 0 };
|
|
19
|
+
}
|
|
20
|
+
function recordDuration(stats, ms) {
|
|
21
|
+
stats.count += 1;
|
|
22
|
+
stats.totalMs += ms;
|
|
23
|
+
stats.minMs = Math.min(stats.minMs, ms);
|
|
24
|
+
stats.maxMs = Math.max(stats.maxMs, ms);
|
|
25
|
+
stats.lastMs = ms;
|
|
26
|
+
}
|
|
27
|
+
function emptyTokens() {
|
|
28
|
+
return { input: 0, output: 0, reasoning: 0, cacheRead: 0, cacheWrite: 0 };
|
|
29
|
+
}
|
|
30
|
+
function addTokens(target, usage) {
|
|
31
|
+
target.input += usage.input;
|
|
32
|
+
target.output += usage.output;
|
|
33
|
+
target.reasoning += usage.reasoning;
|
|
34
|
+
target.cacheRead += usage.cache.read;
|
|
35
|
+
target.cacheWrite += usage.cache.write;
|
|
36
|
+
}
|
|
37
|
+
function emptySnapshot() {
|
|
38
|
+
return {
|
|
39
|
+
since: Date.now(),
|
|
40
|
+
updatedAt: 0,
|
|
41
|
+
agents: {
|
|
42
|
+
calls: 0,
|
|
43
|
+
failed: 0,
|
|
44
|
+
duration: emptyDuration(),
|
|
45
|
+
tokens: emptyTokens(),
|
|
46
|
+
costUSD: 0,
|
|
47
|
+
byModel: {},
|
|
48
|
+
},
|
|
49
|
+
workflows: {},
|
|
50
|
+
steps: { completed: 0, failed: 0, totalMs: 0 },
|
|
51
|
+
checks: { total: 0, passed: 0 },
|
|
52
|
+
verifies: { total: 0, passed: 0, reviewerPassed: 0, reviewerTotal: 0 },
|
|
53
|
+
checkpoints: { waiting: 0, approved: 0, rejected: 0 },
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export class MetricsCollector {
|
|
57
|
+
bus;
|
|
58
|
+
unsubscribe;
|
|
59
|
+
state = emptySnapshot();
|
|
60
|
+
/** 订阅指定 bus(缺省全局 bus) */
|
|
61
|
+
constructor(bus = getEventBus()) {
|
|
62
|
+
this.bus = bus;
|
|
63
|
+
this.unsubscribe = bus.subscribe((event) => this.handle(event));
|
|
64
|
+
}
|
|
65
|
+
workflowStats(id) {
|
|
66
|
+
let stats = this.state.workflows[id];
|
|
67
|
+
if (!stats) {
|
|
68
|
+
stats = { started: 0, completed: 0, failed: 0, duration: emptyDuration() };
|
|
69
|
+
this.state.workflows[id] = stats;
|
|
70
|
+
}
|
|
71
|
+
return stats;
|
|
72
|
+
}
|
|
73
|
+
handle(event) {
|
|
74
|
+
const s = this.state;
|
|
75
|
+
s.updatedAt = event.time;
|
|
76
|
+
switch (event.type) {
|
|
77
|
+
case "agent.started":
|
|
78
|
+
break;
|
|
79
|
+
case "agent.completed": {
|
|
80
|
+
s.agents.calls += 1;
|
|
81
|
+
recordDuration(s.agents.duration, event.durationMs);
|
|
82
|
+
if (event.usage)
|
|
83
|
+
addTokens(s.agents.tokens, event.usage);
|
|
84
|
+
if (typeof event.costUSD === "number")
|
|
85
|
+
s.agents.costUSD += event.costUSD;
|
|
86
|
+
if (event.model || event.usage) {
|
|
87
|
+
const key = event.model ?? "(unknown)";
|
|
88
|
+
let model = s.agents.byModel[key];
|
|
89
|
+
if (!model) {
|
|
90
|
+
model = { calls: 0, tokens: emptyTokens(), costUSD: 0 };
|
|
91
|
+
s.agents.byModel[key] = model;
|
|
92
|
+
}
|
|
93
|
+
model.calls += 1;
|
|
94
|
+
if (event.usage)
|
|
95
|
+
addTokens(model.tokens, event.usage);
|
|
96
|
+
if (typeof event.costUSD === "number")
|
|
97
|
+
model.costUSD += event.costUSD;
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case "agent.failed":
|
|
102
|
+
s.agents.failed += 1;
|
|
103
|
+
break;
|
|
104
|
+
case "workflow.started": {
|
|
105
|
+
const wf = this.workflowStats(event.workflowId);
|
|
106
|
+
wf.started += 1;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case "workflow.completed": {
|
|
110
|
+
const wf = this.workflowStats(event.workflowId);
|
|
111
|
+
wf.completed += 1;
|
|
112
|
+
recordDuration(wf.duration, event.durationMs);
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
case "workflow.failed": {
|
|
116
|
+
const wf = this.workflowStats(event.workflowId);
|
|
117
|
+
wf.failed += 1;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
case "step.completed":
|
|
121
|
+
s.steps.completed += 1;
|
|
122
|
+
s.steps.totalMs += event.durationMs;
|
|
123
|
+
break;
|
|
124
|
+
case "step.failed":
|
|
125
|
+
s.steps.failed += 1;
|
|
126
|
+
break;
|
|
127
|
+
case "check.completed":
|
|
128
|
+
s.checks.total += 1;
|
|
129
|
+
if (event.ok)
|
|
130
|
+
s.checks.passed += 1;
|
|
131
|
+
break;
|
|
132
|
+
case "verify.completed":
|
|
133
|
+
s.verifies.total += 1;
|
|
134
|
+
if (event.passed)
|
|
135
|
+
s.verifies.passed += 1;
|
|
136
|
+
s.verifies.reviewerPassed += event.passedCount;
|
|
137
|
+
s.verifies.reviewerTotal += event.totalCount;
|
|
138
|
+
break;
|
|
139
|
+
case "checkpoint.waiting":
|
|
140
|
+
s.checkpoints.waiting += 1;
|
|
141
|
+
break;
|
|
142
|
+
case "checkpoint.completed":
|
|
143
|
+
if (event.approved)
|
|
144
|
+
s.checkpoints.approved += 1;
|
|
145
|
+
else
|
|
146
|
+
s.checkpoints.rejected += 1;
|
|
147
|
+
break;
|
|
148
|
+
default:
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/** 当前聚合快照(深拷贝,调用方修改不影响内部状态) */
|
|
153
|
+
snapshot() {
|
|
154
|
+
return JSON.parse(JSON.stringify(this.state));
|
|
155
|
+
}
|
|
156
|
+
/** 清零重新收集 */
|
|
157
|
+
reset() {
|
|
158
|
+
this.state = emptySnapshot();
|
|
159
|
+
}
|
|
160
|
+
/** 停止订阅 */
|
|
161
|
+
dispose() {
|
|
162
|
+
this.unsubscribe();
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* 快照落盘:workflow 结束(completed/failed)时把当前聚合写到 <file>。
|
|
166
|
+
* 写失败只记录日志,绝不影响 workflow(观测设施不能成为故障源)。
|
|
167
|
+
*/
|
|
168
|
+
subscribeFileSink(file) {
|
|
169
|
+
this.bus.subscribe((event) => {
|
|
170
|
+
if (event.type !== "workflow.completed" && event.type !== "workflow.failed")
|
|
171
|
+
return;
|
|
172
|
+
const snapshot = this.snapshot();
|
|
173
|
+
void (async () => {
|
|
174
|
+
try {
|
|
175
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
176
|
+
await fs.writeFile(file, JSON.stringify({ ...snapshot, writtenAt: Date.now() }, null, 2), "utf8");
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
console.log(`[agentic-workflow] metrics sink write failed: ` +
|
|
180
|
+
`${error instanceof Error ? error.message : String(error)}`);
|
|
181
|
+
}
|
|
182
|
+
})();
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function fmtMs(ms) {
|
|
187
|
+
if (ms >= 60_000)
|
|
188
|
+
return `${(ms / 60_000).toFixed(1)}min`;
|
|
189
|
+
if (ms >= 1_000)
|
|
190
|
+
return `${(ms / 1_000).toFixed(1)}s`;
|
|
191
|
+
return `${ms}ms`;
|
|
192
|
+
}
|
|
193
|
+
function fmtTokens(n) {
|
|
194
|
+
if (n >= 1_000_000)
|
|
195
|
+
return `${(n / 1_000_000).toFixed(2)}M`;
|
|
196
|
+
if (n >= 1_000)
|
|
197
|
+
return `${(n / 1_000).toFixed(1)}k`;
|
|
198
|
+
return String(n);
|
|
199
|
+
}
|
|
200
|
+
function fmtDurationLine(d) {
|
|
201
|
+
if (d.count === 0)
|
|
202
|
+
return "n/a";
|
|
203
|
+
const min = Number.isFinite(d.minMs) ? fmtMs(d.minMs) : "-";
|
|
204
|
+
return `avg ${fmtMs(Math.round(d.totalMs / d.count))} / min ${min} / max ${fmtMs(d.maxMs)} (n=${d.count})`;
|
|
205
|
+
}
|
|
206
|
+
/** 人读快照(工具返回文本用) */
|
|
207
|
+
export function formatMetrics(m) {
|
|
208
|
+
const a = m.agents;
|
|
209
|
+
const lines = [];
|
|
210
|
+
lines.push(`# Workflow Metrics(自 ${new Date(m.since).toISOString()} 起)`);
|
|
211
|
+
lines.push("");
|
|
212
|
+
lines.push("## Agents");
|
|
213
|
+
lines.push(`- 调用 ${a.calls} 次(失败 ${a.failed})`);
|
|
214
|
+
lines.push(`- 耗时:${fmtDurationLine(a.duration)}`);
|
|
215
|
+
lines.push(`- tokens:in ${fmtTokens(a.tokens.input)} / out ${fmtTokens(a.tokens.output)} / ` +
|
|
216
|
+
`reasoning ${fmtTokens(a.tokens.reasoning)} / cache r ${fmtTokens(a.tokens.cacheRead)} w ${fmtTokens(a.tokens.cacheWrite)}`);
|
|
217
|
+
lines.push(`- 成本:$${a.costUSD.toFixed(4)}`);
|
|
218
|
+
if (Object.keys(a.byModel).length > 0) {
|
|
219
|
+
lines.push("- 按模型:");
|
|
220
|
+
for (const [model, stats] of Object.entries(a.byModel)) {
|
|
221
|
+
lines.push(` - ${model}: ${stats.calls} 次, in ${fmtTokens(stats.tokens.input)} / ` +
|
|
222
|
+
`out ${fmtTokens(stats.tokens.output)}, $${stats.costUSD.toFixed(4)}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
lines.push("");
|
|
226
|
+
lines.push("## Workflows");
|
|
227
|
+
const wfEntries = Object.entries(m.workflows);
|
|
228
|
+
if (wfEntries.length === 0) {
|
|
229
|
+
lines.push("- (无)");
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
for (const [id, wf] of wfEntries) {
|
|
233
|
+
lines.push(`- ${id}: started ${wf.started} / completed ${wf.completed} / failed ${wf.failed}; ` +
|
|
234
|
+
`耗时 ${fmtDurationLine(wf.duration)}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
lines.push("");
|
|
238
|
+
lines.push("## 质量门");
|
|
239
|
+
lines.push(`- check: ${m.checks.passed}/${m.checks.total} 通过` +
|
|
240
|
+
(m.checks.total > 0 ? "" : "(无)"));
|
|
241
|
+
lines.push(`- verify: ${m.verifies.passed}/${m.verifies.total} 次(reviewer ${m.verifies.reviewerPassed}/${m.verifies.reviewerTotal})`);
|
|
242
|
+
lines.push(`- checkpoint: ${m.checkpoints.approved} 批准 / ${m.checkpoints.rejected} 拒绝`);
|
|
243
|
+
lines.push(`- steps: ${m.steps.completed} 完成 / ${m.steps.failed} 失败(累计 ${fmtMs(m.steps.totalMs)})`);
|
|
244
|
+
return lines.join("\n");
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/metrics/collector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow 事件总线(P2.4 observability 地基)
|
|
3
|
+
*
|
|
4
|
+
* phase() 从 metadata 升级为事件源:所有核心原语(agent/check/verify/checkpoint/
|
|
5
|
+
* sequence/workflow)在关键节点派发结构化事件,后续 TUI、metrics、debug、
|
|
6
|
+
* trace 文件全部消费这一套事件流。
|
|
7
|
+
*
|
|
8
|
+
* 设计原则:
|
|
9
|
+
* - 事件小而可序列化(JSON-safe),便于落盘与跨进程传输
|
|
10
|
+
* - 派发同步、fan-out;handler 抛错被隔离(监听器绝不能破坏 workflow 本身)
|
|
11
|
+
* - 全局默认 bus 可替换(setEventBus),测试/宿主可注入自己的 bus
|
|
12
|
+
*/
|
|
13
|
+
import type { TokenUsage } from "../runtime/executor.js";
|
|
14
|
+
export interface WorkflowEventBase {
|
|
15
|
+
/** epoch ms */
|
|
16
|
+
time: number;
|
|
17
|
+
}
|
|
18
|
+
export type WorkflowEvent = WorkflowEventBase & ({
|
|
19
|
+
type: "workflow.started";
|
|
20
|
+
workflowId: string;
|
|
21
|
+
args?: Record<string, unknown>;
|
|
22
|
+
} | {
|
|
23
|
+
type: "workflow.completed";
|
|
24
|
+
workflowId: string;
|
|
25
|
+
durationMs: number;
|
|
26
|
+
} | {
|
|
27
|
+
type: "workflow.failed";
|
|
28
|
+
workflowId: string;
|
|
29
|
+
error: string;
|
|
30
|
+
} | {
|
|
31
|
+
type: "phase.started";
|
|
32
|
+
name: string;
|
|
33
|
+
} | {
|
|
34
|
+
type: "agent.started";
|
|
35
|
+
promptPreview: string;
|
|
36
|
+
} | {
|
|
37
|
+
type: "agent.completed";
|
|
38
|
+
durationMs: number;
|
|
39
|
+
outputLength: number;
|
|
40
|
+
/** token 用量(宿主能提供时;metrics 消费) */
|
|
41
|
+
usage?: TokenUsage;
|
|
42
|
+
/** 美元成本(宿主直接给出时) */
|
|
43
|
+
costUSD?: number;
|
|
44
|
+
/** 实际使用的模型 "providerID/id" */
|
|
45
|
+
model?: string;
|
|
46
|
+
} | {
|
|
47
|
+
type: "agent.failed";
|
|
48
|
+
durationMs: number;
|
|
49
|
+
error: string;
|
|
50
|
+
} | {
|
|
51
|
+
type: "check.completed";
|
|
52
|
+
label: string;
|
|
53
|
+
ok: boolean;
|
|
54
|
+
} | {
|
|
55
|
+
type: "verify.completed";
|
|
56
|
+
label: string;
|
|
57
|
+
passed: boolean;
|
|
58
|
+
passedCount: number;
|
|
59
|
+
totalCount: number;
|
|
60
|
+
} | {
|
|
61
|
+
type: "checkpoint.waiting";
|
|
62
|
+
label: string;
|
|
63
|
+
message: string;
|
|
64
|
+
} | {
|
|
65
|
+
type: "checkpoint.completed";
|
|
66
|
+
label: string;
|
|
67
|
+
approved: boolean;
|
|
68
|
+
} | {
|
|
69
|
+
type: "step.started";
|
|
70
|
+
index: number;
|
|
71
|
+
} | {
|
|
72
|
+
type: "step.completed";
|
|
73
|
+
index: number;
|
|
74
|
+
durationMs: number;
|
|
75
|
+
} | {
|
|
76
|
+
type: "step.failed";
|
|
77
|
+
index: number;
|
|
78
|
+
error: string;
|
|
79
|
+
});
|
|
80
|
+
/** 派发用入参(无需填 time,emitEvent 自动补) */
|
|
81
|
+
type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
|
|
82
|
+
export type EventInput = DistributiveOmit<WorkflowEvent, "time">;
|
|
83
|
+
export type EventHandler = (event: WorkflowEvent) => void;
|
|
84
|
+
export interface EventBus {
|
|
85
|
+
dispatch(event: WorkflowEvent): void;
|
|
86
|
+
/** 返回取消订阅函数 */
|
|
87
|
+
subscribe(handler: EventHandler): () => void;
|
|
88
|
+
}
|
|
89
|
+
/** 进程内同步 fan-out 事件总线(默认实现) */
|
|
90
|
+
export declare function createEventBus(): EventBus;
|
|
91
|
+
/** 替换全局 bus(测试/宿主注入) */
|
|
92
|
+
export declare function setEventBus(bus: EventBus): void;
|
|
93
|
+
/** 当前全局 bus */
|
|
94
|
+
export declare function getEventBus(): EventBus;
|
|
95
|
+
/** 派发事件(自动补 time) */
|
|
96
|
+
export declare function emitEvent(event: EventInput): void;
|
|
97
|
+
/** prompt 摘要(事件保持小而可序列化) */
|
|
98
|
+
export declare function preview(text: string, max?: number): string;
|
|
99
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow 事件总线(P2.4 observability 地基)
|
|
3
|
+
*
|
|
4
|
+
* phase() 从 metadata 升级为事件源:所有核心原语(agent/check/verify/checkpoint/
|
|
5
|
+
* sequence/workflow)在关键节点派发结构化事件,后续 TUI、metrics、debug、
|
|
6
|
+
* trace 文件全部消费这一套事件流。
|
|
7
|
+
*
|
|
8
|
+
* 设计原则:
|
|
9
|
+
* - 事件小而可序列化(JSON-safe),便于落盘与跨进程传输
|
|
10
|
+
* - 派发同步、fan-out;handler 抛错被隔离(监听器绝不能破坏 workflow 本身)
|
|
11
|
+
* - 全局默认 bus 可替换(setEventBus),测试/宿主可注入自己的 bus
|
|
12
|
+
*/
|
|
13
|
+
/** 进程内同步 fan-out 事件总线(默认实现) */
|
|
14
|
+
export function createEventBus() {
|
|
15
|
+
const handlers = new Set();
|
|
16
|
+
return {
|
|
17
|
+
dispatch(event) {
|
|
18
|
+
for (const handler of handlers) {
|
|
19
|
+
try {
|
|
20
|
+
handler(event);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
// 监听器异常隔离:只记录,绝不影响 workflow
|
|
24
|
+
console.log(`[agentic-workflow] event handler failed on ${event.type}: ` +
|
|
25
|
+
`${error instanceof Error ? error.message : String(error)}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
subscribe(handler) {
|
|
30
|
+
handlers.add(handler);
|
|
31
|
+
return () => {
|
|
32
|
+
handlers.delete(handler);
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
let currentBus = createEventBus();
|
|
38
|
+
/** 替换全局 bus(测试/宿主注入) */
|
|
39
|
+
export function setEventBus(bus) {
|
|
40
|
+
currentBus = bus;
|
|
41
|
+
}
|
|
42
|
+
/** 当前全局 bus */
|
|
43
|
+
export function getEventBus() {
|
|
44
|
+
return currentBus;
|
|
45
|
+
}
|
|
46
|
+
/** 派发事件(自动补 time) */
|
|
47
|
+
export function emitEvent(event) {
|
|
48
|
+
currentBus.dispatch({ ...event, time: Date.now() });
|
|
49
|
+
}
|
|
50
|
+
/** prompt 摘要(事件保持小而可序列化) */
|
|
51
|
+
export function preview(text, max = 80) {
|
|
52
|
+
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
53
|
+
return collapsed.length <= max ? collapsed : `${collapsed.slice(0, max)}…`;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/observability/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAuDH,+BAA+B;AAC/B,MAAM,UAAU,cAAc;IAC5B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAgB,CAAA;IACxC,OAAO;QACL,QAAQ,CAAC,KAAoB;YAC3B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,IAAI,CAAC;oBACH,OAAO,CAAC,KAAK,CAAC,CAAA;gBAChB,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,4BAA4B;oBAC5B,OAAO,CAAC,GAAG,CACT,8CAA8C,KAAK,CAAC,IAAI,IAAI;wBAC1D,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC9D,CAAA;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QACD,SAAS,CAAC,OAAqB;YAC7B,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YACrB,OAAO,GAAG,EAAE;gBACV,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YAC1B,CAAC,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAED,IAAI,UAAU,GAAa,cAAc,EAAE,CAAA;AAE3C,wBAAwB;AACxB,MAAM,UAAU,WAAW,CAAC,GAAa;IACvC,UAAU,GAAG,GAAG,CAAA;AAClB,CAAC;AAED,eAAe;AACf,MAAM,UAAU,WAAW;IACzB,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,qBAAqB;AACrB,MAAM,UAAU,SAAS,CAAC,KAAiB;IACzC,UAAU,CAAC,QAAQ,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,EAAmB,CAAC,CAAA;AACtE,CAAC;AAED,4BAA4B;AAC5B,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,GAAG,GAAG,EAAE;IAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;IAClD,OAAO,SAAS,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAA;AAC5E,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* observeWorkflow —— workflow 级事件包装器(P2.4)
|
|
3
|
+
*
|
|
4
|
+
* 包住任意 async workflow 函数,派发 workflow.started / completed / failed。
|
|
5
|
+
* 嵌套调用会产生嵌套事件流(P2 单 workflow 场景不依赖强制去重)。
|
|
6
|
+
*/
|
|
7
|
+
export declare function observeWorkflow<T>(workflowId: string, fn: () => Promise<T>, args?: Record<string, unknown>): Promise<T>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* observeWorkflow —— workflow 级事件包装器(P2.4)
|
|
3
|
+
*
|
|
4
|
+
* 包住任意 async workflow 函数,派发 workflow.started / completed / failed。
|
|
5
|
+
* 嵌套调用会产生嵌套事件流(P2 单 workflow 场景不依赖强制去重)。
|
|
6
|
+
*/
|
|
7
|
+
import { emitEvent } from "./events.js";
|
|
8
|
+
export async function observeWorkflow(workflowId, fn, args) {
|
|
9
|
+
emitEvent({ type: "workflow.started", workflowId, args });
|
|
10
|
+
const startedAt = Date.now();
|
|
11
|
+
try {
|
|
12
|
+
const result = await fn();
|
|
13
|
+
emitEvent({
|
|
14
|
+
type: "workflow.completed",
|
|
15
|
+
workflowId,
|
|
16
|
+
durationMs: Date.now() - startedAt,
|
|
17
|
+
});
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
emitEvent({
|
|
22
|
+
type: "workflow.failed",
|
|
23
|
+
workflowId,
|
|
24
|
+
error: error instanceof Error ? error.message : String(error),
|
|
25
|
+
});
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=observe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observe.js","sourceRoot":"","sources":["../../src/observability/observe.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEvC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAkB,EAClB,EAAoB,EACpB,IAA8B;IAE9B,SAAS,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAC5B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,EAAE,EAAE,CAAA;QACzB,SAAS,CAAC;YACR,IAAI,EAAE,oBAAoB;YAC1B,UAAU;YACV,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;SACnC,CAAC,CAAA;QACF,OAAO,MAAM,CAAA;IACf,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,SAAS,CAAC;YACR,IAAI,EAAE,iBAAiB;YACvB,UAAU;YACV,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC9D,CAAC,CAAA;QACF,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execution Trace(P2.4)
|
|
3
|
+
*
|
|
4
|
+
* - createTraceCollector: 订阅 bus,收集事件流为内存数组(debug/断言/测试)
|
|
5
|
+
* - createFileTraceSink: 订阅 bus,逐事件追加 JSONL 文件(持久化观测)
|
|
6
|
+
*
|
|
7
|
+
* 事件已保证 JSON-safe(见 events.ts),可直接序列化。
|
|
8
|
+
*/
|
|
9
|
+
import { type EventBus, type WorkflowEvent } from "./events.js";
|
|
10
|
+
export interface TraceCollector {
|
|
11
|
+
/** 收集到的事件快照(只读) */
|
|
12
|
+
readonly events: readonly WorkflowEvent[];
|
|
13
|
+
/** 停止收集 */
|
|
14
|
+
stop(): void;
|
|
15
|
+
}
|
|
16
|
+
/** 内存 trace 收集器(测试/调试用) */
|
|
17
|
+
export declare function createTraceCollector(bus?: EventBus): TraceCollector;
|
|
18
|
+
export interface TraceSink {
|
|
19
|
+
/** 停止订阅并落盘收尾 */
|
|
20
|
+
stop(): void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* JSONL 文件 trace sink:每事件一行追加写入。
|
|
24
|
+
* 写失败只记录(观测链路绝不影响 workflow 主链路)。
|
|
25
|
+
*/
|
|
26
|
+
export declare function createFileTraceSink(file: string, bus?: EventBus): TraceSink;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execution Trace(P2.4)
|
|
3
|
+
*
|
|
4
|
+
* - createTraceCollector: 订阅 bus,收集事件流为内存数组(debug/断言/测试)
|
|
5
|
+
* - createFileTraceSink: 订阅 bus,逐事件追加 JSONL 文件(持久化观测)
|
|
6
|
+
*
|
|
7
|
+
* 事件已保证 JSON-safe(见 events.ts),可直接序列化。
|
|
8
|
+
*/
|
|
9
|
+
import { appendFile, mkdir } from "node:fs/promises";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import { getEventBus } from "./events.js";
|
|
12
|
+
/** 内存 trace 收集器(测试/调试用) */
|
|
13
|
+
export function createTraceCollector(bus) {
|
|
14
|
+
const events = [];
|
|
15
|
+
const off = (bus ?? getEventBus()).subscribe((event) => {
|
|
16
|
+
events.push(event);
|
|
17
|
+
});
|
|
18
|
+
return {
|
|
19
|
+
get events() {
|
|
20
|
+
return events;
|
|
21
|
+
},
|
|
22
|
+
stop: off,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* JSONL 文件 trace sink:每事件一行追加写入。
|
|
27
|
+
* 写失败只记录(观测链路绝不影响 workflow 主链路)。
|
|
28
|
+
*/
|
|
29
|
+
export function createFileTraceSink(file, bus) {
|
|
30
|
+
const target = bus ?? getEventBus();
|
|
31
|
+
let directory = path.dirname(file);
|
|
32
|
+
let pending = Promise.resolve();
|
|
33
|
+
const off = target.subscribe((event) => {
|
|
34
|
+
// 串行化追加,避免行交错
|
|
35
|
+
pending = pending
|
|
36
|
+
.then(async () => {
|
|
37
|
+
await mkdir(directory, { recursive: true });
|
|
38
|
+
await appendFile(file, JSON.stringify(event) + "\n", "utf8");
|
|
39
|
+
})
|
|
40
|
+
.catch((error) => {
|
|
41
|
+
console.log(`[agentic-workflow] trace sink write failed: ` +
|
|
42
|
+
`${error instanceof Error ? error.message : String(error)}`);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
stop() {
|
|
47
|
+
off();
|
|
48
|
+
directory = directory; // no-op,保持引用形状稳定
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=trace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.js","sourceRoot":"","sources":["../../src/observability/trace.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,WAAW,EAAqC,MAAM,aAAa,CAAA;AAS5E,2BAA2B;AAC3B,MAAM,UAAU,oBAAoB,CAAC,GAAc;IACjD,MAAM,MAAM,GAAoB,EAAE,CAAA;IAClC,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;QACrD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACpB,CAAC,CAAC,CAAA;IACF,OAAO;QACL,IAAI,MAAM;YACR,OAAO,MAAM,CAAA;QACf,CAAC;QACD,IAAI,EAAE,GAAG;KACV,CAAA;AACH,CAAC;AAOD;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,GAAc;IAC9D,MAAM,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAA;IACnC,IAAI,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAClC,IAAI,OAAO,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAA;IAE9C,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;QACrC,cAAc;QACd,OAAO,GAAG,OAAO;aACd,IAAI,CAAC,KAAK,IAAI,EAAE;YACf,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YAC3C,MAAM,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAA;QAC9D,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YACxB,OAAO,CAAC,GAAG,CACT,8CAA8C;gBAC5C,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC9D,CAAA;QACH,CAAC,CAAC,CAAA;IACN,CAAC,CAAC,CAAA;IAEF,OAAO;QACL,IAAI;YACF,GAAG,EAAE,CAAA;YACL,SAAS,GAAG,SAAS,CAAA,CAAC,iBAAiB;QACzC,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkpoint RPC 契约(P2.3,server 与 TUI 双形态共享)
|
|
3
|
+
*
|
|
4
|
+
* 流向:
|
|
5
|
+
* server workflow -> checkpoint() -> InteractiveCheckpointGate
|
|
6
|
+
* --emit--> rpc.agentic-workflow.requested { requestId, label, message }
|
|
7
|
+
* <--call-- TUI: ui.dialog.confirm -> rpc "reply" { requestId, approved, reason? }
|
|
8
|
+
*
|
|
9
|
+
* 事件经 OpenCode 事件流广播(V2EventRpc),TUI 侧 ctx.data.on 订阅;
|
|
10
|
+
* 应答经 client.rpc(...)(或 rpc.call)回到 server 侧注册的 handler。
|
|
11
|
+
*/
|
|
12
|
+
export declare const CheckpointRpc: {
|
|
13
|
+
readonly id: "agentic-workflow";
|
|
14
|
+
readonly methods: {
|
|
15
|
+
/** TUI -> server:应答审批请求 */
|
|
16
|
+
readonly reply: {
|
|
17
|
+
readonly input: {
|
|
18
|
+
readonly type: "object";
|
|
19
|
+
readonly properties: {
|
|
20
|
+
readonly requestId: {
|
|
21
|
+
readonly type: "string";
|
|
22
|
+
};
|
|
23
|
+
readonly approved: {
|
|
24
|
+
readonly type: "boolean";
|
|
25
|
+
};
|
|
26
|
+
readonly reason: {
|
|
27
|
+
readonly type: "string";
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
readonly required: readonly ["requestId", "approved"];
|
|
31
|
+
readonly additionalProperties: false;
|
|
32
|
+
};
|
|
33
|
+
readonly output: {
|
|
34
|
+
readonly type: "object";
|
|
35
|
+
readonly properties: {
|
|
36
|
+
readonly ok: {
|
|
37
|
+
readonly type: "boolean";
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
readonly required: readonly ["ok"];
|
|
41
|
+
readonly additionalProperties: false;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
readonly events: {
|
|
46
|
+
/** server -> TUI:审批请求 */
|
|
47
|
+
readonly requested: {
|
|
48
|
+
readonly schema: {
|
|
49
|
+
readonly type: "object";
|
|
50
|
+
readonly properties: {
|
|
51
|
+
readonly requestId: {
|
|
52
|
+
readonly type: "string";
|
|
53
|
+
};
|
|
54
|
+
readonly label: {
|
|
55
|
+
readonly type: "string";
|
|
56
|
+
};
|
|
57
|
+
readonly message: {
|
|
58
|
+
readonly type: "string";
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
readonly required: readonly ["requestId", "label", "message"];
|
|
62
|
+
readonly additionalProperties: false;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
/** TUI 订阅用的事件名(字面量类型,保证 data.on 类型匹配;与 CheckpointRpc.id 的一致性由单测保证) */
|
|
68
|
+
export declare const CHECKPOINT_REQUESTED_EVENT: "rpc.agentic-workflow.requested";
|
|
69
|
+
/** 解析 TUI 应答(handler 入参为 unknown,需手动收窄) */
|
|
70
|
+
export declare function parseCheckpointReply(input: unknown): {
|
|
71
|
+
requestId: string;
|
|
72
|
+
approved: boolean;
|
|
73
|
+
reason?: string;
|
|
74
|
+
} | undefined;
|