niceeval 0.6.0 → 0.6.2
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/dist/agents/types.d.ts +72 -6
- package/dist/context/types.d.ts +32 -12
- package/dist/i18n/en.d.ts +54 -0
- package/dist/i18n/zh-CN.d.ts +55 -1
- package/dist/o11y/types.d.ts +16 -2
- package/dist/report/aggregate.d.ts +5 -3
- package/dist/report/aggregate.js +32 -5
- package/dist/report/built-ins/experiment-comparison.d.ts +39 -0
- package/dist/report/built-ins/experiment-comparison.js +119 -0
- package/dist/report/built-ins/index.d.ts +2 -1
- package/dist/report/built-ins/index.js +2 -2
- package/dist/report/components.d.ts +10 -2
- package/dist/report/components.js +3 -3
- package/dist/report/compute.d.ts +11 -18
- package/dist/report/compute.js +68 -66
- package/dist/report/flag.d.ts +16 -1
- package/dist/report/flag.js +19 -1
- package/dist/report/format.d.ts +16 -14
- package/dist/report/format.js +28 -30
- package/dist/report/index.d.ts +5 -4
- package/dist/report/index.js +6 -5
- package/dist/report/locale.d.ts +23 -3
- package/dist/report/locale.js +47 -6
- package/dist/report/metrics.d.ts +13 -1
- package/dist/report/metrics.js +66 -15
- package/dist/report/primitives.d.ts +6 -0
- package/dist/report/react/AttemptList.d.ts +4 -4
- package/dist/report/react/AttemptList.js +8 -10
- package/dist/report/react/EvalList.d.ts +1 -1
- package/dist/report/react/EvalList.js +0 -0
- package/dist/report/react/ExperimentComparison.d.ts +8 -0
- package/dist/report/react/ExperimentComparison.js +11 -0
- package/dist/report/react/ExperimentList.d.ts +4 -2
- package/dist/report/react/ExperimentList.js +57 -7
- package/dist/report/react/MetricScatter.js +6 -16
- package/dist/report/react/chart-math.d.ts +23 -6
- package/dist/report/react/chart-math.js +71 -19
- package/dist/report/react/fixtures.d.ts +3 -3
- package/dist/report/react/fixtures.js +30 -18
- package/dist/report/react/format.d.ts +1 -1
- package/dist/report/react/format.js +1 -1
- package/dist/report/react/index.d.ts +1 -1
- package/dist/report/report.d.ts +5 -1
- package/dist/report/report.js +6 -2
- package/dist/report/text/faces.d.ts +1 -1
- package/dist/report/text/faces.js +100 -61
- package/dist/report/text/table.js +36 -5
- package/dist/report/types.d.ts +40 -34
- package/dist/results/types.d.ts +11 -0
- package/dist/runner/feedback/sink.d.ts +110 -0
- package/dist/runner/types.d.ts +513 -22
- package/dist/sandbox/docker.d.ts +23 -2
- package/dist/sandbox/e2b.d.ts +15 -1
- package/dist/sandbox/errors.d.ts +30 -3
- package/dist/sandbox/io-retry.d.ts +17 -0
- package/dist/sandbox/registry.d.ts +2 -0
- package/dist/sandbox/resolve.d.ts +18 -5
- package/dist/sandbox/retry.d.ts +11 -1
- package/dist/sandbox/types.d.ts +39 -5
- package/dist/sandbox/vercel.d.ts +7 -1
- package/dist/scoring/coverage.d.ts +30 -0
- package/dist/scoring/display.d.ts +21 -0
- package/dist/scoring/display.js +120 -0
- package/dist/scoring/types.d.ts +103 -20
- package/dist/shared/aggregate.d.ts +1 -0
- package/dist/shared/aggregate.js +3 -3
- package/dist/shared/types.d.ts +28 -0
- package/dist/tty-line.d.ts +0 -4
- package/dist/util.d.ts +23 -0
- package/docs-site/zh/concepts/adapter.mdx +24 -6
- package/docs-site/zh/concepts/assert.mdx +11 -10
- package/docs-site/zh/concepts/evals.mdx +7 -6
- package/docs-site/zh/concepts/experiment.mdx +1 -1
- package/docs-site/zh/concepts/overview.mdx +7 -7
- package/docs-site/zh/guides/agent-feedback-loop.mdx +35 -31
- package/docs-site/zh/guides/authoring.mdx +33 -0
- package/docs-site/zh/guides/ci-integration.mdx +23 -12
- package/docs-site/zh/guides/connect-your-agent.mdx +29 -3
- package/docs-site/zh/guides/custom-reports.mdx +29 -34
- package/docs-site/zh/guides/dataset-fanout.mdx +25 -3
- package/docs-site/zh/guides/debug-sandbox.mdx +57 -0
- package/docs-site/zh/guides/debugging.mdx +210 -0
- package/docs-site/zh/guides/experiments.mdx +10 -3
- package/docs-site/zh/guides/fixtures.mdx +3 -1
- package/docs-site/zh/guides/official-adapters.mdx +27 -3
- package/docs-site/zh/guides/publish-report.mdx +30 -16
- package/docs-site/zh/guides/report-components.mdx +49 -37
- package/docs-site/zh/guides/reporters.mdx +2 -2
- package/docs-site/zh/guides/results-data.mdx +42 -8
- package/docs-site/zh/guides/runner.mdx +17 -7
- package/docs-site/zh/guides/sandbox-agent.mdx +57 -7
- package/docs-site/zh/guides/sandbox-providers.mdx +258 -10
- package/docs-site/zh/guides/scoring-guide.mdx +4 -4
- package/docs-site/zh/guides/viewing-results.mdx +85 -41
- package/docs-site/zh/guides/write-experiment.mdx +5 -3
- package/docs-site/zh/guides/write-send.mdx +19 -2
- package/docs-site/zh/index.mdx +1 -1
- package/docs-site/zh/reference/builtin-agents.mdx +27 -0
- package/docs-site/zh/reference/capabilities.mdx +2 -2
- package/docs-site/zh/reference/cli.mdx +35 -9
- package/docs-site/zh/reference/define-agent.mdx +60 -5
- package/docs-site/zh/reference/define-config.mdx +1 -1
- package/docs-site/zh/reference/define-eval.mdx +42 -9
- package/docs-site/zh/reference/events.mdx +2 -2
- package/docs-site/zh/reference/expect.mdx +36 -6
- package/package.json +5 -1
- package/src/agents/ai-sdk-otel.test.ts +1 -0
- package/src/agents/ai-sdk.test.ts +3 -0
- package/src/agents/ai-sdk.ts +3 -0
- package/src/agents/bub-install-spec.test.ts +34 -0
- package/src/agents/bub-install-spec.ts +32 -0
- package/src/agents/bub.ts +31 -32
- package/src/agents/claude-code.test.ts +130 -9
- package/src/agents/claude-code.ts +76 -4
- package/src/agents/codex.test.ts +189 -40
- package/src/agents/codex.ts +155 -14
- package/src/agents/coding-cli-versions.test.ts +15 -0
- package/src/agents/coding-cli-versions.ts +3 -0
- package/src/agents/index.ts +11 -0
- package/src/agents/langgraph.test.ts +204 -0
- package/src/agents/langgraph.ts +495 -0
- package/src/agents/marketplace.ts +85 -0
- package/src/agents/native-config.test.ts +179 -0
- package/src/agents/native-config.ts +267 -0
- package/src/agents/openai-compat.test.ts +1 -0
- package/src/agents/openclaw.test.ts +31 -0
- package/src/agents/openclaw.ts +171 -0
- package/src/agents/plugin-config.test.ts +1 -0
- package/src/agents/sdk-streams.test.ts +79 -0
- package/src/agents/sdk-streams.ts +55 -10
- package/src/agents/skills.test.ts +1 -0
- package/src/agents/streaming.test.ts +3 -9
- package/src/agents/types.ts +73 -6
- package/src/agents/ui-message-stream.test.ts +3 -0
- package/src/cli.ts +411 -108
- package/src/context/context.test.ts +51 -12
- package/src/context/context.ts +161 -29
- package/src/context/session.test.ts +1 -0
- package/src/context/session.ts +114 -6
- package/src/context/types.ts +30 -12
- package/src/define.test.ts +13 -8
- package/src/define.ts +25 -4
- package/src/expect/index.ts +53 -23
- package/src/i18n/en.ts +65 -4
- package/src/i18n/zh-CN.ts +66 -4
- package/src/o11y/cost.test.ts +1 -0
- package/src/o11y/execution-tree.test.ts +1 -20
- package/src/o11y/otlp/mappers/claude-code.test.ts +1 -0
- package/src/o11y/otlp/parse.test.ts +1 -0
- package/src/o11y/otlp/turn-otel.test.ts +1 -0
- package/src/o11y/parsers/bub.test.ts +1 -0
- package/src/o11y/parsers/claude-code.test.ts +1 -34
- package/src/o11y/parsers/openclaw.test.ts +154 -0
- package/src/o11y/parsers/openclaw.ts +310 -0
- package/src/o11y/prices.json +746 -311
- package/src/o11y/tool-names.test.ts +1 -0
- package/src/o11y/types.ts +16 -2
- package/src/report/aggregate.ts +34 -5
- package/src/report/built-in-user-parity.test.tsx +127 -173
- package/src/report/built-ins/experiment-comparison.tsx +179 -0
- package/src/report/built-ins/index.ts +7 -2
- package/src/report/components.tsx +11 -3
- package/src/report/compute.ts +80 -74
- package/src/report/dual-render.test.tsx +222 -91
- package/src/report/flag.ts +30 -2
- package/src/report/format.ts +36 -27
- package/src/report/index.ts +23 -6
- package/src/report/locale.ts +49 -6
- package/src/report/metrics.ts +68 -15
- package/src/report/primitives.tsx +6 -0
- package/src/report/react/AttemptList.tsx +9 -36
- package/src/report/react/EvalList.tsx +0 -0
- package/src/report/react/ExperimentComparison.tsx +68 -0
- package/src/report/react/ExperimentList.tsx +173 -55
- package/src/report/react/MetricScatter.tsx +13 -25
- package/src/report/react/chart-math.test.ts +85 -0
- package/src/report/react/chart-math.ts +101 -22
- package/src/report/react/enhance.js +72 -1
- package/src/report/react/fixtures.ts +34 -21
- package/src/report/react/format.ts +1 -1
- package/src/report/react/index.tsx +0 -1
- package/src/report/react/render.test.tsx +30 -69
- package/src/report/react/styles.css +112 -14
- package/src/report/report.test.ts +308 -105
- package/src/report/report.ts +6 -2
- package/src/report/text/faces.ts +111 -67
- package/src/report/text/table.ts +42 -5
- package/src/report/types.ts +42 -34
- package/src/results/annotated-source.test.ts +62 -9
- package/src/results/annotated-source.ts +64 -6
- package/src/results/attempt-evidence.test.ts +9 -7
- package/src/results/attempt-evidence.ts +15 -8
- package/src/results/attempt-source.ts +6 -3
- package/src/results/copy.ts +145 -55
- package/src/results/host-equivalence.test.ts +11 -9
- package/src/results/index.ts +2 -0
- package/src/results/locator.test.ts +1 -22
- package/src/results/open.ts +7 -1
- package/src/results/publish.ts +149 -0
- package/src/results/results.test.ts +85 -51
- package/src/results/truncate.ts +90 -0
- package/src/results/types.ts +7 -0
- package/src/results/writer.ts +31 -13
- package/src/runner/attempt.test.ts +138 -7
- package/src/runner/attempt.ts +603 -104
- package/src/runner/discover.test.ts +47 -0
- package/src/runner/discover.ts +36 -2
- package/src/runner/eval-source.test.ts +1 -27
- package/src/runner/feedback/agent.test.ts +504 -0
- package/src/runner/feedback/agent.ts +409 -0
- package/src/runner/feedback/ci.test.ts +562 -0
- package/src/runner/feedback/ci.ts +401 -0
- package/src/runner/feedback/coordinator.test.ts +317 -0
- package/src/runner/feedback/coordinator.ts +397 -0
- package/src/runner/feedback/failure.ts +40 -0
- package/src/runner/feedback/human.test.ts +616 -0
- package/src/runner/feedback/human.ts +535 -0
- package/src/runner/feedback/index.ts +66 -0
- package/src/runner/feedback/io.ts +78 -0
- package/src/runner/feedback/profile.test.ts +50 -0
- package/src/runner/feedback/profile.ts +58 -0
- package/src/runner/feedback/reducer.test.ts +395 -0
- package/src/runner/feedback/reducer.ts +260 -0
- package/src/runner/feedback/renderer.ts +82 -0
- package/src/runner/feedback/sink.ts +203 -0
- package/src/runner/feedback/testing.ts +106 -0
- package/src/runner/ledger.test.ts +230 -0
- package/src/runner/ledger.ts +329 -0
- package/src/runner/report.test.ts +128 -3
- package/src/runner/report.ts +33 -9
- package/src/runner/reporters/artifacts.ts +8 -2
- package/src/runner/reporters/braintrust.test.ts +8 -7
- package/src/runner/reporters/braintrust.ts +9 -2
- package/src/runner/reporters/index.ts +2 -2
- package/src/runner/reporters/json.test.ts +162 -0
- package/src/runner/reporters/json.ts +35 -8
- package/src/runner/reporters/shared.ts +1 -5
- package/src/runner/run.test.ts +760 -3
- package/src/runner/run.ts +242 -36
- package/src/runner/sandbox-prep.ts +3 -42
- package/src/runner/timing.ts +158 -0
- package/src/runner/types.ts +518 -22
- package/src/sandbox/checkpoint.test.ts +55 -0
- package/src/sandbox/checkpoint.ts +29 -8
- package/src/sandbox/cli-commands.ts +407 -0
- package/src/sandbox/docker.ts +115 -16
- package/src/sandbox/e2b-agent-template.test.ts +56 -0
- package/src/sandbox/e2b-agent-template.ts +94 -0
- package/src/sandbox/e2b.ts +74 -9
- package/src/sandbox/errors.ts +111 -4
- package/src/sandbox/index.ts +2 -0
- package/src/sandbox/io-retry.test.ts +58 -0
- package/src/sandbox/io-retry.ts +45 -0
- package/src/sandbox/keep-registry.test.ts +86 -0
- package/src/sandbox/keep-registry.ts +142 -0
- package/src/sandbox/keep.ts +178 -0
- package/src/sandbox/paths.test.ts +1 -0
- package/src/sandbox/paths.ts +19 -8
- package/src/sandbox/registry.ts +20 -3
- package/src/sandbox/resolve.ts +76 -11
- package/src/sandbox/retry.test.ts +70 -0
- package/src/sandbox/retry.ts +46 -4
- package/src/sandbox/types.ts +44 -6
- package/src/sandbox/vercel.ts +43 -20
- package/src/scoring/collector.ts +60 -17
- package/src/scoring/coverage.ts +95 -0
- package/src/scoring/diff.ts +81 -0
- package/src/scoring/display.test.ts +121 -0
- package/src/scoring/display.ts +133 -0
- package/src/scoring/evidence.test.ts +189 -0
- package/src/scoring/judge.test.ts +142 -0
- package/src/scoring/judge.ts +15 -18
- package/src/scoring/scoped.ts +217 -50
- package/src/scoring/types.ts +117 -20
- package/src/scoring/verdict.ts +16 -4
- package/src/shared/aggregate.ts +3 -2
- package/src/shared/types.ts +31 -0
- package/src/show/compose.ts +2 -2
- package/src/show/index.ts +29 -16
- package/src/show/render.ts +626 -308
- package/src/show/show.test.ts +251 -36
- package/src/tty-line.ts +8 -26
- package/src/util.test.ts +1 -0
- package/src/util.ts +41 -0
- package/src/view/app/components/AttemptModal.tsx +153 -2
- package/src/view/app/components/CodeView.tsx +32 -11
- package/src/view/app/components/CopyControls.tsx +2 -2
- package/src/view/app/i18n.ts +6 -0
- package/src/view/app/lib/attempt-route.test.ts +1 -0
- package/src/view/app/lib/verdict.ts +7 -9
- package/src/view/artifact-serving.test.ts +2 -1
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +17 -17
- package/src/view/data.test.ts +2 -1
- package/src/view/data.ts +17 -7
- package/src/view/index.ts +12 -1
- package/src/view/server.ts +2 -0
- package/src/view/shared/types.ts +1 -1
- package/src/view/styles.css +3 -0
- package/src/view/view-report.test.ts +11 -10
- package/dist/o11y/execution-tree.d.ts +0 -103
- package/dist/o11y/otlp/select.d.ts +0 -22
- package/dist/report/built-ins/cost-pass-rate-comparison.d.ts +0 -1
- package/dist/report/built-ins/cost-pass-rate-comparison.js +0 -17
- package/dist/results/annotated-source.d.ts +0 -61
- package/dist/results/attempt-evidence.d.ts +0 -69
- package/dist/results/attempt-source.d.ts +0 -15
- package/src/report/built-ins/cost-pass-rate-comparison.tsx +0 -23
- package/src/runner/reporters/console.ts +0 -70
- package/src/runner/reporters/live.test.ts +0 -56
- package/src/runner/reporters/live.ts +0 -247
- package/src/runner/reporters/quiet.test.ts +0 -66
- package/src/runner/reporters/quiet.ts +0 -49
- package/src/runner/reporters/table.ts +0 -277
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// cases: docs/engineering/unit-tests/adapters/cases.md
|
|
1
2
|
import { describe, expect, it } from "vitest";
|
|
2
3
|
|
|
3
4
|
import { fromClaudeSdkMessages, fromCodexThreadEvents, fromPiAgentEvents, sseJsonFrames } from "./sdk-streams.ts";
|
|
@@ -50,6 +51,26 @@ describe("fromClaudeSdkMessages", () => {
|
|
|
50
51
|
expect(s.add({ type: "user", message: { content: [{ type: "tool_result", tool_use_id: "tu1", content: "denied" }] } })).toEqual([]);
|
|
51
52
|
});
|
|
52
53
|
|
|
54
|
+
it("assistant 的 thinking 块 → thinking 事件,与 text/tool_use 保持原始顺序", () => {
|
|
55
|
+
const s = fromClaudeSdkMessages();
|
|
56
|
+
expect(
|
|
57
|
+
s.add({
|
|
58
|
+
type: "assistant",
|
|
59
|
+
message: {
|
|
60
|
+
content: [
|
|
61
|
+
{ type: "thinking", thinking: "先查天气", signature: "sig-1" },
|
|
62
|
+
{ type: "text", text: "我来查" },
|
|
63
|
+
{ type: "tool_use", id: "tu1", name: "get_weather", input: { city: "北京" } },
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
}),
|
|
67
|
+
).toEqual([
|
|
68
|
+
{ type: "thinking", text: "先查天气" },
|
|
69
|
+
{ type: "message", role: "assistant", text: "我来查" },
|
|
70
|
+
{ type: "action.called", callId: "tu1", name: "get_weather", input: { city: "北京" } },
|
|
71
|
+
]);
|
|
72
|
+
});
|
|
73
|
+
|
|
53
74
|
it("stream_event 等未知帧返回 []", () => {
|
|
54
75
|
expect(fromClaudeSdkMessages().add({ type: "stream_event" })).toEqual([]);
|
|
55
76
|
});
|
|
@@ -86,6 +107,64 @@ describe("fromPiAgentEvents", () => {
|
|
|
86
107
|
{ type: "action.result", callId: "c9", output: undefined, status: "rejected" },
|
|
87
108
|
]);
|
|
88
109
|
});
|
|
110
|
+
|
|
111
|
+
it("三段式聚合成一条:start/delta 不产事件,end 帧的完整 content 只落一条", () => {
|
|
112
|
+
const s = fromPiAgentEvents();
|
|
113
|
+
expect(s.add({ type: "message_start", message: { role: "assistant", content: [] } })).toEqual([]);
|
|
114
|
+
expect(s.add({ type: "message_update", assistantMessageEvent: { type: "text_delta", contentIndex: 0, delta: "18" } })).toEqual([]);
|
|
115
|
+
expect(s.add({ type: "message_update", assistantMessageEvent: { type: "text_delta", contentIndex: 0, delta: " 度" } })).toEqual([]);
|
|
116
|
+
// end 帧带完整 content:以它为准,增量不重复落地
|
|
117
|
+
expect(s.add({ type: "message_end", message: { role: "assistant", content: [{ type: "text", text: "18 度" }] } })).toEqual([
|
|
118
|
+
{ type: "message", role: "assistant", text: "18 度" },
|
|
119
|
+
]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("end 帧缺 content 时用累加的 text/thinking 增量兜底", () => {
|
|
123
|
+
const s = fromPiAgentEvents();
|
|
124
|
+
s.add({ type: "message_start", message: { role: "assistant" } });
|
|
125
|
+
s.add({ type: "message_update", assistantMessageEvent: { type: "thinking_delta", contentIndex: 0, delta: "想" } });
|
|
126
|
+
s.add({ type: "message_update", assistantMessageEvent: { type: "thinking_delta", contentIndex: 0, delta: "想" } });
|
|
127
|
+
s.add({ type: "message_update", assistantMessageEvent: { type: "text_delta", contentIndex: 1, delta: "18 度" } });
|
|
128
|
+
expect(s.add({ type: "message_end", message: { role: "assistant" } })).toEqual([
|
|
129
|
+
{ type: "message", role: "assistant", text: "18 度" },
|
|
130
|
+
{ type: "thinking", text: "想想" },
|
|
131
|
+
]);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("只有 start/delta 的截断流不产半条消息,下一条消息不串入旧增量", () => {
|
|
135
|
+
const s = fromPiAgentEvents();
|
|
136
|
+
expect(s.add({ type: "message_start", message: { role: "assistant" } })).toEqual([]);
|
|
137
|
+
expect(s.add({ type: "message_update", assistantMessageEvent: { type: "text_delta", contentIndex: 0, delta: "半截" } })).toEqual([]);
|
|
138
|
+
// 流在这里断掉:没有 message_end,什么都不落地。新消息开始后旧增量作废。
|
|
139
|
+
expect(s.add({ type: "message_start", message: { role: "assistant" } })).toEqual([]);
|
|
140
|
+
expect(s.add({ type: "message_end", message: { role: "assistant", content: [{ type: "text", text: "新消息" }] } })).toEqual([
|
|
141
|
+
{ type: "message", role: "assistant", text: "新消息" },
|
|
142
|
+
]);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("失败状态帧:stopReason error/aborted → error 事件 + failed", () => {
|
|
146
|
+
const s = fromPiAgentEvents();
|
|
147
|
+
expect(s.failed).toBe(false);
|
|
148
|
+
expect(
|
|
149
|
+
s.add({ type: "message_end", message: { role: "assistant", content: [{ type: "text", text: "试到一半" }], stopReason: "error", errorMessage: "boom" } }),
|
|
150
|
+
).toEqual([
|
|
151
|
+
{ type: "message", role: "assistant", text: "试到一半" },
|
|
152
|
+
{ type: "error", message: "boom" },
|
|
153
|
+
]);
|
|
154
|
+
expect(s.failed).toBe(true);
|
|
155
|
+
|
|
156
|
+
const aborted = fromPiAgentEvents();
|
|
157
|
+
expect(aborted.add({ type: "message_end", message: { role: "assistant", stopReason: "aborted" } })).toEqual([
|
|
158
|
+
{ type: "error", message: "pi agent stopReason=aborted" },
|
|
159
|
+
]);
|
|
160
|
+
expect(aborted.failed).toBe(true);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("正常收尾(stopReason stop/toolUse)不置 failed", () => {
|
|
164
|
+
const s = fromPiAgentEvents();
|
|
165
|
+
s.add({ type: "message_end", message: { role: "assistant", content: [{ type: "text", text: "好了" }], stopReason: "stop" } });
|
|
166
|
+
expect(s.failed).toBe(false);
|
|
167
|
+
});
|
|
89
168
|
});
|
|
90
169
|
|
|
91
170
|
describe("fromCodexThreadEvents", () => {
|
|
@@ -96,10 +96,10 @@ export interface ClaudeSdkStream {
|
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
98
|
* Claude Agent SDK 消息流(`system` / `assistant` / `user` / `result`)→ 标准事件。
|
|
99
|
-
* `assistant` 的 text/tool_use 块 → message / action.called;`user` 的
|
|
100
|
-
* action.result;`system`/`permission_denied` → rejected;`stream_event`
|
|
101
|
-
* 整个忽略。HITL 的停轮判定(哪个工具被门控)
|
|
102
|
-
* 返回的 action.called 自行决定。
|
|
99
|
+
* `assistant` 的 text/thinking/tool_use 块 → message / thinking / action.called;`user` 的
|
|
100
|
+
* tool_result 块 → action.result;`system`/`permission_denied` → rejected;`stream_event`
|
|
101
|
+
* (逐 token 渲染)整个忽略。HITL 的停轮判定(哪个工具被门控)是应用侧的知识,不在这里——
|
|
102
|
+
* 扫描 add() 返回的 action.called 自行决定。
|
|
103
103
|
*/
|
|
104
104
|
export function fromClaudeSdkMessages(): ClaudeSdkStream {
|
|
105
105
|
let sessionId: string | undefined;
|
|
@@ -152,6 +152,8 @@ export function fromClaudeSdkMessages(): ClaudeSdkStream {
|
|
|
152
152
|
if (!isRecord(block)) continue;
|
|
153
153
|
if (block.type === "text" && typeof block.text === "string" && block.text) {
|
|
154
154
|
events.push({ type: "message", role: "assistant", text: block.text });
|
|
155
|
+
} else if (block.type === "thinking" && typeof block.thinking === "string" && block.thinking) {
|
|
156
|
+
events.push({ type: "thinking", text: block.thinking });
|
|
155
157
|
} else if (block.type === "tool_use" && typeof block.id === "string" && typeof block.name === "string") {
|
|
156
158
|
events.push({ type: "action.called", callId: block.id, name: block.name, input: block.input as JsonValue });
|
|
157
159
|
}
|
|
@@ -209,8 +211,14 @@ export interface PiAgentEventLike {
|
|
|
209
211
|
message?: {
|
|
210
212
|
role?: string;
|
|
211
213
|
content?: unknown;
|
|
214
|
+
/** assistant 消息的收尾原因;"error" / "aborted" 表示这条消息以失败告终。 */
|
|
215
|
+
stopReason?: string;
|
|
216
|
+
/** stopReason 为 "error" 时的错误说明。 */
|
|
217
|
+
errorMessage?: string;
|
|
212
218
|
usage?: { input: number; output: number; cacheRead: number; cacheWrite: number; cost: { total: number } };
|
|
213
219
|
};
|
|
220
|
+
/** `message_update` 帧携带的增量事件(text_delta / thinking_delta 等)——只读 type/delta,防御式解析。 */
|
|
221
|
+
assistantMessageEvent?: { type?: string; delta?: unknown; [key: string]: unknown };
|
|
214
222
|
[key: string]: unknown;
|
|
215
223
|
}
|
|
216
224
|
|
|
@@ -219,17 +227,27 @@ export interface PiAgentStream {
|
|
|
219
227
|
add(event: PiAgentEventLike): StreamEvent[];
|
|
220
228
|
/** assistant `message_end` 逐条累加的用量。 */
|
|
221
229
|
readonly usage: Usage | undefined;
|
|
230
|
+
/** assistant 消息以 stopReason "error" / "aborted" 收尾过。 */
|
|
231
|
+
readonly failed: boolean;
|
|
222
232
|
/** 拒绝审批后续读前登记:该调用 `tool_execution_end` 的 isError 判成 "rejected" 而非 "failed"。 */
|
|
223
233
|
markRejected(toolCallId: string): void;
|
|
224
234
|
}
|
|
225
235
|
|
|
226
236
|
/**
|
|
227
|
-
* pi-agent-core 事件流(`
|
|
228
|
-
*
|
|
237
|
+
* pi-agent-core 事件流(`message_start` / `message_update` / `message_end` /
|
|
238
|
+
* `tool_execution_start` / `tool_execution_end`)→ 标准事件。消息三段式聚合成一条:
|
|
239
|
+
* message_start 清空增量缓冲、message_update 的 text_delta / thinking_delta 逐段累加、
|
|
240
|
+
* message_end 落地成 message / thinking(优先取 end 帧的完整 content,缺了用累加的增量兜底);
|
|
241
|
+
* 只有 start/delta 的截断流不产出半条消息。message_end 同时累加 usage;assistant 消息以
|
|
242
|
+
* stopReason "error" / "aborted" 收尾时记失败(`failed`)并发一条 error 事件。
|
|
229
243
|
* tool_execution_start/end → action.called / action.result。
|
|
230
244
|
*/
|
|
231
245
|
export function fromPiAgentEvents(): PiAgentStream {
|
|
232
246
|
let usage: Usage | undefined;
|
|
247
|
+
let failed = false;
|
|
248
|
+
// message_start/update 累加的增量缓冲;message_end 落地后清空,截断流(无 end)不落地。
|
|
249
|
+
let deltaText = "";
|
|
250
|
+
let deltaThinking = "";
|
|
233
251
|
const rejected = new Set<string>();
|
|
234
252
|
|
|
235
253
|
const partText = (event: PiAgentEventLike, type: "text" | "thinking"): string => {
|
|
@@ -247,17 +265,44 @@ export function fromPiAgentEvents(): PiAgentStream {
|
|
|
247
265
|
get usage() {
|
|
248
266
|
return usage;
|
|
249
267
|
},
|
|
268
|
+
get failed() {
|
|
269
|
+
return failed;
|
|
270
|
+
},
|
|
250
271
|
markRejected(toolCallId) {
|
|
251
272
|
rejected.add(toolCallId);
|
|
252
273
|
},
|
|
253
274
|
add(event) {
|
|
254
275
|
const events: StreamEvent[] = [];
|
|
255
276
|
switch (event.type) {
|
|
277
|
+
case "message_start": {
|
|
278
|
+
// 新消息开始:上一条没等到 message_end 的增量作废(不落地半条消息)。
|
|
279
|
+
deltaText = "";
|
|
280
|
+
deltaThinking = "";
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
case "message_update": {
|
|
284
|
+
const e = event.assistantMessageEvent;
|
|
285
|
+
if (isRecord(e) && typeof e.delta === "string") {
|
|
286
|
+
if (e.type === "text_delta") deltaText += e.delta;
|
|
287
|
+
else if (e.type === "thinking_delta") deltaThinking += e.delta;
|
|
288
|
+
}
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
256
291
|
case "message_end": {
|
|
257
|
-
|
|
292
|
+
// 优先取 end 帧的完整 content;缺了(部分传输只带增量)用累加的 delta 兜底。
|
|
293
|
+
const text = partText(event, "text") || (event.message?.role === "assistant" ? deltaText : "");
|
|
258
294
|
if (text) events.push({ type: "message", role: "assistant", text });
|
|
259
|
-
const thinking = partText(event, "thinking");
|
|
295
|
+
const thinking = partText(event, "thinking") || (event.message?.role === "assistant" ? deltaThinking : "");
|
|
260
296
|
if (thinking) events.push({ type: "thinking", text: thinking });
|
|
297
|
+
deltaText = "";
|
|
298
|
+
deltaThinking = "";
|
|
299
|
+
if (event.message?.role === "assistant") {
|
|
300
|
+
const stopReason = event.message.stopReason;
|
|
301
|
+
if (stopReason === "error" || stopReason === "aborted") {
|
|
302
|
+
failed = true;
|
|
303
|
+
events.push({ type: "error", message: event.message.errorMessage ?? `pi agent stopReason=${stopReason}` });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
261
306
|
const u = event.message?.role === "assistant" ? event.message.usage : undefined;
|
|
262
307
|
if (u) {
|
|
263
308
|
usage = {
|
|
@@ -284,8 +329,8 @@ export function fromPiAgentEvents(): PiAgentStream {
|
|
|
284
329
|
}
|
|
285
330
|
break;
|
|
286
331
|
}
|
|
287
|
-
// agent_start / turn_start / turn_end /
|
|
288
|
-
//
|
|
332
|
+
// agent_start / turn_start / turn_end / tool_execution_update / agent_end:
|
|
333
|
+
// 无对应 StreamEvent(消息文本统一在 message_end 落地)。
|
|
289
334
|
default:
|
|
290
335
|
break;
|
|
291
336
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// cases: docs/engineering/unit-tests/adapters/cases.md
|
|
1
2
|
import { describe, expect, it } from "vitest";
|
|
2
3
|
|
|
3
4
|
import { deltaStream, driveFrameStream } from "./streaming.ts";
|
|
@@ -12,6 +13,8 @@ function lineCtx(): AgentContext {
|
|
|
12
13
|
flags: {},
|
|
13
14
|
session: createAgentSession(),
|
|
14
15
|
sandbox: undefined as never,
|
|
16
|
+
progress() {},
|
|
17
|
+
diagnostic() {},
|
|
15
18
|
log() {},
|
|
16
19
|
};
|
|
17
20
|
}
|
|
@@ -73,15 +76,6 @@ describe("deltaStream", () => {
|
|
|
73
76
|
expect(s.add({ finish_reason: "tool_calls" })).toEqual([{ type: "action.called", callId: "call_2", name: "broken", input: "not json" }]);
|
|
74
77
|
});
|
|
75
78
|
|
|
76
|
-
it("tool-result 独立到达,配对靠 core 的 deriveRunFacts,这里只管落地成 action.result", () => {
|
|
77
|
-
const s = deltaStream<{ result?: { callId: string; output: string } }>({
|
|
78
|
-
toOps: (f) => (f.result ? [{ kind: "tool-result", callId: f.result.callId, output: f.result.output, status: "completed" }] : []),
|
|
79
|
-
});
|
|
80
|
-
expect(s.add({ result: { callId: "call_1", output: "22C" } })).toEqual([
|
|
81
|
-
{ type: "action.result", callId: "call_1", output: "22C", status: "completed" },
|
|
82
|
-
]);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
79
|
it("error 操作:落地未完成的文本、置 failed、附一条 error 事件", () => {
|
|
86
80
|
const s = deltaStream({ toOps });
|
|
87
81
|
s.add({ delta: { content: "还没说完" } });
|
package/src/agents/types.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// 「连到哪个被测对象、协议怎么说」的全部契约在这里(见 docs-site/zh/concepts/adapter.mdx)。
|
|
3
3
|
// 能力不再是问卷式声明:t 上解锁什么完全由构造证据决定(见 docs-site 「能力从哪来」一节)。
|
|
4
4
|
|
|
5
|
-
import type { Cleanup } from "../shared/types.ts";
|
|
5
|
+
import type { Cleanup, DiagnosticInput, ProgressUpdate } from "../shared/types.ts";
|
|
6
6
|
import type { StreamEvent, TraceSpan, Usage } from "../o11y/types.ts";
|
|
7
7
|
import type { Sandbox } from "../sandbox/types.ts";
|
|
8
8
|
|
|
@@ -69,10 +69,51 @@ export interface AgentSetupManifest {
|
|
|
69
69
|
}>;
|
|
70
70
|
/** 挂上的 MCP server(不含 env:secret 不进 manifest)。 */
|
|
71
71
|
mcpServers?: Array<{ name: string; command: string; args?: string[] }>;
|
|
72
|
+
/**
|
|
73
|
+
* 官方原生配置文件(Claude Code `settings.json` / Codex `config.toml`):只记 Agent 名、
|
|
74
|
+
* 项目相对来源路径与原始字节的 SHA-256,不落正文 —— 任意官方配置都可能携带敏感字符串,
|
|
75
|
+
* 不能靠字段白名单证明适合原样落盘。
|
|
76
|
+
*/
|
|
77
|
+
nativeConfigFile?: { agent: "claude-code" | "codex"; path: string; sha256: string };
|
|
72
78
|
/** Bub 的 Python Plugin(规范化后的 package 串)。 */
|
|
73
79
|
pythonPlugins?: Array<{ package: string }>;
|
|
74
80
|
}
|
|
75
81
|
|
|
82
|
+
// ───────────────────────── 证据覆盖声明 ─────────────────────────
|
|
83
|
+
|
|
84
|
+
/** 证据通道的覆盖状态。省略(不声明)= unknown,不是 complete——消费侧与 unavailable 同样保守。 */
|
|
85
|
+
export type CoverageStatus = "complete" | "partial" | "unavailable";
|
|
86
|
+
|
|
87
|
+
/** 单个证据通道的覆盖声明:状态 + 可选的人可读原因(如 "stream reconnected mid-turn")。 */
|
|
88
|
+
export interface CoverageDeclaration {
|
|
89
|
+
status: CoverageStatus;
|
|
90
|
+
reason?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* 覆盖声明(EvidenceCoverage):完整性不是口头承诺,是随数据走的声明
|
|
95
|
+
* (见 docs/feature/adapters/architecture/evidence.md)。两层:
|
|
96
|
+
* - Agent 级默认(`defineAgent` / `defineSandboxAgent` 的 `coverage`)声明该 Adapter 的常态覆盖;
|
|
97
|
+
* 官方 SDK 适配器显式声明全通道 complete(用 `completeCoverage` 常量)。
|
|
98
|
+
* - Turn 级降级(`Turn.coverage`)只用于相对 Agent 默认值降级(这一轮流断了 / 拿不到 usage),
|
|
99
|
+
* 不能把 Agent 未声明的通道升格成 complete。
|
|
100
|
+
* 整个 Agent 不声明时全部通道视为 unknown。
|
|
101
|
+
*/
|
|
102
|
+
export interface EvidenceCoverage {
|
|
103
|
+
/** 完整事件流(event / notEvent / order 的依据)。 */
|
|
104
|
+
events?: CoverageDeclaration;
|
|
105
|
+
/** action 生命周期(工具正负断言、顺序、失败的依据)。 */
|
|
106
|
+
actions?: CoverageDeclaration;
|
|
107
|
+
/** assistant / user message(reply、messageIncludes 的依据)。 */
|
|
108
|
+
messages?: CoverageDeclaration;
|
|
109
|
+
/** usage(token / cost 上限断言的依据)。 */
|
|
110
|
+
usage?: CoverageDeclaration;
|
|
111
|
+
/** Turn status 的真实性(succeeded / parked 的依据)——恒 completed 的映射必须声明非 complete。 */
|
|
112
|
+
status?: CoverageDeclaration;
|
|
113
|
+
/** Turn.data(outputEquals / outputMatches 的依据)。 */
|
|
114
|
+
data?: CoverageDeclaration;
|
|
115
|
+
}
|
|
116
|
+
|
|
76
117
|
/** 随一轮消息附带的文件(图片等多模态输入)。 */
|
|
77
118
|
export interface InputFile {
|
|
78
119
|
/** 文件名(可选,供 adapter / 模型参考)。 */
|
|
@@ -111,6 +152,11 @@ export interface Turn {
|
|
|
111
152
|
readonly data?: unknown;
|
|
112
153
|
readonly status: "completed" | "failed" | "waiting";
|
|
113
154
|
readonly usage?: Usage;
|
|
155
|
+
/**
|
|
156
|
+
* 本轮相对 Agent 默认覆盖的降级声明(这一轮流断了、拿不到 usage 等);
|
|
157
|
+
* 只能降级,不能把 Agent 未声明的通道升格成 complete(见 EvidenceCoverage)。
|
|
158
|
+
*/
|
|
159
|
+
readonly coverage?: EvidenceCoverage;
|
|
114
160
|
}
|
|
115
161
|
|
|
116
162
|
/**
|
|
@@ -221,7 +267,11 @@ export interface AgentContext {
|
|
|
221
267
|
* 具体取值)是两个维度——这里只是「跑的是哪个实验」的稳定标识,不携带条件内容。
|
|
222
268
|
*/
|
|
223
269
|
readonly experimentId?: string;
|
|
224
|
-
/**
|
|
270
|
+
/**
|
|
271
|
+
* 所有 agent 都有:沙箱型是运行器按项目/experiment 配置备好的真实沙箱句柄,remote 型是
|
|
272
|
+
* `createRemoteSandbox()` 产出的 stub(仅含 `workdir`/`sandboxId`/`otlpHost`/`stop` 等
|
|
273
|
+
* 元信息,其余方法调用即抛错)。
|
|
274
|
+
*/
|
|
225
275
|
readonly sandbox: Sandbox;
|
|
226
276
|
readonly session: AgentSession;
|
|
227
277
|
/**
|
|
@@ -234,10 +284,21 @@ export interface AgentContext {
|
|
|
234
284
|
*/
|
|
235
285
|
readonly telemetry?: Telemetry;
|
|
236
286
|
/**
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
* (
|
|
287
|
+
* 作用域反馈:报告此刻正在做什么(turn / tool / 安装进度)。短命状态——Human profile
|
|
288
|
+
* 更新 active 行,`agent`/`ci` 不逐条打印,也不进最终结果;不要每个 token/delta 都调用。
|
|
289
|
+
* runner 按当前回调所处的生命周期阶段(agent.setup / agent.run / agent.teardown)归因,
|
|
290
|
+
* 调用方不能冒充其它阶段(见 docs/feature/experiments/library.md)。
|
|
291
|
+
*/
|
|
292
|
+
progress(update: ProgressUpdate): void;
|
|
293
|
+
/**
|
|
294
|
+
* 作用域反馈:报告运行结束后仍应保留的问题(协议降级、数据不完整、cleanup 问题)。
|
|
295
|
+
* 永久事件,落进 attempt 的 diagnostics 并进各 profile 的永久输出;`dedupeKey` 去重。
|
|
296
|
+
* 即使 level 为 "error" 也不改变 Turn.status / verdict——无法继续时抛异常。
|
|
297
|
+
*/
|
|
298
|
+
diagnostic(input: DiagnosticInput): void;
|
|
299
|
+
/**
|
|
300
|
+
* `progress({ message: msg })` 的别名,不是第二条通道(见 docs/feature/experiments/cli.md
|
|
301
|
+
* 「Attempt 阶段」)。超时失败时最近若干行会并入结果的 error 信息,方便定位卡在哪一步。
|
|
241
302
|
*/
|
|
242
303
|
log(msg: string): void;
|
|
243
304
|
}
|
|
@@ -268,6 +329,8 @@ export interface Agent {
|
|
|
268
329
|
* `t.sandbox`/`t.sandbox.fileChanged()` 等文件系统断言,见 docs-site「能力从哪来」一节。
|
|
269
330
|
*/
|
|
270
331
|
readonly kind: "sandbox" | "remote";
|
|
332
|
+
/** 该 Adapter 的常态证据覆盖声明;省略 = 全通道 unknown(见 EvidenceCoverage)。 */
|
|
333
|
+
coverage?: EvidenceCoverage;
|
|
271
334
|
setup?: AgentSetup;
|
|
272
335
|
/** OTLP 导出配置(仅当此字段存在时运行器才为该 agent 开 OTLP 接收);与 setup 分开,见 AgentTracing。 */
|
|
273
336
|
tracing?: AgentTracing;
|
|
@@ -281,6 +344,8 @@ export interface Agent {
|
|
|
281
344
|
export interface SandboxAgentDef {
|
|
282
345
|
/** agent 的显示名/标识,原样进入 `Agent.name`——不是注册表查找 key,只用于展示、结果归属与去重指纹。 */
|
|
283
346
|
name: string;
|
|
347
|
+
/** 该 Adapter 的常态证据覆盖声明(完整采集的用 `completeCoverage` 常量);省略 = 全通道 unknown。 */
|
|
348
|
+
coverage?: EvidenceCoverage;
|
|
284
349
|
/**
|
|
285
350
|
* 每个沙箱一次(不是每轮一次):装 CLI、写 config.toml / 鉴权配置(model/base/auth 等
|
|
286
351
|
* 本轮内不变的东西)。运行器在沙箱备好(上传/基线/eval.setup 之后)、第一次 send 前
|
|
@@ -301,6 +366,8 @@ export interface SandboxAgentDef {
|
|
|
301
366
|
export interface RemoteAgentDef {
|
|
302
367
|
/** agent 的显示名/标识,原样进入 `Agent.name`——不是注册表查找 key,只用于展示、结果归属与去重指纹。 */
|
|
303
368
|
name: string;
|
|
369
|
+
/** 该 Adapter 的常态证据覆盖声明(完整采集的用 `completeCoverage` 常量);省略 = 全通道 unknown。 */
|
|
370
|
+
coverage?: EvidenceCoverage;
|
|
304
371
|
/**
|
|
305
372
|
* 每个 attempt 一次(remote agent 没有真实沙箱,运行器会传入一个仅含 `workdir`/`sandboxId`/
|
|
306
373
|
* `otlpHost`/`stop` 等元信息的 stub `Sandbox`,其余方法调用即抛错——不要在这里调用
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// cases: docs/engineering/unit-tests/adapters/cases.md
|
|
1
2
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
3
|
|
|
3
4
|
import type { AgentContext } from "../types.ts";
|
|
@@ -77,6 +78,8 @@ function ctx(overrides: Partial<{ model: string }> = {}): AgentContext {
|
|
|
77
78
|
sandbox: undefined as never,
|
|
78
79
|
// 同一个 ctx 重复用 = 同一条会话线(续接,同一个 ctx.session);新造 = 新线。
|
|
79
80
|
session: createAgentSession(),
|
|
81
|
+
progress: () => {},
|
|
82
|
+
diagnostic: () => {},
|
|
80
83
|
log: () => {},
|
|
81
84
|
} as AgentContext;
|
|
82
85
|
}
|