niceeval 0.4.4 → 0.4.5
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/README.md +21 -12
- package/README.zh.md +8 -9
- package/docs-site/.mintignore +13 -0
- package/docs-site/AGENTS.md +46 -0
- package/docs-site/concepts/adapter.mdx +287 -0
- package/docs-site/concepts/assert.mdx +243 -0
- package/docs-site/concepts/drive.mdx +118 -0
- package/docs-site/concepts/evals.mdx +108 -0
- package/docs-site/concepts/experiment.mdx +37 -0
- package/docs-site/concepts/hitl.mdx +83 -0
- package/docs-site/concepts/judge.mdx +129 -0
- package/docs-site/concepts/overview.mdx +98 -0
- package/docs-site/concepts/tier.mdx +42 -0
- package/docs-site/docs-ref/00-index.md +23 -0
- package/docs-site/docs-ref/01-page-types.md +43 -0
- package/docs-site/docs-ref/03-style-rules.md +45 -0
- package/docs-site/docs-ref/04-code-examples.md +37 -0
- package/docs-site/docs-ref/05-dx-failure-paths.md +45 -0
- package/docs-site/docs-ref/06-checklists.md +53 -0
- package/docs-site/docs.json +256 -0
- package/docs-site/example/ai-agent-application.mdx +148 -0
- package/docs-site/example/claude-code-codex-plugin.mdx +162 -0
- package/docs-site/example/claude-code-codex-skill.mdx +147 -0
- package/docs-site/example/showcase.mdx +39 -0
- package/docs-site/example/tier1-ai-sdk-v7.mdx +136 -0
- package/docs-site/example/tier1-claude-sdk.mdx +119 -0
- package/docs-site/example/tier1-codex-sdk.mdx +111 -0
- package/docs-site/example/tier1-langgraph.mdx +119 -0
- package/docs-site/example/tier1-pi-sdk.mdx +119 -0
- package/docs-site/favicon.svg +5 -0
- package/docs-site/github-diff.css +135 -0
- package/docs-site/github-diff.js +11 -0
- package/docs-site/guides/authoring.mdx +129 -0
- package/docs-site/guides/ci-integration.mdx +97 -0
- package/docs-site/guides/connect-otel.mdx +209 -0
- package/docs-site/guides/connect-your-agent.mdx +221 -0
- package/docs-site/guides/dataset-fanout.mdx +98 -0
- package/docs-site/guides/experiments.mdx +71 -0
- package/docs-site/guides/fixtures.mdx +147 -0
- package/docs-site/guides/reporters.mdx +113 -0
- package/docs-site/guides/runner.mdx +79 -0
- package/docs-site/guides/sandbox-agent.mdx +138 -0
- package/docs-site/guides/sandbox-backends.mdx +64 -0
- package/docs-site/guides/scoring-guide.mdx +92 -0
- package/docs-site/guides/viewing-results.mdx +195 -0
- package/docs-site/guides/write-experiment.mdx +81 -0
- package/docs-site/guides/write-send.mdx +347 -0
- package/docs-site/images/adapter-tiers-zh.svg +60 -0
- package/docs-site/images/agent-turn-roundtrip-en.svg +62 -0
- package/docs-site/images/agent-turn-roundtrip-zh.svg +77 -0
- package/docs-site/images/hitl-handshake-zh.svg +89 -0
- package/docs-site/images/logo.svg +6 -0
- package/docs-site/index.mdx +181 -0
- package/docs-site/introduction.mdx +141 -0
- package/docs-site/quickstart.mdx +136 -0
- package/docs-site/reference/builtin-agents.mdx +161 -0
- package/docs-site/reference/capabilities.mdx +76 -0
- package/docs-site/reference/cli.mdx +120 -0
- package/docs-site/reference/define-agent.mdx +168 -0
- package/docs-site/reference/define-config.mdx +41 -0
- package/docs-site/reference/define-eval.mdx +160 -0
- package/docs-site/reference/events.mdx +131 -0
- package/docs-site/reference/expect.mdx +112 -0
- package/docs-site/tracker.js +8 -0
- package/docs-site/zh/concepts/adapter.mdx +286 -0
- package/docs-site/zh/concepts/assert.mdx +243 -0
- package/docs-site/zh/concepts/drive.mdx +118 -0
- package/docs-site/zh/concepts/evals.mdx +124 -0
- package/docs-site/zh/concepts/experiment.mdx +37 -0
- package/docs-site/zh/concepts/hitl.mdx +83 -0
- package/docs-site/zh/concepts/judge.mdx +130 -0
- package/docs-site/zh/concepts/overview.mdx +109 -0
- package/docs-site/zh/concepts/tier.mdx +44 -0
- package/docs-site/zh/example/ai-agent-application.mdx +152 -0
- package/docs-site/zh/example/claude-code-codex-plugin.mdx +163 -0
- package/docs-site/zh/example/claude-code-codex-skill.mdx +147 -0
- package/docs-site/zh/example/showcase.mdx +39 -0
- package/docs-site/zh/example/tier1-ai-sdk-v7.mdx +140 -0
- package/docs-site/zh/example/tier1-claude-sdk.mdx +122 -0
- package/docs-site/zh/example/tier1-codex-sdk.mdx +117 -0
- package/docs-site/zh/example/tier1-langgraph.mdx +123 -0
- package/docs-site/zh/example/tier1-pi-sdk.mdx +122 -0
- package/docs-site/zh/guides/agent-feedback-loop.mdx +79 -0
- package/docs-site/zh/guides/authoring.mdx +129 -0
- package/docs-site/zh/guides/ci-integration.mdx +97 -0
- package/docs-site/zh/guides/connect-otel.mdx +208 -0
- package/docs-site/zh/guides/connect-your-agent.mdx +226 -0
- package/docs-site/zh/guides/dataset-fanout.mdx +83 -0
- package/docs-site/zh/guides/experiments.mdx +72 -0
- package/docs-site/zh/guides/fixtures.mdx +147 -0
- package/docs-site/zh/guides/official-adapters.mdx +132 -0
- package/docs-site/zh/guides/reporters.mdx +113 -0
- package/docs-site/zh/guides/runner.mdx +82 -0
- package/docs-site/zh/guides/sandbox-agent.mdx +139 -0
- package/docs-site/zh/guides/sandbox-backends.mdx +75 -0
- package/docs-site/zh/guides/scoring-guide.mdx +92 -0
- package/docs-site/zh/guides/viewing-results.mdx +195 -0
- package/docs-site/zh/guides/write-experiment.mdx +101 -0
- package/docs-site/zh/guides/write-send.mdx +353 -0
- package/docs-site/zh/index.mdx +180 -0
- package/docs-site/zh/introduction.mdx +140 -0
- package/docs-site/zh/quickstart.mdx +137 -0
- package/docs-site/zh/reference/builtin-agents.mdx +364 -0
- package/docs-site/zh/reference/capabilities.mdx +76 -0
- package/docs-site/zh/reference/cli.mdx +140 -0
- package/docs-site/zh/reference/define-agent.mdx +461 -0
- package/docs-site/zh/reference/define-config.mdx +107 -0
- package/docs-site/zh/reference/define-eval.mdx +674 -0
- package/docs-site/zh/reference/events.mdx +252 -0
- package/docs-site/zh/reference/expect.mdx +208 -0
- package/package.json +3 -2
- package/src/agents/bub.ts +1 -1
- package/src/agents/claude-code.ts +8 -5
- package/src/agents/codex.ts +9 -5
- package/src/agents/sdk-streams.test.ts +4 -4
- package/src/agents/sdk-streams.ts +14 -9
- package/src/agents/types.ts +40 -1
- package/src/agents/ui-message-stream.ts +1 -0
- package/src/cli.ts +36 -7
- package/src/context/types.ts +140 -0
- package/src/expect/index.ts +15 -8
- package/src/i18n/en.ts +19 -6
- package/src/i18n/zh-CN.ts +19 -6
- package/src/o11y/parsers/bub.test.ts +71 -0
- package/src/o11y/parsers/bub.ts +5 -0
- package/src/o11y/types.ts +27 -2
- package/src/runner/reporters/artifacts.ts +11 -3
- package/src/runner/reporters/live.ts +45 -8
- package/src/runner/run.ts +71 -21
- package/src/runner/types.ts +45 -2
- package/src/sandbox/types.ts +18 -0
- package/src/scoring/types.ts +5 -0
- package/src/shared/types.ts +3 -0
- package/src/util.test.ts +26 -1
- package/src/util.ts +16 -0
- package/src/view/app/App.tsx +2 -2
- package/src/view/app/components/AttemptModal.tsx +2 -0
- package/src/view/app/components/CopyControls.tsx +87 -28
- package/src/view/app/i18n.ts +3 -3
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +18 -18
- package/docs/README.md +0 -120
- package/docs/adapters/README.md +0 -60
- package/docs/adapters/authoring.md +0 -179
- package/docs/adapters/coding-agent-skills-plugins.md +0 -324
- package/docs/adapters/collection.md +0 -128
- package/docs/adapters/contract.md +0 -264
- package/docs/adapters/reference/agent-eval.md +0 -215
- package/docs/adapters/reference/agent-loop-apis.md +0 -69
- package/docs/adapters/reference/claude-code-otel-telemetry.md +0 -100
- package/docs/adapters/reference/eve-protocol.md +0 -127
- package/docs/adapters/reference/otel-genai.md +0 -107
- package/docs/adapters/reference/otel-instrumentation.md +0 -65
- package/docs/adapters/targets.md +0 -99
- package/docs/architecture.md +0 -140
- package/docs/assertions.md +0 -387
- package/docs/capabilities-by-construction.md +0 -48
- package/docs/cli.md +0 -173
- package/docs/concepts.md +0 -106
- package/docs/e2e-ci.md +0 -332
- package/docs/eval-authoring.md +0 -319
- package/docs/experiments.md +0 -157
- package/docs/getting-started.md +0 -224
- package/docs/multi-agent.md +0 -145
- package/docs/observability.md +0 -337
- package/docs/origin-integration.md +0 -195
- package/docs/references.md +0 -35
- package/docs/reports.md +0 -551
- package/docs/results-format.md +0 -228
- package/docs/results-lib.md +0 -191
- package/docs/runner.md +0 -104
- package/docs/sandbox.md +0 -276
- package/docs/scoring.md +0 -119
- package/docs/source-map.md +0 -126
- package/docs/tier-sync.md +0 -193
- package/docs/view.md +0 -194
- package/docs/vision.md +0 -88
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
# Coding Agent Skills / Plugins DX
|
|
2
|
-
|
|
3
|
-
这篇只讨论沙箱型 coding agent adapter:Claude Code、Codex、bub 这类 CLI agent 如何在 niceeval 里安装 skill 与 plugin,并让实验可以 A/B 对比它们的收益。
|
|
4
|
-
|
|
5
|
-
先定词:
|
|
6
|
-
|
|
7
|
-
- **Skill** 是模型上下文。它告诉 agent "遇到某类任务时怎么想、怎么写、用哪些约定"。典型形态是一个本地 Markdown / `SKILL.md`,或一个可以用 `npx skill add` 安装的 repo skill。
|
|
8
|
-
- **Plugin** 是可执行能力。它给 agent 增加工具、MCP server、Python package、hook 或其它运行时扩展。它可能也带文档,但核心价值是让 agent 能调用新的东西。
|
|
9
|
-
|
|
10
|
-
不要把两者混在一个 `flags.skill = true` 里。skill 影响 prompt / context,plugin 影响工具面 / runtime;这两个维度要能独立打开,否则无法判断收益来自"指导更清楚"还是"多了工具"。
|
|
11
|
-
|
|
12
|
-
## 设计目标
|
|
13
|
-
|
|
14
|
-
1. **实验决定装什么。** base agent 只知道怎么跑 Claude Code / Codex / bub;某次实验要不要加 skill / plugin,在 experiment 里表达,而不是 CLI 位置参数或全局 config。
|
|
15
|
-
2. **adapter 负责翻译。** niceeval core 不知道 Claude Code 怎么读 skill、Codex 配置文件在哪、bub 插件怎么装。统一配置只到 adapter 边界,再由具体 adapter 翻译成它自己的安装动作。
|
|
16
|
-
3. **安装发生在 `setup`。** 每个 attempt 的沙箱建好后、第一次 `send` 前安装。多轮会话不能在每轮 `send` 里重装。
|
|
17
|
-
4. **结果可对比。** 同一组 eval 应该能跑 `baseline`、`with-local-skill`、`with-installed-skill`、`with-plugin` 四类实验,报告里 agent 名字要带出变体。
|
|
18
|
-
5. **选择要显式。** 一个 repo 里有多个 skill 时,必须能选择其中几个;不要默认把整个 repo 全部启用。
|
|
19
|
-
|
|
20
|
-
## 目标 API
|
|
21
|
-
|
|
22
|
-
建议内置 coding-agent adapter 都收敛到同一组概念字段:
|
|
23
|
-
|
|
24
|
-
```typescript
|
|
25
|
-
type SkillSpec =
|
|
26
|
-
| {
|
|
27
|
-
kind: "local";
|
|
28
|
-
path: string; // repo 内文件或目录,如 "skills/zod.md" / "skills/ponytail/SKILL.md"
|
|
29
|
-
name?: string; // 展示名;省略则由文件名推导
|
|
30
|
-
}
|
|
31
|
-
| {
|
|
32
|
-
kind: "repo";
|
|
33
|
-
source: string; // "owner/repo" 或 git URL,传给 npx skill add
|
|
34
|
-
skills?: string[]; // repo 内只启用这些 skill;省略 = repo 只有一个 skill 时可接受
|
|
35
|
-
ref?: string; // 可选 pin:tag / commit / branch
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
type PluginSpec =
|
|
39
|
-
| {
|
|
40
|
-
kind: "mcp";
|
|
41
|
-
name: string;
|
|
42
|
-
command: string;
|
|
43
|
-
args?: string[];
|
|
44
|
-
env?: Record<string, string>;
|
|
45
|
-
}
|
|
46
|
-
| {
|
|
47
|
-
kind: "python";
|
|
48
|
-
package: string; // bub:uv tool install --with <package>
|
|
49
|
-
}
|
|
50
|
-
| {
|
|
51
|
-
kind: "agent-native";
|
|
52
|
-
source: string; // 预留给 Claude Code / Codex 自己的 plugin installer
|
|
53
|
-
plugins?: string[]; // repo 内选择其中几个 plugin
|
|
54
|
-
ref?: string;
|
|
55
|
-
};
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
在 experiment 里使用:
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
import { defineExperiment } from "niceeval";
|
|
62
|
-
import { dockerSandbox } from "niceeval/sandbox";
|
|
63
|
-
import { claudeCodeAgent, codexAgent, bubAgent } from "niceeval/adapter";
|
|
64
|
-
|
|
65
|
-
export default defineExperiment({
|
|
66
|
-
description: "codex + local zod skill",
|
|
67
|
-
agent: codexAgent({
|
|
68
|
-
name: "codex+zod-skill",
|
|
69
|
-
skills: [{ kind: "local", path: "examples/zh/coding-agent-skill/skills/zod.md" }],
|
|
70
|
-
}),
|
|
71
|
-
model: "gpt-5.4",
|
|
72
|
-
sandbox: dockerSandbox(),
|
|
73
|
-
});
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
当前代码里 `claudeCodeAgent` / `codexAgent` 已有 `skills?: string[]` 和 `mcpServers?: McpServer[]`,`bubAgent` 已有 `pythonPlugins?: string[]`。上面的 `SkillSpec` / `PluginSpec` 是 DX 目标:把已有字符串数组升级成可选择、可 pin、可解释的结构。
|
|
77
|
-
|
|
78
|
-
## Skill 两种来源
|
|
79
|
-
|
|
80
|
-
### 1. 本地 skill
|
|
81
|
-
|
|
82
|
-
本地 skill 适合团队内部规范、项目知识、API 使用约定、迁移指南。`examples/zh/coding-agent-skill/` 当前就是这个形状:实验 wrapper 在 `setup` 阶段把 `skills/zod.md` 写成工作区 `CLAUDE.md`,让 Claude Code 自动读到。
|
|
83
|
-
|
|
84
|
-
目标 DX 不应该要求每个实验手写 wrapper。adapter 应提供统一注入:
|
|
85
|
-
|
|
86
|
-
```typescript
|
|
87
|
-
const agent = claudeCodeAgent({
|
|
88
|
-
name: "claude-code+zod",
|
|
89
|
-
skills: [{ kind: "local", path: "skills/zod.md" }],
|
|
90
|
-
});
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
adapter 翻译规则:
|
|
94
|
-
|
|
95
|
-
| Agent | 本地 skill 注入 |
|
|
96
|
-
|---|---|
|
|
97
|
-
| Claude Code | 写入工作区 `CLAUDE.md`,或写入 Claude Code 原生 skill 目录(如果当前 CLI 版本支持) |
|
|
98
|
-
| Codex | 写入工作区 `AGENTS.md` / Codex skill 目录,保持和 Codex CLI 当前读取规则一致 |
|
|
99
|
-
| bub | 写入工作区 `AGENTS.md` 或 bub 支持的项目说明文件;如果 bub 没有原生 skill 概念,就把 skill 作为明确的 project instruction 注入 |
|
|
100
|
-
|
|
101
|
-
规则是:本地 skill 是 eval fixture 的一部分,应该随 repo 签入,并被沙箱上传 / 写入;不要依赖用户机器上的全局 skill 状态。
|
|
102
|
-
|
|
103
|
-
### 2. `npx skill add` 安装的 skill
|
|
104
|
-
|
|
105
|
-
第三方 skill 适合复用公开仓库,也适合把一个组织维护的 skill repo 分发给多项目。DX 应支持:
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
const agent = claudeCodeAgent({
|
|
109
|
-
name: "claude-code+effect-sql",
|
|
110
|
-
skills: [
|
|
111
|
-
{
|
|
112
|
-
kind: "repo",
|
|
113
|
-
source: "Effect-TS/skills",
|
|
114
|
-
skills: ["effect", "effect-sql"],
|
|
115
|
-
ref: "8f3c1a2",
|
|
116
|
-
},
|
|
117
|
-
],
|
|
118
|
-
});
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
安装流程放在 `setup`:
|
|
122
|
-
|
|
123
|
-
```sh
|
|
124
|
-
npx skill add Effect-TS/skills --ref 8f3c1a2 --only effect --only effect-sql
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
如果实际 installer 叫 `skills add` 或选择参数不是 `--only`,这是 adapter 的翻译细节;文档层只要求表达能力:
|
|
128
|
-
|
|
129
|
-
- `source` 指明装哪个 repo;
|
|
130
|
-
- `ref` 固定版本,保证 eval 可复现;
|
|
131
|
-
- `skills` 在多 skill repo 中选择启用集合;
|
|
132
|
-
- 安装后写 lock/artifact,让 `.niceeval/<run>/` 能看见实际安装了什么。
|
|
133
|
-
|
|
134
|
-
选择规则:
|
|
135
|
-
|
|
136
|
-
| 情况 | 行为 |
|
|
137
|
-
|---|---|
|
|
138
|
-
| repo 只有一个 skill,`skills` 省略 | 可以安装并启用这个 skill |
|
|
139
|
-
| repo 有多个 skill,`skills` 省略 | adapter 应 fail fast,错误里列出可选 skill,要求显式选择 |
|
|
140
|
-
| 指定的 skill 不存在 | adapter 应 fail fast,把 source/ref/skill 名写进错误 |
|
|
141
|
-
| 同一个 skill 既本地又 repo 安装 | 不自动合并;按配置顺序注入,并在 agent 名字或安装 manifest 中保留来源 |
|
|
142
|
-
|
|
143
|
-
## Plugin 设计
|
|
144
|
-
|
|
145
|
-
plugin 不应该通过 skill 文本偷偷安装。它改变运行时能力,必须独立配置,否则 trace / tool 调用 / 失败诊断会很难读。
|
|
146
|
-
|
|
147
|
-
### MCP plugin
|
|
148
|
-
|
|
149
|
-
Claude Code 和 Codex 都能走 MCP 这条共同抽象。DX:
|
|
150
|
-
|
|
151
|
-
```typescript
|
|
152
|
-
const agent = codexAgent({
|
|
153
|
-
name: "codex+browser-mcp",
|
|
154
|
-
plugins: [
|
|
155
|
-
{
|
|
156
|
-
kind: "mcp",
|
|
157
|
-
name: "browser",
|
|
158
|
-
command: "npx",
|
|
159
|
-
args: ["-y", "@modelcontextprotocol/server-browser"],
|
|
160
|
-
},
|
|
161
|
-
],
|
|
162
|
-
});
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
adapter 翻译:
|
|
166
|
-
|
|
167
|
-
| Agent | MCP 写入位置 |
|
|
168
|
-
|---|---|
|
|
169
|
-
| Claude Code | `~/.claude/claude.json` 的 `mcpServers` |
|
|
170
|
-
| Codex | `~/.codex/config.toml` 的 `[mcp_server.<name>]` |
|
|
171
|
-
| bub | 如果 bub 支持 MCP,写 bub 自己的配置;否则 fail fast,提示该 agent 不支持 `kind: "mcp"` |
|
|
172
|
-
|
|
173
|
-
### bub Python plugin
|
|
174
|
-
|
|
175
|
-
bub 当前更自然的 plugin 面是 Python package:
|
|
176
|
-
|
|
177
|
-
```typescript
|
|
178
|
-
const agent = bubAgent({
|
|
179
|
-
name: "bub+otel-memory",
|
|
180
|
-
plugins: [
|
|
181
|
-
{ kind: "python", package: "bub-plugin-memory" },
|
|
182
|
-
{ kind: "python", package: "git+https://github.com/acme/bub-tools.git" },
|
|
183
|
-
],
|
|
184
|
-
});
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
adapter 翻译为:
|
|
188
|
-
|
|
189
|
-
```sh
|
|
190
|
-
uv tool install --reinstall --python 3.12 --prerelease allow bub --with <package>
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
这类 plugin 应进安装 checkpoint 的 hash。否则一次 eval 装了插件、下一次没装插件却复用了缓存,结果会污染。
|
|
194
|
-
|
|
195
|
-
### agent-native plugin
|
|
196
|
-
|
|
197
|
-
给未来 Claude Code / Codex 原生 plugin installer 预留:
|
|
198
|
-
|
|
199
|
-
```typescript
|
|
200
|
-
const agent = claudeCodeAgent({
|
|
201
|
-
name: "claude-code+org-plugin",
|
|
202
|
-
plugins: [
|
|
203
|
-
{
|
|
204
|
-
kind: "agent-native",
|
|
205
|
-
source: "acme/coding-agent-plugins",
|
|
206
|
-
plugins: ["safe-shell", "repo-map"],
|
|
207
|
-
ref: "v1.3.0",
|
|
208
|
-
},
|
|
209
|
-
],
|
|
210
|
-
});
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
和 repo skill 一样:多 plugin repo 必须显式选择,安装结果要落 manifest。
|
|
214
|
-
|
|
215
|
-
## A/B 组织方式
|
|
216
|
-
|
|
217
|
-
不要用 CLI flag 临时开关 skill/plugin。用 experiment 文件表达可比组:
|
|
218
|
-
|
|
219
|
-
```text
|
|
220
|
-
experiments/
|
|
221
|
-
└── skill-ab/
|
|
222
|
-
├── baseline.ts
|
|
223
|
-
├── claude-zod-local.ts
|
|
224
|
-
├── codex-zod-local.ts
|
|
225
|
-
├── claude-ponytail-repo.ts
|
|
226
|
-
└── bub-python-plugin.ts
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
每个文件引用一个明确 agent 变体:
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
export default defineExperiment({
|
|
233
|
-
description: "claude-code + ponytail repo skill",
|
|
234
|
-
agent: claudeCodeAgent({
|
|
235
|
-
name: "claude-code+ponytail",
|
|
236
|
-
skills: [{ kind: "repo", source: "DietrichGebert/ponytail", skills: ["ponytail"], ref: "..." }],
|
|
237
|
-
}),
|
|
238
|
-
model: "claude-sonnet-4-6",
|
|
239
|
-
evals: (id) => id.startsWith("ponytail-"),
|
|
240
|
-
runs: 3,
|
|
241
|
-
earlyExit: false,
|
|
242
|
-
});
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
这样 `niceeval exp skill-ab` 的含义清楚:同一批任务,不同 agent 上下文 / runtime 变体。`niceeval view` 里也能直接按 agent 名比较通过率、成本、工具调用和 diff 质量。
|
|
246
|
-
|
|
247
|
-
## 安装 Manifest
|
|
248
|
-
|
|
249
|
-
adapter 在 setup 结束后应写一份标准 manifest 到沙箱和结果工件,例如:
|
|
250
|
-
|
|
251
|
-
```json
|
|
252
|
-
{
|
|
253
|
-
"agent": "codex+zod-local",
|
|
254
|
-
"skills": [
|
|
255
|
-
{ "kind": "local", "name": "zod", "path": "skills/zod.md", "sha256": "..." },
|
|
256
|
-
{ "kind": "repo", "source": "Effect-TS/skills", "ref": "8f3c1a2", "skills": ["effect"] }
|
|
257
|
-
],
|
|
258
|
-
"plugins": [
|
|
259
|
-
{ "kind": "mcp", "name": "browser", "command": "npx" }
|
|
260
|
-
]
|
|
261
|
-
}
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
建议路径:
|
|
265
|
-
|
|
266
|
-
- 沙箱内:`__niceeval__/agent-setup.json`
|
|
267
|
-
- 结果目录:`.niceeval/<run>/<eval>/<attempt>/agent-setup.json`
|
|
268
|
-
|
|
269
|
-
这份 manifest 不参与评分,但用于复现和诊断:"这次失败到底有没有装 skill"应该能从 artifact 一眼确认。
|
|
270
|
-
|
|
271
|
-
## 失败语义
|
|
272
|
-
|
|
273
|
-
skill/plugin 安装失败是 **errored**,不是 agent 做题失败:
|
|
274
|
-
|
|
275
|
-
- 本地 skill 路径不存在;
|
|
276
|
-
- `npx skill add` 下载失败;
|
|
277
|
-
- 多 skill repo 未指定 `skills`;
|
|
278
|
-
- MCP command 找不到;
|
|
279
|
-
- bub Python plugin 安装失败。
|
|
280
|
-
|
|
281
|
-
这些都发生在 adapter setup 阶段,应该进入 `EvalResult.outcome = "errored"`。不要让它伪装成 `Turn.status = "failed"` 或一个 gate assertion fail。
|
|
282
|
-
|
|
283
|
-
## 当前示例如何演进
|
|
284
|
-
|
|
285
|
-
`examples/zh/coding-agent-skill/` 当前有两个好点:
|
|
286
|
-
|
|
287
|
-
- 它已经用 experiment 表达 baseline vs skill 变体;
|
|
288
|
-
- 它把本地 `zod.md` 与迁移来的 `ponytail.md` 分成两组 eval。
|
|
289
|
-
|
|
290
|
-
下一步可以把手写 wrapper:
|
|
291
|
-
|
|
292
|
-
```typescript
|
|
293
|
-
const baseAgent = claudeCodeAgent();
|
|
294
|
-
const zodAgent = {
|
|
295
|
-
...baseAgent,
|
|
296
|
-
name: "claude-code+zod-skill",
|
|
297
|
-
async setup(sb, ctx) {
|
|
298
|
-
const cleanup = await baseAgent.setup?.(sb, ctx);
|
|
299
|
-
await sb.writeFiles({ "CLAUDE.md": zodSkill }); // targetDir 省略 → workdir,跨后端可移植
|
|
300
|
-
return cleanup;
|
|
301
|
-
},
|
|
302
|
-
};
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
收敛为:
|
|
306
|
-
|
|
307
|
-
```typescript
|
|
308
|
-
const zodAgent = claudeCodeAgent({
|
|
309
|
-
name: "claude-code+zod-skill",
|
|
310
|
-
skills: [{ kind: "local", path: "examples/zh/coding-agent-skill/skills/zod.md" }],
|
|
311
|
-
});
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
ponytail 如果继续 vendored 到本 repo,就用 `kind: "local"`;如果希望测试真实第三方安装路径,就用 `kind: "repo"` 并指定 `skills: ["ponytail"]` 与 `ref`。
|
|
315
|
-
|
|
316
|
-
## 落地顺序
|
|
317
|
-
|
|
318
|
-
1. 在 `src/types.ts` 增加 `SkillSpec` / `PluginSpec`,并让内置 adapter config 复用它们。
|
|
319
|
-
2. 先实现本地 skill 注入,替换 `examples/zh/coding-agent-skill/` 的 wrapper。
|
|
320
|
-
3. 实现 repo skill 安装和多 skill 选择失败提示。
|
|
321
|
-
4. 把 `mcpServers` / `pythonPlugins` 兼容迁移到 `plugins`,旧字段保留一版并打印 deprecation。
|
|
322
|
-
5. 写 `agent-setup.json` artifact,让 view 可以展示每个 attempt 的安装清单。
|
|
323
|
-
|
|
324
|
-
这套设计不改变 core:core 仍只看 Agent/Adapter 契约、标准事件流、sandbox 与 result artifact。所有 Claude Code / Codex / bub 的差异都留在对应 adapter 的 setup 翻译层。
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
# 采集设计 —— 通道、矩阵与每个被测对象怎么接
|
|
2
|
-
|
|
3
|
-
这一篇集中回答:**每个被测对象,行为数据和 trace 从哪条路径采、哪些字段从哪里来。**
|
|
4
|
-
|
|
5
|
-
分工:[Adapter 契约](contract.md) 定义采集的**目标**(`StreamEvent` / `Turn` 长什么样、每条断言要什么数据);[Adapter 写法 · 采集层](authoring.md#采集层原始数据怎么从-agent-cli-弄到手) 讲通用**纪律**(采集脏 / 转换净、raw string 边界、行级容错);本篇是**具体矩阵**——三条外部路线的对比结论、niceeval 的通道设计、以及 claude-code / codex / bub / AI SDK 各自的字段来源(与 `src/o11y/parsers/` 和 `src/agents/` 现状对齐)。接一个新被测对象时,从[决策树](#接新被测对象的决策树)进。
|
|
6
|
-
|
|
7
|
-
## 三条外部路线:采集路径与字段的取舍
|
|
8
|
-
|
|
9
|
-
[reference/](README.md#这组文档怎么分) 三篇调研收拢成一张表,核心结论:**采集路径决定字段上限**——你从哪拿数据,决定了你最多能知道什么。
|
|
10
|
-
|
|
11
|
-
| 路线 | 采集路径 | 字段上限 | 前提 | 代价 |
|
|
12
|
-
|---|---|---|---|---|
|
|
13
|
-
| [eve](reference/eve-protocol.md) | **无采集**——运行时原生吐协议(NDJSON over HTTP,带版本号) | 最高:26 种事件、`sequence/turnId/stepIndex` 坐标、per-step usage、`RuntimeIdentity` 自报模型 | **拥有运行时** | 只能评自己 |
|
|
14
|
-
| [agent-eval](reference/agent-eval.md) | 磁盘旁读(claude-code)+ stdout 捕获(codex),另开第二通道读磁盘抠实际模型;无 trace | 最小公分母:5 种事件、无 callId(顺序配对)、丢 turn/step 边界 | 无(逆向未接管理层的对象) | 每个 CLI 一堆 hack,并发配对会错 |
|
|
15
|
-
| [OTel GenAI](reference/otel-genai.md) | OTLP 网络推送(agent 自己 instrument) | span 树带时间与层级;但消息内容 / 工具入参 **opt-in**,常缺 | agent 愿意发、发得对 | 断言最需要的内容字段恰恰不保证有 |
|
|
16
|
-
|
|
17
|
-
## niceeval 的设计:双轨 × 四通道
|
|
18
|
-
|
|
19
|
-
行为和时间分两轨,各自选通道;一个 agent 可以多通道并用,按"这份数据用来干什么"分别决定怎么采(agent-eval 的 codex 双通道教训):
|
|
20
|
-
|
|
21
|
-
```text
|
|
22
|
-
行为轨(StreamEvent[] —— 断言的唯一数据源,必须全量)
|
|
23
|
-
通道 0 · 官方转换器直构 remote agent:send 消费天生带完整调用记录的返回(官方转换器直接映射成事件),零手写映射
|
|
24
|
-
通道 1 · 磁盘旁读 CLI 为自己 resume 写的侧写文件(claude-code transcript、bub tape)
|
|
25
|
-
通道 2 · stdout 捕获 CLI 的结构化输出 flag(codex --json)
|
|
26
|
-
↘ 通道 1/2 统一收窄成 raw string → o11y/parsers/<agent>.ts(纯函数,可单测)
|
|
27
|
-
|
|
28
|
-
时间轨(TraceSpan[] —— 瀑布图,允许缺)
|
|
29
|
-
通道 3 · OTLP 推送 agent 经 OpenTelemetry 推给运行器的本机接收器
|
|
30
|
-
→ o11y/otlp/mappers/<agent>.ts 归一 canonical GenAI semconv
|
|
31
|
-
没有 OTel 输出的(claude-code)从 transcript 时间戳合成 span
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
两轨的容错要求不同,这是设计的关键不对称:**行为轨缺数据是契约问题**(负断言静默假通过,见[契约 · 负断言完整性规则](contract.md#负断言的完整性规则)),做不到完整就如实说明这条 eval 的负断言不可信;**时间轨缺数据是降级**(view 少画一张瀑布图,断言不受影响)。
|
|
35
|
-
|
|
36
|
-
## 采集矩阵:现状(与 `src/` 对齐)
|
|
37
|
-
|
|
38
|
-
每行都是"这个字段从原始数据的哪里抠"——写新 parser 时照这个粒度补一行:
|
|
39
|
-
|
|
40
|
-
| | claude-code | codex | bub |
|
|
41
|
-
|---|---|---|---|
|
|
42
|
-
| **行为轨通道** | 磁盘旁读 | stdout 捕获 | 磁盘旁读(tape) |
|
|
43
|
-
| **原始位置** | `~/.claude/projects/<slug>/` 最新 `.jsonl`(`shared.captureLatestJsonl`) | `codex exec --json` 的 stdout(`shared.extractJsonlFromStdout`) | `~/.bub/tapes/<md5(ws)__md5(sess)>.jsonl` |
|
|
44
|
-
| **行形状** | `{ type: "user"\|"assistant", message: { content: [...], usage } }`,content 混 text / tool_use / thinking 块 | 生命周期事件(`thread.*` / `turn.*` / `item.*` / `response.*`) | `{ kind: message\|tool_call\|event\|anchor, payload }` |
|
|
45
|
-
| **callId 配对** | `tool_use.id` ↔ user 行里 `tool_result.tool_use_id`(显式,坑:工具结果包装成 user 消息) | `call_id` 显式 + FIFO 队列兜底(老式 `function_call_output` 无 id) | 与上一条 tool_call **按位对齐** + 合成 id 兜底 |
|
|
46
|
-
| **usage** | assistant 行 `message.usage`(含 cache read) | 防御式多路径:`data/payload/item/turn/response.usage`,兼容 `input/output_tokens` 与 `prompt/completion_tokens` 两套命名 | `event(name=="run")` 的 `data.usage`(`prompt/completion_tokens`,**`cost` 直接有**) |
|
|
47
|
-
| **session id(resume 用)** | transcript 首个 `sessionId` 字段(`shared.sessionIdFromClaudeTranscript`) | `thread.started.thread_id`(`shared.codexThreadId`) | tape 文件名含 session hash;adapter 自管 |
|
|
48
|
-
| **实际模型** | transcript 行内有 | 网关场景要第二通道读 `~/.codex/sessions` 的 `turn_context.payload.model`(agent-eval 的做法;niceeval 未接,记为已知缺口) | tape 内 run 事件 |
|
|
49
|
-
| **时间轨** | beta 版原生 OTLP trace 导出,已接进 adapter 的 `tracing.env`(`CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1` 等一串 env;span 只有结构与计时、内容默认脱敏,内容仍由 transcript 旁读补全,详见 [reference/claude-code-otel-telemetry.md](reference/claude-code-otel-telemetry.md)) | 原生 OTLP/JSON(`config.toml [otel]`,走 `tracing.configure`) | 原生 OTLP/protobuf(env-based `OTEL_*`,走 `tracing.env`) |
|
|
50
|
-
|
|
51
|
-
remote agent(通道 0)不在表里——它没有"采集",字段来源就是你自己代码里的返回值,见下节示例。
|
|
52
|
-
|
|
53
|
-
## 接入路线的优先级
|
|
54
|
-
|
|
55
|
-
用户侧的建议顺序(docs-site 的接入导流已按此排):
|
|
56
|
-
|
|
57
|
-
1. **内置件**:AI SDK `useChat` 后端应用用 `uiMessageStreamAgent`(走 HTTP,无侵入),coding agent 用内置三个 sandbox agent;
|
|
58
|
-
2. **官方转换器 / SDK 通道 0**:`fromAiSdk` 这类精品转换器(消费你的 HTTP 接口返回的、形状像 AI SDK 结果的 JSON),或官方 SDK 包装(Codex SDK / Cursor SDK,见 [targets.md](targets.md));
|
|
59
|
-
3. **手写映射**:以上都接不了的应用,`toStreamEvents` 兜底。
|
|
60
|
-
|
|
61
|
-
**OTel 不在这条优先级列表里,因为它不产出事件。** 所有断言依据必须来自上面这条行为轨的选择。OTel 是完全独立的第二件事:配置好之后(agent 的 `tracing` 块,或 remote agent + `defineConfig({ telemetry })`),`niceeval view` 多一张调用瀑布图,不影响、也不参与上面的选择,详见 [Observability · OTLP traces](../observability.md#otlp-traces--统一瀑布图)。
|
|
62
|
-
|
|
63
|
-
## 接新被测对象的决策树
|
|
64
|
-
|
|
65
|
-
```text
|
|
66
|
-
应用的 HTTP 接口返回天生带显式 callId、完整调用记录?(比如内部用 AI SDK / Responses API 实现)
|
|
67
|
-
├─ 是 → 通道 0:官方转换器(`fromAiSdk` 等)直接消费接口返回,保真上限最高,见下面示例
|
|
68
|
-
└─ 否 → 未接管理层的 CLI / 别人的服务
|
|
69
|
-
├─ 官方有 SDK 包装?(Codex SDK / Cursor SDK,见 targets.md)→ 当通道 0 接,别逆向 stdout/磁盘
|
|
70
|
-
├─ CLI 有结构化输出 flag(--json)? → 通道 2:stdout 捕获
|
|
71
|
-
├─ 没有,但 CLI 为 resume 写侧写文件? → 通道 1:磁盘旁读(找它的 session 目录)
|
|
72
|
-
└─ 都没有 → 老实做第一步:events 传 [],
|
|
73
|
-
别让负断言假通过——如实说明这条 eval 的负断言不可信
|
|
74
|
-
trace 另算,和上面的选择正交:CLI/应用会发 OTel?→ 写 tracing 块(或 remote agent 配 defineConfig({ telemetry }))+ mapper;
|
|
75
|
-
不会 → transcript 时间戳合成,或直接跳过(只影响瀑布图,不影响断言)
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
字段找不到时的取舍,有先例可循:
|
|
79
|
-
|
|
80
|
-
- **callId 缺失** → 按位 / FIFO 兜底(bub、codex 老格式的做法)——能用,但这是在赌"工具调用严格顺序",并发即错配;有显式 id 一定用显式 id。
|
|
81
|
-
- **usage 缺失** → 不填,**别编数字**。后果是 `maxTokens` / `maxCost` 假通过(见契约),这比错误的成本数据可接受。
|
|
82
|
-
- **实际模型拿不准**(网关改写)→ 学 agent-eval 开第二通道去磁盘 session 文件里读,别信请求参数。
|
|
83
|
-
|
|
84
|
-
### 通道 0 示例:官方转换器直构(应用返回天生带完整调用记录)
|
|
85
|
-
|
|
86
|
-
AI SDK 的 `generateText` 返回天生带显式 `toolCallId`、分 step、带 usage——映射几乎是逐字段抄写,这是通道 0 的典型代表。这层映射(含 v4/v5/v7 字段名漂移:`args`/`input`、`result`/`output`、`promptTokens`/`inputTokens`/`inputTokenDetails`)已收进 `fromAiSdk`(`niceeval/adapter` 导出,`src/agents/ai-sdk.ts`,结构化 typing、不依赖 `ai` 包)。
|
|
87
|
-
|
|
88
|
-
用法是:你自己的 HTTP 服务内部用 AI SDK 实现,接口返回的 JSON 形状就是 AI SDK 的结果(或贴近它)——adapter 的 `send` 照常 `fetch` 你的接口,拿到响应后用 `fromAiSdk` 转成标准事件流,不需要手写映射:
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
// agents/my-ai-sdk-app.ts —— send 走 HTTP,响应体形状贴近 AI SDK 结果
|
|
92
|
-
import { defineAgent, fromAiSdk } from "niceeval/adapter";
|
|
93
|
-
|
|
94
|
-
export default defineAgent({
|
|
95
|
-
name: "my-ai-sdk-app",
|
|
96
|
-
async send(input, ctx) {
|
|
97
|
-
const r = await fetch(`${process.env.MY_APP_URL}/api/chat`, {
|
|
98
|
-
method: "POST", body: JSON.stringify({ message: input.text }), signal: ctx.signal,
|
|
99
|
-
});
|
|
100
|
-
const result = await r.json(); // 形状贴近 AI SDK 的 GenerateTextResult
|
|
101
|
-
// steps 里带 toolCallId 的完整调用记录 + 全 step 聚合 usage + waiting/completed → 一行转完
|
|
102
|
-
return { ...fromAiSdk(result), data: result.text };
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
`fromAiSdk` 做的事,对照矩阵读:`toolCallId` 直接就是 `callId`(不需要兜底);v5+ 的 `step.content` parts 自带真实顺序(reasoning → tool-call → tool-result → text),时序保真;`tool-error` part 映射成 `status: "failed"` 的 `action.result`,喂 `noFailedActions()`;v7 tool approval(`needsApproval` 工具)的 `tool-approval-request` part 映射成 `input.requested` 事件 + 整轮 `status: "waiting"`,resume 后被拦工具的执行结果从 `responseMessages` 里补成 `action.result`(拒绝 = `rejected`,不是 `failed`)——HITL 契约的「waiting + input.requested」两条义务由转换器直接满足;usage 用 `totalUsage`(全 step 聚合)优先、v7 的 cache tokens 从 `inputTokenDetails` 读(eve 按 step 记的粒度这里是可得而未取,见 [eve 笔记 · 启发 3](reference/eve-protocol.md#对-niceeval-适配器设计的启发));时间轨可选接 AI SDK 的 `experimental_telemetry`(OTel spans → mapper)。
|
|
108
|
-
|
|
109
|
-
应用用的是 AI SDK `useChat` 后端(UI Message Stream 协议)而不是自定义 JSON 接口时,优先用内置的 `uiMessageStreamAgent`(`niceeval/adapter` 导出,`src/agents/ui-message-stream.ts`)——它把 SSE 归约、全量历史重放、HITL 审批改写重发都托管了,adapter 只剩配置,完整可跑参考见 `examples/zh/tier1/ai-sdk-v7/`。
|
|
110
|
-
|
|
111
|
-
自有 HTTP 服务同理走通道 0:协议是服务的私事,但如果服务是你写的,**让它直接返回 `StreamEvent` 兼容的 JSON 是最省的适配**——`toStreamEvents` 退化成透传,完整可跑参考见 `examples/zh/tier1/ai-sdk/`。
|
|
112
|
-
|
|
113
|
-
## 接新未接管理层 CLI 的清单
|
|
114
|
-
|
|
115
|
-
以"接 gemini-cli / opencode / 下一个"为例,照矩阵补一列的活:
|
|
116
|
-
|
|
117
|
-
1. **选行为轨通道**:翻它的文档 / strace 找结构化输出 flag(通道 2);没有就找 `~/.<cli>/` 下的 session 侧写(通道 1)。
|
|
118
|
-
2. **写 parser**(`o11y/parsers/<name>.ts`):纯函数只吃 `raw: string`;逐行 try/catch;按[契约 · 事件流三条纪律](contract.md#标准事件流)产事件(时序、callId、双名字);usage 学 codex 的防御式多路径。
|
|
119
|
-
3. **抠 session id**:resume 要用;学 `shared.firstJsonField` 的通用兜底。
|
|
120
|
-
4. **时间轨**:CLI 有 OTel 配置就写 `tracing` 块 + mapper;没有先跳过(降级不崩)。
|
|
121
|
-
5. **对照矩阵自查字段**:callId 显式吗?usage 哪套命名?实际模型在哪?——每格都该能回答"从哪抠",答不上的格子显式记为缺口(像上表 codex 实际模型那格)。
|
|
122
|
-
|
|
123
|
-
## 相关阅读
|
|
124
|
-
|
|
125
|
-
- [Adapter 契约](contract.md) —— 采集的目标形状与逐断言数据义务。
|
|
126
|
-
- [Adapter 写法](authoring.md) —— 采集纪律、分档、shared 工具袋。
|
|
127
|
-
- [reference/](reference/agent-eval.md) —— 三条路线的原始调研(agent-eval / OTel GenAI / eve)。
|
|
128
|
-
- [Observability](../observability.md) —— parser 与 mapper 在 o11y 管线里的位置。
|