Interactive REPL demo (v2):用自研 oc-repl 在 run-3 iter215 上跑 4 个 TB 任务 × 2 套协议
接续 #10 / #11 / #13 的工作。基于 #13 评论 里查明的 "camel 和 terminus 都没官方 REPL" 的结论,自己开了个独立工具 HansBug/oc-repl,用它重录了这次 demo——单一 CLI、Codex 风格 UI、一行启动、交互模式 + 非交互 exec 模式都支持。
TL;DR:oc-repl 把 camel-ai 的 TerminalToolkit 协议(openai-tools)和 terminal-bench terminus-2 的 JSON 协议(terminus-json)统一在一个 30 行级别的 Codex-style REPL 里。<think> 默认折成 spinner,正式 assistant 输出(analysis + plan)和 tool block 视觉权重对等,命令输出做了篇幅控制(10 行 × 180 字符 + … N more lines clipped)。8 段动图 = 4 个真实 TB 任务 × terminus-json / openai-tools 两条协议。
3 套协议在一个 CLI 里:
启动一行:
oc-repl --protocol terminus-json \
--sandbox docker:openclaw-fixperm \
--api-base http://127.0.0.1:30000/v1 \
--model qwen3-8b-rl-iter215
非交互(Codex exec 等价品):
oc-repl exec --protocol terminus-json --sandbox docker:openclaw-fixperm \
"Fix /app/process_data.sh so it can run, then run it."
# 退出码:0 = task_complete / 1 = parse 错误 / 2 = 没 task_complete / 3 = verify FAIL
# --json 输出机器可读的 {rounds, commands, task_complete, last_summary, verify}
带评分钩子(agent 自报 task_complete 后跑一段验证脚本,把"agent 觉得自己赢了"和"任务真做对了"分开):
oc-repl exec --sandbox docker:openclaw-recover \
--verify-file /nfs/terminal-rl-workspace/openclaw-repl-demo/scripts/check_recover.sh \
"Decode each *.b64_content in /app/sensitive_data/ — basename and content are both base64. Restore them into /app/recovered/."
# 结尾会多出一个 ✓ verified(绿) / ✗ verification failed(红)面板。
--sandbox 不是 required option,省略时默认 local(host shell,banner 会用黄字醒目提醒「⚠ commands will run on the host shell」)。docker:NAME 模式假设容器已经预先 docker run -d 起好,oc-repl 只 attach、不 spawn。
详见仓库 README 和 AGENTS.md。
2. UI 设计要点(响应 #13 评审)
| 元素 |
行为 |
<think>...</think> |
默认隐藏,渲染成 thinking… 3.2s · 184 chars spinner。--show-thinking 或运行时 /think 切换。 |
analysis / plan 等正式输出 |
Codex 风格:assistant cyan 灯片 + 加粗 cyan 标签 + 缩进 normal-weight prose,与 tool block 等权重。 |
| Tool call |
框圆角面板,标题栏 ▸ shell,命令一行加粗,captured stdout/stderr 收紧到 ≤10 行 × ≤180 字符,超出显示 … (N more lines clipped);exit 0 绿底、非零红底。 |
| 末尾 |
✓ rounds=N commands=M task_complete=… verify=… 一行 footer,回到 › 提示。 |
| sandbox |
默认 local(host shell,banner 黄字警告);docker:NAME 自动检测当前 shell 是否有 docker group,没有就自动 wrap sg docker -c '...',并且只 attach 已经 running 的容器。 |
| verify hook |
--verify "<bash cmd>" 或 --verify-file PATH — agent 自报 done 后在 sandbox 跑一段评分脚本,结果用绿/红面板展示,覆盖 model 自报 task_complete 的语义。 |
3. Demo 视频:4 任务 × 2 协议
每条 demo:交互模式,banner → 输入 instruction → 模型 think(spinner 隐藏)→ analysis/plan + tool blocks → task_complete 标志 → 回到 prompt → /quit。末尾静止 8 秒。
任务选自 #10 long-comment 的 truly-learnable 桶 + 新加的 hello-world 起步例:
3.1 terminus-json(与 iter215 RL 训练分布对齐的协议)
| 任务 |
GIF |
MP4 |
| hello-world |
 |
mp4 |
| fix-permissions |
 |
mp4 |
| recover-obfuscated-files |
 |
mp4 |
| heterogeneous-dates |
 |
mp4 |
3.2 openai-tools(camel-ai TerminalToolkit 兼容协议)
| 任务 |
GIF |
MP4 |
| hello-world |
 |
mp4 |
| fix-permissions |
 |
mp4 |
| recover-obfuscated-files |
 |
mp4 |
| heterogeneous-dates |
 |
mp4 |
4. 复现 / 接管 runbook 摘要
完整版见持久路径 /nfs/terminal-rl-workspace/openclaw-repl-demo/README.md 以及 HansBug/oc-repl/README.md。
# 1. 起 sglang(参数:--tool-call-parser qwen,不带 --reasoning-parser 以保留 <think> 流)
python -m sglang.launch_server --model-path /nfs/eval_models/qwen3-8b-rl-iter215 \
--served-model-name qwen3-8b-rl-iter215 --port 30000 --tp 1 --mem-fraction-static 0.85 \
--tool-call-parser qwen
# 2. 起 sandbox 容器(每个 TB 任务一个长寿 docker)
docker run -d --name openclaw-hello -w /app tb__hello-world__client sleep infinity
docker run -d --name openclaw-fixperm -w /app tb__fix-permissions__client sleep infinity
docker run -d --name openclaw-recover -w /app tb__recover-obfuscated-files__client sleep infinity
docker run -d --name openclaw-hetdates -w /app tb__heterogeneous-dates__client sleep infinity
# 3. 装 oc-repl
git clone https://github.com/HansBug/oc-repl && cd oc-repl && pip install -e .
# 4. 跑!
oc-repl --protocol terminus-json --sandbox docker:openclaw-fixperm
# 或者
oc-repl exec --protocol openai-tools --sandbox docker:openclaw-fixperm \
"Fix /app/process_data.sh and run it"
录像通过 VHS 完成,scripts/make_oc_tapes.py 生成 tape,scripts/render_oc_all.sh 批量渲染 + 重置容器。
5. 训练协议 vs. 推理协议(FAQ — 已校正)
短答:ckpt215(以及 run-3 / run-4 etc.)的 RL 训练用的是 camel-ai ChatAgent + camel.toolkits.TerminalToolkit,sglang qwen25 tool-call parser;不是 terminus-2。terminus-2 只在 tb run 评测时用,不进 RL rollout 路径。oc-repl 0.2.0 新加了 --protocol camel-terminal-toolkit 来精确复刻这个分布,且已经作为默认。
5.1 证据链
挨条对着源码看:
-
wandb 启动命令里没有 --terminal-agent-type flag。run msp60ius(产出 iter215 那一次)的完整命令:
python slime/train_async.py ... \
--custom-generate-function-path generate.generate \
--custom-config-path .../configs/rollout_qwen3.yaml
没有 --terminal-agent-type,也没有任何环境变量改写。
-
generate.py:142 默认值是 camel_agent:
rollout_agent = create_rollout_agent(
agent_type=getattr(args, "terminal_agent_type", "camel_agent"),
...
)
-
rollout_agent.py:97-106 只处理 camel_agent 一条路径——其他值直接 raise ValueError:
if agent_type == "camel_agent":
from agent.camel_agent import CamelAgent
return CamelAgent(...)
raise ValueError(f"Unsupported agent type: {agent_type!r}. Expected 'camel_agent'.")
仓库里根本没有 terminus 这条路。
-
agent/camel_agent.py 是 camel.ChatAgent 的子类:
from camel.agents import ChatAgent
...
class CamelAgent(ChatAgent):
"""ChatAgent extension used by AgentRunner's rollout loop."""
-
remote/terminal_env.py:163-185 把 camel TerminalToolkit 的 4 个工具 schema 喂给 rollout:
self._terminal_toolkit = TerminalToolkit(use_docker_backend=True, ...)
self._tools = {
"shell_exec": ...shell_exec,
"shell_view": ...shell_view,
"shell_write_to_process": ...shell_write_to_process,
"shell_write_content_to_file": ...shell_write_content_to_file,
}
tool_schemas = [FunctionTool(fn).get_openai_tool_schema() for fn in self._tools.values()]
-
sglang 用 qwen25 parser 把模型的 <tool_call>...</tool_call> 转回结构化 tool_calls:
# configs/rollout_qwen3.yaml
tool_call_parser: qwen25
-
训练 log 实证:terminal-rl/logs/training_8b_tboverfit.log 里 <tool_call> 出现 628 次,terminus-2 JSON 的 key "task_complete" 出现 0 次。模型实际吐的是:
ToolCallRequest(tool_name='shell_exec',
args={'id': '1', 'command': 'mkdir -p /app/ssl', 'block': True, 'timeout': 20},
tool_call_id='call_9de3e5a5e3ce4d18bf20a0a8')
新加了一个 protocol,对齐到训练分布字节级别:
- 4 个工具 schema:从
camel-ai==0.2.90 的 FunctionTool.get_openai_tool_schema() 抓出来逐字 hardcode,包括 ["boolean", "null"] union 类型 + "strict": true 等训练时模型真的见过的 JSON-schema 细节。
- System prompt:
terminal-rl/agent/camel_agent.py::get_developer_agent_prompt(system='Linux (in Docker)', machine='x86_64', is_workforce=False, non_think_mode=True) 的整段输出原样复制,结尾带 /no_think。
/no_think 这部分是 critical:training-time non_think_mode=True 是默认值(rollout_agent.py:62),模型 RL 训练时根本没生成过 <think> 块;如果把这个去掉、放任 <think> 跑,tool-call adherence 会塌掉(亲测:在 recover 任务上让 think 开着,模型生成 1500+ token 的 prose 然后 0 个 tool_call,verify 直接红)。
- Sandbox 映射:
shell_exec 全保真;shell_write_content_to_file 用 here-doc 100% 保真;shell_view / shell_write_to_process 因为 oc-repl sandbox 是 stateless docker exec(不维护 per-id tmux session),降级为 stub 输出,schema 还在但 session 语义只是「best-effort」。
5.3 其他 protocol 在 iter215 上的语义
| protocol |
是否训练分布 |
实测表现 |
camel-terminal-toolkit(默认,新增 0.2.0) |
✅ 字节级匹配 |
adherence 满分;recover 验证不通过是模型本身没解 filename 那层 base64 的能力问题,不是协议问题 |
openai-tools(简化版 1 个 shell(command) 工具) |
❌ 不匹配 |
简单单步任务 OK(chmod +x 那种);复杂任务偶尔失配 |
terminus-json |
❌ 模型 RL 阶段从没见过 |
靠 qwen3 底座的 JSON 模仿能力跑通;adherence 中等 |
terminus-xml |
❌ 同上 |
比 JSON 还冷,8B 上 adherence 更差 |
→ 「这个 ckpt 应该用哪个」的答案现在是 camel-terminal-toolkit(默认就是它)。
本文档之前给过错误结论(声称训练用 terminus-2),原因是把 evaluation 时的 tb run --agent terminus-2 当成了训练 scaffolding。这一节是更正版,证据全部来自源码 + wandb 启动命令 + 训练 log。
6. 资产清单
📦 打包下载:oc-repl-demo-v2.zip (8.7 MB) 包含全部 8 个 .tape、16 个 .gif + .mp4、make_oc_tapes.py、render_oc_all.sh 以及一个简要的复现 README。
| 路径 |
作用 |
github.com/HansBug/oc-repl/ |
REPL 工具仓库(pip install -e .) |
/nfs/terminal-rl-workspace/oc-repl/ |
工具本地路径 |
/nfs/terminal-rl-workspace/openclaw-repl-demo/scripts/make_oc_tapes.py |
8 段 VHS scenario 生成器 |
/nfs/terminal-rl-workspace/openclaw-repl-demo/scripts/render_oc_all.sh |
重置 sandbox + 批量 vhs 渲染 |
/nfs/terminal-rl-workspace/openclaw-repl-demo/scenarios-oc/*.tape |
8 个 VHS scenario |
/nfs/terminal-rl-workspace/openclaw-repl-demo/output-oc/oc-*.{gif,mp4} |
8 段最终视频 |
/nfs/terminal-rl-workspace/openclaw-repl-demo/scripts/check_recover.sh |
recover 任务的示例 verify 脚本 |
之前版本(旧的 6 段 demo + camel_repl.py wrapper):见 #13 的提交历史;那一版的脚本和媒体保留在 scripts/{camel_repl.py,repl-camel,repl-terminus} + output/,仍可作为对照参考。本次的 v2 demo 把所有协议统一在 oc-repl 里,体验和 Codex 一致。
Interactive REPL demo (v2):用自研
oc-repl在run-3 iter215上跑 4 个 TB 任务 × 2 套协议接续 #10 / #11 / #13 的工作。基于 #13 评论 里查明的 "camel 和 terminus 都没官方 REPL" 的结论,自己开了个独立工具
HansBug/oc-repl,用它重录了这次 demo——单一 CLI、Codex 风格 UI、一行启动、交互模式 + 非交互exec模式都支持。1. 工具:
HansBug/oc-repl3 套协议在一个 CLI 里:
--protocolterminus-json(默认)terminal-bench/.../terminus-json-plain.txt{analysis, plan, commands[].keystrokes, task_complete}terminus-xmlterminal-bench/.../terminus-xml-plain.txt<response><analysis/><plan/><commands>…</commands><task_complete/></response>openai-toolscamel-ai TerminalToolkittool_calls(shell+write_file两个函数)启动一行:
oc-repl --protocol terminus-json \ --sandbox docker:openclaw-fixperm \ --api-base http://127.0.0.1:30000/v1 \ --model qwen3-8b-rl-iter215非交互(Codex
exec等价品):带评分钩子(agent 自报 task_complete 后跑一段验证脚本,把"agent 觉得自己赢了"和"任务真做对了"分开):
--sandbox不是 required option,省略时默认local(host shell,banner 会用黄字醒目提醒「⚠ commands will run on the host shell」)。docker:NAME 模式假设容器已经预先docker run -d起好,oc-repl 只 attach、不 spawn。详见仓库 README 和 AGENTS.md。
2. UI 设计要点(响应 #13 评审)
<think>...</think>thinking… 3.2s · 184 charsspinner。--show-thinking或运行时/think切换。analysis/plan等正式输出assistantcyan 灯片 + 加粗 cyan 标签 + 缩进 normal-weight prose,与 tool block 等权重。▸ shell,命令一行加粗,captured stdout/stderr 收紧到 ≤10 行 × ≤180 字符,超出显示… (N more lines clipped);exit 0绿底、非零红底。✓ rounds=N commands=M task_complete=… verify=…一行 footer,回到›提示。local(host shell,banner 黄字警告);docker:NAME自动检测当前 shell 是否有 docker group,没有就自动 wrapsg docker -c '...',并且只 attach 已经 running 的容器。--verify "<bash cmd>"或--verify-file PATH— agent 自报 done 后在 sandbox 跑一段评分脚本,结果用绿/红面板展示,覆盖 model 自报 task_complete 的语义。3. Demo 视频:4 任务 × 2 协议
每条 demo:交互模式,banner → 输入 instruction → 模型 think(spinner 隐藏)→ analysis/plan + tool blocks → task_complete 标志 → 回到 prompt →
/quit。末尾静止 8 秒。任务选自 #10 long-comment 的 truly-learnable 桶 + 新加的 hello-world 起步例:
hello-worldecho Hello, world! > /app/hello.txtfix-permissionsrecover-obfuscated-filesheterogeneous-dates3.1
terminus-json(与 iter215 RL 训练分布对齐的协议)3.2
openai-tools(camel-ai TerminalToolkit 兼容协议)4. 复现 / 接管 runbook 摘要
完整版见持久路径
/nfs/terminal-rl-workspace/openclaw-repl-demo/README.md以及HansBug/oc-repl/README.md。录像通过 VHS 完成,
scripts/make_oc_tapes.py生成 tape,scripts/render_oc_all.sh批量渲染 + 重置容器。5. 训练协议 vs. 推理协议(FAQ — 已校正)
短答:ckpt215(以及 run-3 / run-4 etc.)的 RL 训练用的是
camel-aiChatAgent+camel.toolkits.TerminalToolkit,sglangqwen25tool-call parser;不是 terminus-2。terminus-2 只在tb run评测时用,不进 RL rollout 路径。oc-repl 0.2.0 新加了--protocol camel-terminal-toolkit来精确复刻这个分布,且已经作为默认。5.1 证据链
挨条对着源码看:
wandb 启动命令里没有
--terminal-agent-typeflag。run msp60ius(产出 iter215 那一次)的完整命令:没有
--terminal-agent-type,也没有任何环境变量改写。generate.py:142默认值是camel_agent:rollout_agent.py:97-106只处理camel_agent一条路径——其他值直接raise ValueError:仓库里根本没有 terminus 这条路。
agent/camel_agent.py是 camel.ChatAgent 的子类:remote/terminal_env.py:163-185把 camel TerminalToolkit 的 4 个工具 schema 喂给 rollout:sglang 用
qwen25parser 把模型的<tool_call>...</tool_call>转回结构化tool_calls:训练 log 实证:
terminal-rl/logs/training_8b_tboverfit.log里<tool_call>出现 628 次,terminus-2 JSON 的 key"task_complete"出现 0 次。模型实际吐的是:5.2 oc-repl 0.2.0:
camel-terminal-toolkit协议新加了一个 protocol,对齐到训练分布字节级别:
camel-ai==0.2.90的FunctionTool.get_openai_tool_schema()抓出来逐字 hardcode,包括["boolean", "null"]union 类型 +"strict": true等训练时模型真的见过的 JSON-schema 细节。terminal-rl/agent/camel_agent.py::get_developer_agent_prompt(system='Linux (in Docker)', machine='x86_64', is_workforce=False, non_think_mode=True)的整段输出原样复制,结尾带/no_think。/no_think这部分是 critical:training-timenon_think_mode=True是默认值(rollout_agent.py:62),模型 RL 训练时根本没生成过<think>块;如果把这个去掉、放任<think>跑,tool-call adherence 会塌掉(亲测:在 recover 任务上让 think 开着,模型生成 1500+ token 的 prose 然后 0 个 tool_call,verify 直接红)。shell_exec全保真;shell_write_content_to_file用 here-doc 100% 保真;shell_view/shell_write_to_process因为 oc-repl sandbox 是 statelessdocker exec(不维护 per-id tmux session),降级为 stub 输出,schema 还在但 session 语义只是「best-effort」。5.3 其他 protocol 在 iter215 上的语义
camel-terminal-toolkit(默认,新增 0.2.0)openai-tools(简化版 1 个shell(command)工具)chmod +x那种);复杂任务偶尔失配terminus-jsonterminus-xml→ 「这个 ckpt 应该用哪个」的答案现在是
camel-terminal-toolkit(默认就是它)。6. 资产清单
📦 打包下载:
oc-repl-demo-v2.zip(8.7 MB) 包含全部 8 个 .tape、16 个 .gif + .mp4、make_oc_tapes.py、render_oc_all.sh以及一个简要的复现 README。github.com/HansBug/oc-repl/pip install -e .)/nfs/terminal-rl-workspace/oc-repl//nfs/terminal-rl-workspace/openclaw-repl-demo/scripts/make_oc_tapes.py/nfs/terminal-rl-workspace/openclaw-repl-demo/scripts/render_oc_all.sh/nfs/terminal-rl-workspace/openclaw-repl-demo/scenarios-oc/*.tape/nfs/terminal-rl-workspace/openclaw-repl-demo/output-oc/oc-*.{gif,mp4}/nfs/terminal-rl-workspace/openclaw-repl-demo/scripts/check_recover.sh之前版本(旧的 6 段 demo + camel_repl.py wrapper):见 #13 的提交历史;那一版的脚本和媒体保留在
scripts/{camel_repl.py,repl-camel,repl-terminus}+output/,仍可作为对照参考。本次的 v2 demo 把所有协议统一在oc-repl里,体验和 Codex 一致。