@qwen-code/arena-agent 0.0.9-image-input-fallback.0 → 0.0.10-dev.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/.env.example +34 -13
- package/README.md +156 -53
- package/dist/agent.d.ts +4 -2
- package/dist/agent.js +142 -20
- package/dist/agent.js.map +1 -1
- package/dist/anthropic.d.ts +1 -0
- package/dist/anthropic.js +78 -19
- package/dist/anthropic.js.map +1 -1
- package/dist/canonical-data.js +2 -2
- package/dist/canonical-data.js.map +1 -1
- package/dist/cli.js +44 -13
- package/dist/cli.js.map +1 -1
- package/dist/code-tools.js +18 -161
- package/dist/code-tools.js.map +1 -1
- package/dist/compaction.js +8 -2
- package/dist/compaction.js.map +1 -1
- package/dist/config.d.ts +22 -0
- package/dist/config.js +53 -1
- package/dist/config.js.map +1 -1
- package/dist/history.d.ts +3 -2
- package/dist/history.js +7 -2
- package/dist/history.js.map +1 -1
- package/dist/image.d.ts +2 -0
- package/dist/image.js +88 -7
- package/dist/image.js.map +1 -1
- package/dist/model-capabilities.js +12 -2
- package/dist/model-capabilities.js.map +1 -1
- package/dist/model-diagnostics.js +11 -3
- package/dist/model-diagnostics.js.map +1 -1
- package/dist/model-router-media.d.ts +26 -0
- package/dist/model-router-media.js +274 -0
- package/dist/model-router-media.js.map +1 -0
- package/dist/openai-responses.d.ts +28 -0
- package/dist/openai-responses.js +473 -0
- package/dist/openai-responses.js.map +1 -0
- package/dist/process-manager.d.ts +38 -0
- package/dist/process-manager.js +486 -0
- package/dist/process-manager.js.map +1 -0
- package/dist/prompts.js +3 -1
- package/dist/prompts.js.map +1 -1
- package/dist/provider.d.ts +7 -0
- package/dist/provider.js +259 -14
- package/dist/provider.js.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.js +37 -18
- package/dist/server.js.map +1 -1
- package/dist/spec.js +15 -1
- package/dist/spec.js.map +1 -1
- package/dist/tools.js +160 -237
- package/dist/tools.js.map +1 -1
- package/dist/tui.d.ts +2 -0
- package/dist/tui.js +15 -11
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/voice-registry.d.ts +30 -0
- package/dist/voice-registry.js +82 -0
- package/dist/voice-registry.js.map +1 -0
- package/dist/web/app.js +8 -0
- package/dist/web/app.js.map +1 -1
- package/docs/SDK.md +4 -3
- package/package.json +7 -2
- package/web/styles.css +6 -0
- package/dist/audit.d.ts +0 -14
- package/dist/audit.js +0 -31
- package/dist/audit.js.map +0 -1
- package/dist/dashscope.d.ts +0 -5
- package/dist/dashscope.js +0 -55
- package/dist/dashscope.js.map +0 -1
- package/dist/fetch-page/aparat.d.ts +0 -30
- package/dist/fetch-page/aparat.js +0 -209
- package/dist/fetch-page/aparat.js.map +0 -1
- package/dist/fetch-page/json-path.d.ts +0 -12
- package/dist/fetch-page/json-path.js +0 -111
- package/dist/fetch-page/json-path.js.map +0 -1
- package/dist/fetch-page/sites.d.ts +0 -26
- package/dist/fetch-page/sites.js +0 -39
- package/dist/fetch-page/sites.js.map +0 -1
- package/dist/fetch-page/text.d.ts +0 -5
- package/dist/fetch-page/text.js +0 -38
- package/dist/fetch-page/text.js.map +0 -1
- package/dist/fetch-page/types.d.ts +0 -17
- package/dist/fetch-page/types.js +0 -3
- package/dist/fetch-page/types.js.map +0 -1
- package/dist/fetch-page/youtube.d.ts +0 -35
- package/dist/fetch-page/youtube.js +0 -282
- package/dist/fetch-page/youtube.js.map +0 -1
- package/dist/web-search.d.ts +0 -5
- package/dist/web-search.js +0 -465
- package/dist/web-search.js.map +0 -1
package/.env.example
CHANGED
|
@@ -7,6 +7,14 @@ OPENAI_MODEL=openai/qwen-latest-series-invite-beta-v92
|
|
|
7
7
|
OPENAI_BASE_URL=
|
|
8
8
|
OPENAI_API_KEY=
|
|
9
9
|
|
|
10
|
+
# Auto mode uses Responses for GPT model names and Chat Completions otherwise.
|
|
11
|
+
# Native Responses preserves opaque OpenAI reasoning across tool steps and
|
|
12
|
+
# separate CLI turns by replaying encrypted output items with store=false.
|
|
13
|
+
# Set chat to force Chat Completions.
|
|
14
|
+
# ARENA_OPENAI_API=auto
|
|
15
|
+
# ARENA_OPENAI_API=responses
|
|
16
|
+
# ARENA_OPENAI_API=chat
|
|
17
|
+
|
|
10
18
|
# Unified runtime mode. Canonical values are shown; full_stack/fullstack and
|
|
11
19
|
# single_html/single-html remain accepted compatibility aliases.
|
|
12
20
|
ARENA_HARNESS_MODE=arena
|
|
@@ -72,6 +80,13 @@ ARENA_HARNESS_MODE=arena
|
|
|
72
80
|
# false, the optional fallback model converts Arena read_file images to text.
|
|
73
81
|
# ARENA_MODEL_SUPPORTS_IMAGE_INPUT=false
|
|
74
82
|
# ARENA_IMAGE_INPUT_FALLBACK_MODEL=qwen3.7-plus
|
|
83
|
+
# Inline image budget before downscaling: max pixels per edge and max 28x28
|
|
84
|
+
# patches. Images within both limits are sent unchanged; larger ones are
|
|
85
|
+
# downscaled to fit and re-encoded as JPEG. Defaults match the captured
|
|
86
|
+
# baseline; raise both for long screenshots (a 1920x5344 full-page capture
|
|
87
|
+
# needs about 8192 edge and 13179 patches to pass through unchanged).
|
|
88
|
+
# ARENA_IMAGE_MAX_EDGE=1568
|
|
89
|
+
# ARENA_IMAGE_MAX_PATCHES=1568
|
|
75
90
|
|
|
76
91
|
# Optional headless ask_user delegation. When enabled, `arena -p` sends the
|
|
77
92
|
# current questions plus a serialized ATIF trajectory to this JSON endpoint.
|
|
@@ -80,10 +95,13 @@ ARENA_HARNESS_MODE=arena
|
|
|
80
95
|
# ARENA_ASK_USER_HANDLER_URL=http://127.0.0.1:8080/v1/ask-user
|
|
81
96
|
# ARENA_ASK_USER_TIMEOUT_MS=60000
|
|
82
97
|
|
|
83
|
-
# Dynamic session metrics.
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
98
|
+
# Dynamic session metrics. Disabled by default: with the switch off the daemon
|
|
99
|
+
# performs no metric analysis, persists no metrics, and emits no
|
|
100
|
+
# data-session-metrics events. Enable it to compute a snapshot after every
|
|
101
|
+
# user-facing turn; high-confidence Bash cases use deterministic rules, while
|
|
102
|
+
# ambiguous Bash attribution/termination plus user praise, complaint,
|
|
103
|
+
# correction, repair-attempt, and repair-verdict classification use this
|
|
104
|
+
# tool-free structured side query.
|
|
87
105
|
# ARENA_METRICS_SIDE_QUERY_ENABLED=true
|
|
88
106
|
# ARENA_METRICS_SIDE_QUERY_MODEL=openai/qwen-latest-series-invite-beta-v92
|
|
89
107
|
# ARENA_METRICS_SIDE_QUERY_MAX_TOKENS=800
|
|
@@ -101,23 +119,26 @@ ARENA_HARNESS_MODE=arena
|
|
|
101
119
|
# defaults to ~/.arena so runs never write into the task workspace.
|
|
102
120
|
# ARENA_HOME=~/.arena
|
|
103
121
|
|
|
104
|
-
#
|
|
122
|
+
# Search, page reading, image generation, and speech through ModelRouter/Routify.
|
|
105
123
|
ROUTIFY_API_KEY=
|
|
106
124
|
# ROUTIFY_WEB_SEARCH_URL=https://routify-pub.alibaba-inc.com/protocol/compatible-mode/res/v1/llm/context
|
|
107
125
|
# ROUTIFY_IMAGE_SEARCH_URL=https://routify-pub.alibaba-inc.com/protocol/brave/res/v1/images/search
|
|
126
|
+
# ROUTIFY_VERTEX_BASE_URL=https://routify-pub.alibaba-inc.com/protocol/vertex/v1beta
|
|
108
127
|
# ARENA_WEB_SEARCH_MODEL=brave.llm-context
|
|
109
128
|
# CODE_HARNESS_WEB_SEARCH_MODEL=brave.llm-context
|
|
110
129
|
# Optional fetch_page/web_fetch path: Firecrawl first, then Jina Reader.
|
|
111
130
|
# CODE_HARNESS_ROUTIFY_WEB_FETCH_ENABLED=false
|
|
131
|
+
# ARENA_IMAGE_MODEL=gemini-2.5-flash-image
|
|
132
|
+
# ARENA_IMAGE_SIZE=1024*1024
|
|
133
|
+
# CODE_HARNESS_IMAGE_MODEL=gemini-2.5-flash-image
|
|
134
|
+
# CODE_HARNESS_IMAGE_SIZE=1024*1024
|
|
135
|
+
# ARENA_SPEECH_MODEL=doubao-tts
|
|
136
|
+
# ARENA_SPEECH_VOICE=zh_female_vv_uranus_bigtts
|
|
112
137
|
|
|
113
|
-
#
|
|
114
|
-
|
|
115
|
-
#
|
|
116
|
-
#
|
|
117
|
-
# ARENA_IMAGE_MODEL=qwen-image-2.0-pro
|
|
118
|
-
# ARENA_IMAGE_SIZE=2048*2048
|
|
119
|
-
# ARENA_SPEECH_MODEL=qwen-audio-3.0-tts-flash
|
|
120
|
-
# DASHSCOPE_SPEECH_VOICE=longanhuan_v3.6
|
|
138
|
+
# start_process automatically checks E2B preview hosts when E2B_SANDBOX_ID is
|
|
139
|
+
# present. For another preview proxy, use {port} and optionally {sandboxId}:
|
|
140
|
+
# ARENA_PREVIEW_HOST_TEMPLATE={port}-{sandboxId}.e2b.app
|
|
141
|
+
# ROUTIFY_MEDIA_MAX_RETRIES=5
|
|
121
142
|
|
|
122
143
|
# Code Arena stock photo/video search used by fetch_media.
|
|
123
144
|
# PEXELS_API_KEY=
|
package/README.md
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
# Arena CodeAgent Harness
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
harness。运行时只依赖 Node.js,不再依赖 Python:
|
|
3
|
+
这是一个基于 `message.json` 与 `tools.json` 所定义消息和工具契约的 TypeScript
|
|
4
|
+
CodeAgent harness。运行时只依赖 Node.js,不再依赖 Python:
|
|
5
5
|
|
|
6
6
|
- `arena -p ...`:headless 单轮入口,支持文本、完整 JSON 和 NDJSON 流。
|
|
7
7
|
- `arena tui`:终端多轮对话,实时输出并自动保存、恢复历史。
|
|
8
8
|
- `arena serve`:HTTP daemon、Web UI 与双通道 SSE 实时接口。
|
|
9
9
|
- Agent loop:流式 assistant → tool call → tool result → assistant。
|
|
10
|
-
-
|
|
10
|
+
- 15 个工具按照 `tools.json` 中的 Draft-07 schema 提供参数校验。
|
|
11
|
+
|
|
12
|
+
本文提及的第三方产品、模型与服务名称仅用于说明兼容性和配置方式,不表示相关
|
|
13
|
+
权利人对本项目的认可或背书;相关商标归各自权利人所有。使用者应自行确认并遵守
|
|
14
|
+
所接入模型、数据源和在线服务的许可、服务条款及适用法律。
|
|
11
15
|
|
|
12
16
|
## 源码与 SDK 安装
|
|
13
17
|
|
|
@@ -86,6 +90,39 @@ code-harness -p '做一个单文件网页' --mode html
|
|
|
86
90
|
`CODE_HARNESS_MODE`、`ARENA_MODE` 及旧模式别名。详细目录和发包决策见
|
|
87
91
|
[`docs/MODES_AND_RELEASES.md`](docs/MODES_AND_RELEASES.md)。
|
|
88
92
|
|
|
93
|
+
如需完全替换模型收到的 system prompt,可在任一运行入口传入
|
|
94
|
+
`--system-prompt <text>`:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
arena -p '分析这个目录' --system-prompt '你是一名精简的代码审查助手。'
|
|
98
|
+
arena tui --system-prompt '始终先给结论,再解释原因。'
|
|
99
|
+
arena serve --system-prompt '只使用中文回复。'
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
该参数只在运行时覆盖第一条 system message,不会修改 canonical prompt fixture;
|
|
103
|
+
续跑已有 session 时,当前传入的值会替换历史中的 system message。未传参数时,
|
|
104
|
+
日期、workspace 和 mode 对应的现有 prompt 生成逻辑保持不变。
|
|
105
|
+
|
|
106
|
+
如需保留当前 mode 生成的 system prompt,只在末尾追加任务或部署指令,可传入
|
|
107
|
+
`--append-system-prompt <text>`:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
arena -p '分析这个目录' --append-system-prompt '回答保持精简。'
|
|
111
|
+
arena tui --append-system-prompt '始终先给结论,再解释原因。'
|
|
112
|
+
arena serve --append-system-prompt '只使用中文回复。'
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
追加内容会作为独立段落放在运行时 system message 末尾,因此原有日期、workspace、
|
|
116
|
+
工具和 mode 指令保持不变,也不会修改 canonical prompt fixture。同一会话内只会追加
|
|
117
|
+
一次,不会随 turn 重复累积。使用 headless CLI 续跑 session 时,需要再次传入相同的
|
|
118
|
+
追加参数。`--system-prompt` 与 `--append-system-prompt` 可以同时使用,此时先完整
|
|
119
|
+
替换,再追加指定文本。
|
|
120
|
+
|
|
121
|
+
`arena serve` 是一个例外:未显式传入 `--system-prompt` 时,它会保留现有系统
|
|
122
|
+
提示词中的日期、workspace、工具和 mode 指令,但默认将身份声明设为 `Qwen`。
|
|
123
|
+
显式传入 `--system-prompt` 时仍会完整替换系统提示词;仅传
|
|
124
|
+
`--append-system-prompt` 时,则先应用该 Qwen 身份变换,再追加文本。
|
|
125
|
+
|
|
89
126
|
Arena 模式下,如需从 system prompt 的身份模型列表中移除 `Qwen`,可增加
|
|
90
127
|
`--exclude-qwen-from-system-prompt`,或设置
|
|
91
128
|
`ARENA_EXCLUDE_QWEN_FROM_SYSTEM_PROMPT=true`。CLI 开关优先于环境变量:
|
|
@@ -96,15 +133,18 @@ arena tui --exclude-qwen-from-system-prompt
|
|
|
96
133
|
arena serve --exclude-qwen-from-system-prompt
|
|
97
134
|
```
|
|
98
135
|
|
|
99
|
-
三个 Code Arena
|
|
136
|
+
三个 Code Arena 模式的兼容性测试集、工具回归测试和模型行为评估入口见
|
|
100
137
|
[`tasks/code-harness/README.md`](tasks/code-harness/README.md);这些开发数据不会
|
|
101
138
|
进入 npm 或 SEA 发布包。
|
|
102
139
|
|
|
103
140
|
## 模型
|
|
104
141
|
|
|
105
|
-
TypeScript
|
|
106
|
-
|
|
107
|
-
OpenAI
|
|
142
|
+
TypeScript 运行时根据模型前缀与名称选择协议:`anthropic/` 使用原生
|
|
143
|
+
Messages,`gemini/` 使用 Google 的 OpenAI-compatible 接口;`openai/` 或
|
|
144
|
+
无前缀模型使用 OpenAI 传输,其中模型名包含 `gpt`(大小写不敏感)时默认
|
|
145
|
+
使用 Responses,其余使用 Chat Completions。无前缀且名称包含 `claude` 时
|
|
146
|
+
使用 Anthropic Messages。显式 provider 前缀与 `ARENA_OPENAI_API` 始终优先。
|
|
147
|
+
LiteLLM 官方提供 Python SDK 或独立 Proxy,因此
|
|
108
148
|
纯 TypeScript 版本使用
|
|
109
149
|
[LiteLLM Proxy](https://docs.litellm.ai/) 作为多 provider 网关:
|
|
110
150
|
|
|
@@ -140,10 +180,19 @@ export OPENAI_API_KEY=...
|
|
|
140
180
|
```
|
|
141
181
|
|
|
142
182
|
`OPENAI_BASE_URL` / `OPENAI_API_KEY` 是统一的模型连接入口,变量名不决定
|
|
143
|
-
wire protocol。`OPENAI_MODEL=anthropic/...`
|
|
144
|
-
Anthropic Messages payload 并使用 `x-api-key
|
|
145
|
-
`<base>/chat/completions`
|
|
146
|
-
|
|
183
|
+
wire protocol。`OPENAI_MODEL=anthropic/...` 会向 `<base>/messages` 发送
|
|
184
|
+
Anthropic Messages payload 并使用 `x-api-key`;OpenAI 路由根据上述规则向
|
|
185
|
+
`<base>/chat/completions` 或 `<base>/responses` 发送 Bearer 请求。Responses
|
|
186
|
+
路径固定使用 `store=false`,不会发送 `previous_response_id` 或 conversation。
|
|
187
|
+
每次响应完成时,Harness 会把 `reasoning`、`function_call` 和 assistant message
|
|
188
|
+
等原生 output items 原样保存在 assistant 历史中;其中 reasoning 的
|
|
189
|
+
`encrypted_content` 是 OpenAI 返回的不可读加密载荷。后续工具 step 和跨 CLI
|
|
190
|
+
回合会把这些 output items 连同 function output 一起完整回放到下一次 `input`,
|
|
191
|
+
从而在不依赖 provider 端存储的情况下保留隐藏 reasoning。请求显式包含
|
|
192
|
+
`reasoning.encrypted_content`;GPT-5.6 还会使用 `reasoning.context=all_turns`。
|
|
193
|
+
设置 `ARENA_OPENAI_API=chat` 或 `responses` 可覆盖 GPT 的自动选择。
|
|
194
|
+
该开关不作用于 LiteLLM、Gemini 或 Anthropic 路由。如未设置统一入口,
|
|
195
|
+
Anthropic 可回退到 `ANTHROPIC_BASE_URL` /
|
|
147
196
|
`ANTHROPIC_API_KEY`。
|
|
148
197
|
|
|
149
198
|
Anthropic 直连默认只用 `x-api-key` 鉴权(同时携带 Authorization 会让部分
|
|
@@ -160,11 +209,11 @@ Anthropic 直连在原生协议上完整支持 thinking。旧版 Claude 和非 C
|
|
|
160
209
|
budget。Anthropic 要求启用 thinking 时不调整 temperature,此时不发送该
|
|
161
210
|
参数。带签名的 thinking/redacted_thinking block 会原样保存在对应 assistant
|
|
162
211
|
消息的 `reasoning_details` 字段——
|
|
163
|
-
Anthropic 要求 tool-use 续跑时回传签名 thinking block
|
|
212
|
+
Anthropic 要求 tool-use 续跑时回传签名 thinking block,恢复历史上下文时会按
|
|
164
213
|
原顺序还原;无签名的 thinking block(部分网关返回 `signature: ""`)
|
|
165
|
-
|
|
214
|
+
不会再次发送,因为协议不需要它们,而且某些网关收到会挂起。
|
|
166
215
|
`reasoning_content` 仍是纯文本推理,历史契约不变。向
|
|
167
|
-
OpenAI-compatible
|
|
216
|
+
OpenAI-compatible 服务发送同一份历史时,`reasoning_details` 与 `usage`
|
|
168
217
|
一样在 wire 边界剥离。usage 会映射为 OpenAI 风格字段(`prompt_tokens`
|
|
169
218
|
含 cache 创建/读取部分),同时保留 `input_tokens`、
|
|
170
219
|
`cache_read_input_tokens` 等原生字段。`OPENAI_BASE_URL` 对 anthropic
|
|
@@ -191,8 +240,9 @@ ARENA_COMPACTION_SUMMARY_MAX_TOKENS=8192
|
|
|
191
240
|
```
|
|
192
241
|
|
|
193
242
|
可选的 `ARENA_REASONING_EFFORT` 支持 `low`、`medium`、`high`、`xhigh`
|
|
194
|
-
和 `max` 五档;
|
|
195
|
-
Anthropic Messages 请求映射为
|
|
243
|
+
和 `max` 五档;Chat Completions 请求使用 `reasoning_effort`,Responses
|
|
244
|
+
请求使用 `reasoning.effort`,原生 Anthropic Messages 请求映射为
|
|
245
|
+
`output_config.effort`。不会按模型静默
|
|
196
246
|
降档;目标模型或兼容网关不支持所选档位时,由服务端返回明确错误。
|
|
197
247
|
`ARENA_DISALLOWED_TOOLS` 是 JSON 字符串数组,工具名精确匹配:
|
|
198
248
|
|
|
@@ -207,17 +257,17 @@ ARENA_DISALLOWED_TOOLS=["bash","write_file"]
|
|
|
207
257
|
参数覆盖,也会原样写入 `history.json` 的
|
|
208
258
|
`metadata.parameters.extra_body`。
|
|
209
259
|
|
|
210
|
-
`ROUTIFY_API_KEY` 供 `web_search` 和
|
|
260
|
+
`ROUTIFY_API_KEY` 供 `web_search`、`image_search`、`generate_image` 和
|
|
261
|
+
`generate_speech` 使用;开启
|
|
211
262
|
`CODE_HARNESS_ROUTIFY_WEB_FETCH_ENABLED` 后,Arena 的 `fetch_page` 和 Code Arena 的
|
|
212
263
|
`web_fetch` 也复用该密钥,通过 Routify 先调用 Firecrawl,失败时回退到
|
|
213
264
|
Jina Reader。
|
|
214
|
-
|
|
215
|
-
作为主模型连接的密钥。
|
|
265
|
+
该密钥不会作为主模型连接的密钥。
|
|
216
266
|
|
|
217
267
|
Harness 会在每次模型调用前估算消息、reasoning、工具 schema 和图片占用;达到
|
|
218
268
|
`ARENA_CONTEXT_WINDOW × ARENA_CONTEXT_COMPACTION_RATIO`(默认 80%)时,调用
|
|
219
269
|
当前模型把已完成的旧回合生成结构化续作摘要。只有发给模型的内存上下文会把
|
|
220
|
-
|
|
270
|
+
旧前缀替换为符合既有会话格式的 leading `<arena-system-message>`;持久化的
|
|
221
271
|
`history.json.messages` 保留原始消息,不会因压缩删除或替换前缀。当前用户回合及
|
|
222
272
|
其后的 tool-call / result 链在模型上下文中保持原样。摘要重点保留目标、硬约束、
|
|
223
273
|
发现、已完成/未完成事项、下一步和相关文件路径;摘要调用默认关闭 thinking,
|
|
@@ -225,14 +275,20 @@ Harness 会在每次模型调用前估算消息、reasoning、工具 schema 和
|
|
|
225
275
|
`ARENA_COMPACTION_SUMMARY_MAX_TOKENS` 控制(默认 8192)。
|
|
226
276
|
|
|
227
277
|
`ARENA_CONTEXT_WINDOW` 应设置为所用模型的真实上下文窗口;默认 `1000000` 是
|
|
228
|
-
|
|
278
|
+
当前默认模型的暂定值。token 数目前是本地保守估算,并非 provider tokenizer
|
|
229
279
|
的精确计数。如果摘要请求失败,Harness 会保留原历史并继续正常模型请求,避免
|
|
230
280
|
摘要服务的瞬时故障直接中断任务。
|
|
231
281
|
|
|
282
|
+
Responses 与其他协议一样,会在每个工具 step 前检查是否需要压缩。由于所有
|
|
283
|
+
reasoning/function-call 状态都由本地 history 携带,压缩不再需要切断或重建 provider
|
|
284
|
+
端 response 链。压缩会把已完成的旧回合替换成续作摘要,同时保留当前 user turn 里的
|
|
285
|
+
加密 reasoning、function call 和 function output;下一次 Responses 请求直接回放这份
|
|
286
|
+
压缩后的本地上下文。持久化的原始 `history.json` 仍保持 append-only。
|
|
287
|
+
|
|
232
288
|
每次模型请求都会通过 OpenAI-compatible 的 `stream_options.include_usage`
|
|
233
289
|
请求 token 用量,并把服务端在最终 chunk 上报的 `usage` 对象原样记录到该轮
|
|
234
290
|
assistant 消息的 `usage` 字段(`history.json` 与事件流中均可见),供训练
|
|
235
|
-
|
|
291
|
+
和成本统计使用。再次发送历史上下文时,`usage` 会在 wire 边界剥离,不会发回
|
|
236
292
|
服务端。`model.complete` 事件同样携带该轮 `usage`;上下文压缩的摘要调用
|
|
237
293
|
不会在历史中留下消息,其用量通过 `compaction` 事件上报,只在事件流中可
|
|
238
294
|
见。不支持 `stream_options` 的服务可通过 `ARENA_EXTRA_BODY` 覆盖该参数。
|
|
@@ -250,6 +306,14 @@ assistant 消息的 `usage` 字段(`history.json` 与事件流中均可见)
|
|
|
250
306
|
`model.retry` 事件(TUI 会显示「reconnecting after a network error」提示)。
|
|
251
307
|
用户主动取消(abort)不会被当作可重试的网络故障。
|
|
252
308
|
|
|
309
|
+
OpenAI Responses 还会检查 HTTP 200 SSE 中的 `error` / `response.failed`
|
|
310
|
+
事件。带 408/409/429/5xx 或明确瞬时错误类型的事件会整轮重试;上游只给文本时,
|
|
311
|
+
仅明确的 `experiencing high demand`、`maximum usage size allowed during peak
|
|
312
|
+
load`、`Provisioned Throughput` 容量错误会重试。容量错误最多重试 5 次
|
|
313
|
+
(`ARENA_MODEL_MAX_RETRIES` 可进一步降低或关闭),每次均重新发送完全相同的
|
|
314
|
+
模型输入,并沿用 full-jitter 指数退避。上下文超限、参数、鉴权、媒体和安全错误
|
|
315
|
+
等永久错误不会因正文中出现 `error` 一词而重试。
|
|
316
|
+
|
|
253
317
|
Agent turn 默认没有模型 step 数上限;设置 `ARENA_MAX_TURNS` 后,达到指定上限
|
|
254
318
|
会返回 error,已经完成的 assistant/tool step 仍会保留。整轮没有内建墙钟时长
|
|
255
319
|
上限,会持续到模型正常结束、请求用户输入、发生不可恢复错误、达到显式配置的
|
|
@@ -319,12 +383,17 @@ Arena 还维护一份有顺序的模型输入模态表,在第一次 HTTP 调
|
|
|
319
383
|
转换为文字;主模型支持图片、模型未知或 Code Arena 模式均不触发此 fallback。
|
|
320
384
|
fallback 不继承 `ARENA_EXTRA_BODY` 或主模型生成参数;原生 Anthropic Messages
|
|
321
385
|
因协议要求会单独使用 `max_tokens: 16384`。
|
|
386
|
+
同一条件下,用户直接附加的图片不会发送给主模型;已有附件文件列表会保留,并提示
|
|
387
|
+
模型调用 `read_file` 获取 fallback 生成的文字版本。
|
|
322
388
|
|
|
323
389
|
输出事件及 JSON 结果中的 `session_id` 就是路径里的 `<sessionId>`。
|
|
324
390
|
`history.json` 的 `messages` 是只追加的原始轨迹;上下文压缩只影响发送给模型的
|
|
325
391
|
临时副本。`metadata` 记录 session、模型以及本次实际生效的 `max_turns`、
|
|
326
|
-
`context_window
|
|
327
|
-
|
|
392
|
+
`context_window`、生成和压缩参数。`tools` 记录最近一次保存时实际提供给模型的
|
|
393
|
+
完整工具定义,包括针对 workspace 的描述改写和不可用工具(未接 `ask_user`
|
|
394
|
+
handler、`ARENA_DISALLOWED_TOOLS`)的过滤结果。daemon 完成一次 turn 后还会写入
|
|
395
|
+
`version: 4`;开启动态指标统计(`ARENA_METRICS_SIDE_QUERY_ENABLED`,默认关闭)
|
|
396
|
+
时还会写入 `metrics`,后者是截至该 turn 的 praise vs. complaint、
|
|
328
397
|
steerability、Bash recovery 与 tool hallucination 增量快照。即使结果为
|
|
329
398
|
`needs_input` 或 `error` 也会保存;旧的 `{"messages":[...]}` 历史仍可直接加载。
|
|
330
399
|
需要跨命令续写同一份显式历史时,可另外传入
|
|
@@ -358,17 +427,17 @@ arena -p 'redraw this photo with the reference face' \
|
|
|
358
427
|
每个附件会被保存到工作区 `uploads/`(模型内可通过
|
|
359
428
|
`/home/user/uploads/<name>` 访问;重名自动加 `-2`、`-3` 后缀,URL 无扩展名
|
|
360
429
|
时按图片字节特征补全扩展名)。本轮 user message 与 daemon 附件上传共用同
|
|
361
|
-
|
|
430
|
+
一构造逻辑,并使用统一的会话部件格式:图片部件
|
|
362
431
|
`{"image": ...}` 在前,随后是 prompt 文本 `{"text": ...}`,最后追加一条
|
|
363
432
|
`<arena-system-message>`,列出保存到 `/home/user/uploads/` 的文件名。单条
|
|
364
433
|
消息最多 10 个附件,单个附件上限 20 MB、总量上限 50 MB,与 daemon 一致。
|
|
365
434
|
|
|
366
435
|
多模态 user 消息(附件、图片 `read_file` 回灌、中断通知)在历史与事件流中
|
|
367
|
-
一律使用
|
|
368
|
-
|
|
436
|
+
一律使用 `{"image": ...}` / `{"text": ...}` 原生部件并保持字段格式一致;仅在
|
|
437
|
+
向模型发起 chat-completions 请求的边界处转换为
|
|
369
438
|
OpenAI 风格的 `image_url` 部件。`--attach` 传 URL 时 `image` 直接记录该
|
|
370
|
-
URL
|
|
371
|
-
|
|
439
|
+
URL(模型服务端会自行下载;恢复历史上下文时要求该 URL 仍可访问);本地文件
|
|
440
|
+
没有可引用的 URL,`image` 存自包含的 base64
|
|
372
441
|
data-URI。
|
|
373
442
|
|
|
374
443
|
`stream-json` 每行一个 JSON 对象。`start`、`message`、`result` 事件中的
|
|
@@ -382,7 +451,12 @@ data-URI。
|
|
|
382
451
|
|
|
383
452
|
`assistant.delta` 实时提供 content、reasoning 与 tool-call 参数碎片;
|
|
384
453
|
`model.start`、`model.complete`、`model.retry`、`tool.start`、`tool.complete`
|
|
385
|
-
标记阶段。最后的 `result`
|
|
454
|
+
标记阶段。最后的 `result` 带完整消息。
|
|
455
|
+
|
|
456
|
+
Headless 会向模型提供 `present_file`,以保持生成轨迹与 Arena 工具契约一致。
|
|
457
|
+
该工具在 headless 中只校验目标是 workspace 内已有文件,并返回
|
|
458
|
+
`{"path":"<原始路径>","status":"success"}`;不会连接前端或打开 viewer。
|
|
459
|
+
自动打开 viewer 仅由 daemon/WebUI 消费同一工具结果后触发。
|
|
386
460
|
|
|
387
461
|
`ask_user` 只有在注入 handler 时才会提供给模型。TUI 和 WebUI 使用真人交互
|
|
388
462
|
handler;headless(`-p`)默认仍不开放该工具,但可配置远程 User Agent handler:
|
|
@@ -426,8 +500,9 @@ arena tui --workspace . --model mock/ask-user --session-id my-session
|
|
|
426
500
|
workspace 默认是启动命令时的当前目录(可用 `--workspace` 覆盖)。TUI 会把
|
|
427
501
|
实际 workspace root 和 cwd 动态注入 system prompt 与工具 schema;因此本机
|
|
428
502
|
运行时使用本机路径,部署进沙箱后会自然使用沙箱内的实际路径,不需要切换模式。
|
|
429
|
-
TUI
|
|
430
|
-
|
|
503
|
+
TUI 会向模型提供 `present_file`,以保持生成轨迹与 Arena 工具契约一致。由于
|
|
504
|
+
TUI 没有内置文件 viewer,该工具只校验 workspace 内的目标文件并返回 canonical
|
|
505
|
+
成功结果,不会打开文件;模型仍会在正文中报告生成文件的实际路径。
|
|
431
506
|
|
|
432
507
|
assistant 的 reasoning、正文和工具调用状态会边生成边输出。每轮结束都会把
|
|
433
508
|
完整消息原子写入与 headless、daemon 相同的 `history.json`;再次传入相同的
|
|
@@ -673,7 +748,7 @@ curl -N -X POST \
|
|
|
673
748
|
|
|
674
749
|
## 工具
|
|
675
750
|
|
|
676
|
-
|
|
751
|
+
消息与工具契约配置保存在:
|
|
677
752
|
|
|
678
753
|
- `spec/message.json`
|
|
679
754
|
- `spec/tools.json`
|
|
@@ -682,40 +757,56 @@ curl -N -X POST \
|
|
|
682
757
|
`spec/` 目录,运行时也不依赖仓库文件。执行工具前仍使用 AJV 校验原始
|
|
683
758
|
Draft-07 schema。repo mode 的动态提示词模板保存在 `src/prompts.ts`:
|
|
684
759
|
|
|
685
|
-
`bash`、`ask_user`、`edit_file`、`read_file`、`fetch_page
|
|
686
|
-
`write_file`、`image_search`、`present_file`、`
|
|
687
|
-
`generate_speech`。
|
|
760
|
+
`bash`、`ask_user`、`add_voice`、`edit_file`、`read_file`、`fetch_page`、
|
|
761
|
+
`web_search`、`write_file`、`image_search`、`present_file`、`stop_process`、
|
|
762
|
+
`start_process`、`generate_image`、`generate_speech`、`get_process_output`。
|
|
763
|
+
|
|
764
|
+
新版生产导出的前 50 条脱敏请求单独保存在
|
|
765
|
+
[`tasks/v2`](tasks/v2/README.md),没有与原有 replay 数据混放。该目录记录了
|
|
766
|
+
2 GB 源文件的 SHA-256、全量解析统计、tool schema 变体和可重复执行的拆分命令;
|
|
767
|
+
`npm run refresh:arena-v2-contract` 用它刷新 canonical prompt/tool fixtures 并重新
|
|
768
|
+
生成 `src/canonical-data.ts`。
|
|
769
|
+
|
|
770
|
+
`bash` 只用于一次性命令:超时结果为 `status=timeout`,被信号终止为
|
|
771
|
+
`status=killed`,并会清理命令遗留的后台进程。需要跨 tool call 存活的 server、
|
|
772
|
+
watcher 或任务应使用 `start_process`;随后可用 `get_process_output` 按日志、端口
|
|
773
|
+
或退出状态阻塞等待,并用 `stop_process` 停止整个进程组。完整合并日志保存在
|
|
774
|
+
工作区的 `.arena/processes/`,工具返回对应的 `log_tail`;`stop_process` 对齐生产
|
|
775
|
+
只返回最后 100 行。assistant tool call 和这些 JSON tool result 会原样写入
|
|
776
|
+
`history.json`,供后续 turn replay。`start_process` 在 E2B 环境中还会用
|
|
777
|
+
`E2B_SANDBOX_ID` 组成 `{port}-{sandboxId}.e2b.app`,分别探测本地 Host 和用户
|
|
778
|
+
预览 Host;如果新开的公网端口仅拒绝后者,结果会按需增加 `warnings`。其他预览
|
|
779
|
+
代理可用 `ARENA_PREVIEW_HOST_TEMPLATE` 配置 Host 模板。没有告警时不返回该字段,
|
|
780
|
+
保持普通捕获的结果 shape 不变。
|
|
688
781
|
|
|
689
782
|
`web_search` 使用 Routify 网关提供的 Brave LLM Context,从工作区 `.env`
|
|
690
|
-
读取 `ROUTIFY_API_KEY
|
|
691
|
-
`
|
|
692
|
-
并使用 `brave.llm-context` 路由。实现按 depth 请求最多 3/5/8 条结果,并将
|
|
783
|
+
读取 `ROUTIFY_API_KEY`,默认通过内置的 ModelRouter 兼容接口调用
|
|
784
|
+
`brave.llm-context` 路由。实现按 depth 请求最多 3/5/8 条结果,并将
|
|
693
785
|
`grounding.generic` 的内容片段及 `sources` 的来源信息转换成 Arena 的既有工具
|
|
694
786
|
结果。请求固定考虑最多 20 个搜索候选,再通过 `maximum_number_of_urls` 将
|
|
695
787
|
最终来源数限制为 3/5/8。depth 还分别对应 1024/3072/8192 的总 token 预算和
|
|
696
788
|
512/552/2048 的单 URL token 预算;description 使用预算内的全部 grounding
|
|
697
789
|
snippets,仅在没有 grounding 内容时回退到来源摘要。三个 Code Arena 模式
|
|
698
|
-
|
|
790
|
+
使用独立的模式参数:来源数 3/5/10、总 token 预算 1280/4096/6144、单 URL
|
|
699
791
|
token 预算 512/1280/1536。
|
|
700
792
|
可用 `ROUTIFY_WEB_SEARCH_URL` 和 `ARENA_WEB_SEARCH_MODEL` 覆盖默认值。
|
|
701
793
|
|
|
702
794
|
`image_search` 使用 Routify 网关提供的 Brave Images Search,同样读取
|
|
703
|
-
`ROUTIFY_API_KEY`,通过 `X-Subscription-Token` 发送 GET
|
|
704
|
-
`
|
|
705
|
-
|
|
795
|
+
`ROUTIFY_API_KEY`,通过 `X-Subscription-Token` 发送 GET 请求。默认使用内置的
|
|
796
|
+
ModelRouter 兼容接口,可用 `ROUTIFY_IMAGE_SEARCH_URL` 覆盖。实现优先下载 Brave
|
|
797
|
+
返回的原图地址,原图不可用
|
|
706
798
|
时回退到 Brave 代理缩略图,并保持既有工具结果格式和工作区文件命名不变。
|
|
707
799
|
|
|
708
800
|
Arena 的 `fetch_page` 和 Code Arena 的 `web_fetch` 默认仍使用本地抓取与正文
|
|
709
|
-
解析。设置 `CODE_HARNESS_ROUTIFY_WEB_FETCH_ENABLED=true` 后,两者改走 Routify
|
|
710
|
-
|
|
711
|
-
非 200 或响应不可用时回退到 `readpage-jina-inner`;两者都失败则返回普通工具
|
|
801
|
+
解析。设置 `CODE_HARNESS_ROUTIFY_WEB_FETCH_ENABLED=true` 后,两者改走 Routify
|
|
802
|
+
页面读取接口,并在首选读取服务不可用时使用备用服务;两者都失败则返回普通工具
|
|
712
803
|
错误。`fetch_page` 仍按 8000 字符分块并缓存同一 URL 的后续 chunk。认证复用
|
|
713
804
|
`ROUTIFY_API_KEY`。
|
|
714
805
|
|
|
715
|
-
`generate_image`、`generate_speech`
|
|
716
|
-
`.env`
|
|
717
|
-
|
|
718
|
-
|
|
806
|
+
`generate_image`、`generate_speech` 使用 ModelRouter/Routify,并从工作区
|
|
807
|
+
`.env` 读取同一个 `ROUTIFY_API_KEY`。图片使用 Google 兼容协议调用;可用
|
|
808
|
+
`ROUTIFY_VERTEX_BASE_URL` 覆盖默认根地址。语音使用 ModelRouter 的火山引擎
|
|
809
|
+
`/protocol/volcengine/api/v1/tts` 路由,不需要新增服务密钥。
|
|
719
810
|
|
|
720
811
|
`fetch_page` 使用 Defuddle 将 HTML 正文转换为 Markdown,并使用
|
|
721
812
|
`pdf-parse` 提取 PDF 的前 30 页。响应按 Markdown 边界稳定分块,同一轮内
|
|
@@ -730,10 +821,19 @@ Arena 的 `fetch_page` 和 Code Arena 的 `web_fetch` 默认仍使用本地抓
|
|
|
730
821
|
内容继续发送给模型。所有工具结果另有 1,000,000 字符的最终兜底。当前不做
|
|
731
822
|
OCR,扫描版 PDF 只会返回无可提取文字的提示。
|
|
732
823
|
|
|
733
|
-
|
|
824
|
+
图片和语音的默认 ModelRouter 路由分别为 `gemini-2.5-flash-image` 和
|
|
825
|
+
`doubao-tts`,可用 `ARENA_IMAGE_MODEL`、`ARENA_SPEECH_MODEL` 覆盖。图片生成结果和
|
|
734
826
|
搜索到的图片会立即下载到工作区;每次图片搜索的结果按生产命名保存为
|
|
735
827
|
`image-search/<query slug>-<序号>.<扩展名>`,并作为可预览文件显示在 Web UI。
|
|
736
|
-
|
|
828
|
+
语音生成先由 `add_voice` 生成两个试听候选并让用户选择,选择结果注册为稳定的
|
|
829
|
+
`voice_id`;后续 `generate_speech` 必须传入该 id。
|
|
830
|
+
无交互 handler 的 headless 模式仍会开放 `add_voice`,但不会生成无法播放的试听;
|
|
831
|
+
它会按语言和 `voice_identity` 确定性注册一个默认音色,并在结果中以
|
|
832
|
+
`virtual: true` 标记。返回的 `voice_id` 可直接用于后续 `generate_speech`。
|
|
833
|
+
也可用
|
|
834
|
+
`ARENA_SPEECH_VOICE` 强制覆盖底层音色。豆包响应中的 Base64 数据已经是 MP3、RIFF/WAV
|
|
835
|
+
或 Ogg Opus;`.ogg` 与 `.opus` 都保存 Ogg Opus 数据,所有支持的输出均不依赖
|
|
836
|
+
本地 `ffmpeg` 或 `lame`。
|
|
737
837
|
|
|
738
838
|
所有路径工具都限制在 `--workspace` 内并检查符号链接逃逸。`bash` 是本机
|
|
739
839
|
子进程,不是操作系统安全沙箱;多租户或不可信模型部署应使用容器或 VM。
|
|
@@ -749,4 +849,7 @@ npm test
|
|
|
749
849
|
```
|
|
750
850
|
|
|
751
851
|
测试覆盖消息契约、工具校验、headless、`/query`、实时双通道、
|
|
752
|
-
`ask_user`、`present_file` 和 daemon 优雅退出。
|
|
852
|
+
`ask_user`、`add_voice`、后台进程工具、`present_file` 和 daemon 优雅退出。
|
|
853
|
+
配置 `.env` 中的 `ROUTIFY_API_KEY` 后,可运行
|
|
854
|
+
`npm run verify:live-speech-voices` 对 headless `add_voice` 到真实
|
|
855
|
+
`generate_speech` 的多音色链路做烟测。
|
package/dist/agent.d.ts
CHANGED
|
@@ -2,16 +2,17 @@ import { type ArenaConfig } from "./config.js";
|
|
|
2
2
|
import { EventSink } from "./protocol.js";
|
|
3
3
|
import { type HarnessMode } from "./mode.js";
|
|
4
4
|
import { ToolExecutor } from "./tools.js";
|
|
5
|
-
import type { AgentResult, AskUserHandler, ClientContext, Message, ModelClient, RepoContext, UserTurnMessage, WorkspaceContext } from "./types.js";
|
|
5
|
+
import type { AgentResult, AskUserHandler, ClientContext, Message, ModelClient, RepoContext, ToolDefinition, UserTurnMessage, WorkspaceContext } from "./types.js";
|
|
6
6
|
interface AgentOptions {
|
|
7
7
|
client?: ModelClient;
|
|
8
8
|
tools?: ToolExecutor;
|
|
9
9
|
askUserHandler?: AskUserHandler;
|
|
10
10
|
sessionId?: string;
|
|
11
|
+
sessionAffinityId?: string;
|
|
11
12
|
signal?: AbortSignal;
|
|
12
13
|
clientContext?: ClientContext;
|
|
13
14
|
workspaceContext?: WorkspaceContext;
|
|
14
|
-
onCheckpoint?: (messages: readonly Message[]) => Promise<void>;
|
|
15
|
+
onCheckpoint?: (messages: readonly Message[], tools: readonly ToolDefinition[]) => Promise<void>;
|
|
15
16
|
onModelFailure?: (messages: readonly Message[], error: unknown) => void;
|
|
16
17
|
}
|
|
17
18
|
interface AgentRunOptions {
|
|
@@ -27,6 +28,7 @@ export declare class Agent {
|
|
|
27
28
|
private readonly client;
|
|
28
29
|
private readonly tools;
|
|
29
30
|
private readonly workspaceContext?;
|
|
31
|
+
private readonly sessionAffinityId;
|
|
30
32
|
readonly sessionId: string;
|
|
31
33
|
constructor(config: ArenaConfig, sink: EventSink, options?: AgentOptions);
|
|
32
34
|
run(prompt: string, history?: Message[], runOptions?: AgentRunOptions): Promise<AgentResult>;
|