在 Pi 0.85.1 上局部替换主循环。JevPi 决定每轮先调用 Jev,必要时调用一次 GLM;Pi 提供会话、模型流式接口、工具执行和取消机制。
主循环替换、完整本地追踪和 Pi 评测对照入口已跑通,62 项自动测试通过。Langfuse 已使用真实 Jev + GLM 任务完成上传、服务端读回和逐项核对。动作菜单目前需要显式提供,动态菜单尚未实现。
需要 Node.js 24.13+、npm,以及本机 Bash。
git clone https://github.com/direwolfiy/JevPi.git
cd JevPi
npm ci --ignore-scripts
npm run compile:pi
npm run check
npm run test:core
npm start -- --demo
npm run eval:demo--demo 和 eval:demo 都使用脚本脑与真实 Pi 工具,不调用收费模型。前者演示一轮运行,后者运行两题、两组、两次重复,共 8 次独立执行。演示结果只验证工程接线,不衡量模型质量或经济收益。默认 Node 较旧时请先切换;TypeScript 入口不支持 Node 18。
.npmrc 固定 legacy-peer-deps=true,规避本次安装中 npm 10 解析 Vitest 可选 browser/devtools peer 时的崩溃。直接依赖明确固定版本,锁文件保留依赖树。安装不执行生命周期脚本。
真实调用默认自动读取本项目根目录的 .env,CLI 与评测共用这一规则;--cwd 只改变任务工作目录,不改变配置文件的位置。首次配置可复制 .env.example 为 .env 后填写;已有 .env 时直接使用。配置作为数据解析,不执行 shell;完整配置项见 .env.example。
TYPESAFE_API_KEY=...
GLM_API_KEY=...
JEV_MODEL=jev-latest
SLOW_MODEL=glm-5.3-flash
SLOW_BASE_URL=https://open.bigmodel.cn/api/coding/paas/v4配置模型凭证后,可直接运行仓库中的求和示例:
npm start -- "Add every integer in numbers.txt and write the total to sum.txt." \
--cwd examples \
--actions examples/sum-actions.json--cwd 指定工具的工作目录;--actions 指定 Jev 本轮可选择的动作及完整工具参数。示例会将结果写入 examples/sum.txt。运行其他任务时,换成自己的工作目录和动作菜单。
如需其他配置,CLI 与评测均可重复传入 --env-file。指定后仅加载这些文件,后面的文件覆盖前面的同名项;已有 shell 环境变量始终优先。默认 .env 不存在时跳过,显式指定的文件不存在则报错。
npm start -- "任务" --env-file ./models.env --env-file ./tracing.envCLI 默认 --mode hybrid;--mode slow-only 使用原 Pi 循环,只调用 GLM。两组共享工具、提示词和会话实现。CLI 与评测均调用 src/run.ts 的 runAgent(),预算、追踪和结果保存也共用此入口。
默认最多 32 次决策、运行 180 秒,可用 --max-decisions 和 --timeout-seconds 修改。hybrid 按快脑决策计数,slow-only 按慢模型调用计数。慢模型 HTTP 调用默认超时 45 秒,关闭自动重试。Ctrl+C 传递取消信号。运行超时是协作式取消;Pi 工具继承本机进程权限,工作目录不是沙箱。
每次运行保存到独立 runs/<id>/:
| 文件 | 内容 |
|---|---|
trace.html |
按真实调用顺序查看模型输入、Jev 菜单、输出、思考字段、工具和 HTTP 原文 |
events.jsonl |
完整追踪事件,以调用 ID、HTTP 尝试 ID、工具调用 ID 关联 |
result.json |
状态、消息、调用数量、分模型用量及追踪导出状态 |
sessions/*.jsonl |
Pi 原生会话 |
session.html |
Pi 原生会话 HTML 导出 |
Jev 和 GLM 均记录实际 HTTP 请求正文及收到的响应正文,包括 GLM 原始 SSE。仅保留白名单 HTTP 头;审计 JSONL、结果 JSON、本地 trace 回放和 Langfuse 导出对已知密钥脱敏。Pi 原生会话保留正文。这些是应用层 HTTP 内容,不是网络抓包。取消或断流保留已收到正文,并标注响应不完整。
回放只展示供应商实际返回的思考字段;未返回时不会生成或推断。declared 仅表示模型正常声明结束,评测另外验收产物。
用量来自供应商原始响应,不能用 Pi 本地动作消息的零占位计费。缺失用量保持未知;只有部分调用上报时,不将部分之和冒充整次运行总量。默认没有价格,费用为空;Pi 原生页面的零价格占位不作计费依据。需要估算时可按 .env.example 配置 JEVPI_PRICING_JSON;有缓存用量但缺缓存价格时,不推算对应费用。
两路使用同一份按时间排列的标准 Chat Completions 消息:用户输入是 user,模型回复和工具调用是 assistant,工具返回是 tool。工具调用 ID 与结果配对,供应商返回并用于后续上下文的 reasoning_content 按相同方式保留。
Jev 请求.state = GLM 请求.messages。Jev 接口的字段名仍为 state,其值直接是消息数组;不再重新提取 goal、observation、history。选项继续放在 Jev 的 questions 中,工具定义继续作为 GLM 的工具参数。
复用 Pi 的上下文转换与标准消息序列化,每轮准备一次共享上下文。空 Wake 时慢脑沿用快脑所读的同一份上下文;若 Wake 带有文字,则作为新 assistant 消息入史后给慢脑。该差异来自新增消息。src/core.ts 的控制流不变,两个模型的指令与工具描述不增加限制。
本地接口测试及真实求和联调均验证了空 Wake 时两路消息数组逐项相等。格式依据 TypeSafe state 接口,支持直接传入数组。
使用官方 @langfuse/otel 与 OpenTelemetry SDK,把同一份已脱敏记录导出为运行、真实模型 generation 和工具 observation。Jev 的 OTHER 也是一次模型调用;Pi 合成的工具动作消息不会重复计费。
LANGFUSE_BASE_URL=https://your-langfuse-instance
LANGFUSE_PUBLIC_KEY=...
LANGFUSE_SECRET_KEY=...
LANGFUSE_TRACING_ENVIRONMENT=development将这些变量填入项目根目录的 .env 后,CLI 与真实评测启动时会自动加载并启用上传;CLI 可用 --no-langfuse 关闭上传。服务地址和两项 key 缺失时禁用远端导出,并在需要导出时记录原因;本地追踪继续工作。上传或观察器失败不会改变任务结果。结束前会 flush,CLI 打印 trace ID。追踪环境默认 development,可用 LANGFUSE_TRACING_ENVIRONMENT 修改。
按 Langfuse 官方 skill 和 追踪最佳实践 审计后的结构:
run-agent:任务输入与最终回答;完整运行事件位于 metadata 的run_start/run_result。select-action/generate-response:每次真实模型调用各一个 generation,模型名单独记录,不进入节点名。execute-read/execute-write等:工具与模型调用同属 agent,source_call_id保留来源关联。- 输入按标准消息展示。metadata 的
questions是 Jev 行动菜单与指令,request/response保存完整请求与解析后的响应,transport保存原始 HTTP 请求和响应正文(包括 GLM SSE)。GLM 的工具定义可在云端 input 的tools或完整request中查看。 - 用量保留供应商原始值,并将缓存、推理 token 拆成不重叠计数。未提供价格时应用不填零;Langfuse 若匹配自身模型价格表,其推算费用仍应与实际账单区分。
云端 API 会把 GLM 的输入整理为 {messages, tools},这是 Langfuse 后端的工具规范化。其中 messages 与实际发送的数组完全一致,不改变模型调用协议。
2026-09-19 真实验收:4 次 Jev、2 次 GLM、3 次工具,云端共 10 个节点;sum.txt 精确为 139\n,原文件未改动。读回后逐项核对了消息、菜单、工具定义、6 次模型响应、12 条 HTTP 请求/响应记录、工具参数与结果、层级及 token 总数。两次空 Wake 的 Jev/GLM 消息数组也相等。本轮供应商没有返回非空思考正文;有思考正文时的保留由本地接口测试验证。
运行记录与云端项目凭证保留在各自的本地环境,不随仓库发布。可用上面的求和命令生成自己的回放和云端追踪。
复用固定 Pi 源码中的 packages/evals 表格、汇总、reporter 和附件机制,配合 vitest-evals 0.15.0、Vitest 4.1.9。这是上游仓库内部评测代码的复用,未使用名为 pi-evals 的已发布 npm 包;许可证、来源与文件哈希保存在 vendor/pi-evals/。
# 默认两题、两组、两次重复;完全离线。
npm run eval:demo
# 真实 API 对照:sum-file 一题、每组一次。
npm run eval:live -- --task sum-file --repetitions 1每次执行使用独立临时工作目录。sum-file 检查精确总和与输入未改动,repair-file 在对话外运行 9 个行为用例。判分与模型完成声明分开;结束后保存最终文件快照和原生会话,再清理临时目录。
评测目录中 report.txt 是官方 reporter 的真实输出,runs.jsonl 是配对索引,executions/ 保存各次回放与验收结果。支持 --task、--repetitions、--run-dir、--timeout-seconds、--max-decisions;指定结果目录必须为空,防止追加旧记录污染比较。更多说明见 evals/README.md。
已完成一次真实求和对照,双方产物均通过验收。样本量不足、价格未配置,目前不对模型效果或经济收益作结论。
CLI / eval harness
→ runAgent()
→ Pi AgentSession.prompt()
→ hybrid: 本地 Agent.loopRunner → src/loop.ts → src/core.ts
Jev → Action ──────────┐
→ Wake → GLM 一次 ─┤
↓
Pi 执行一个工具 → 回到 Jev
GLM 没有工具调用 → 结束
→ slow-only: Pi 原 runAgentLoop
JevPi 路径不调用 Pi 原来的 runAgentLoop。streamFunction 保留普通模型流式接口,供行动与手动上下文压缩使用;追踪包装器只观察输入输出,不决定动作。
| 文件 | 职责 |
|---|---|
src/core.ts、src/loop.ts |
快慢脑控制流,Pi 历史、事件、工具、取消适配 |
src/session.ts、src/jev.ts、src/messages.ts |
模型与工具配置、Jev 协议、候选绑定、共用标准消息转换 |
src/run.ts、src/cli.ts、src/env.ts |
共用运行入口、命令行及环境配置加载 |
src/record.ts、src/http-trace.ts |
关联事件、HTTP 正文采集、脱敏 |
src/usage.ts、src/langfuse.ts、src/replay.ts |
原始用量、远端导出、本地回放 |
evals/、vendor/pi-evals/ |
任务、外部验收、官方对照与报告 |
test/ |
离线测试与本地 HTTP 联调,不调用真实收费接口 |
上游业务源码只改两处:agent.ts 增加 loopRunner 并替换 prompt/continue 调用点;agent-loop.ts 导出已有单次模型调用和工具执行函数,函数体不变。固定提交、哈希和补丁见 UPSTREAM.json、patches/pi-core.patch。
Pi 源自 earendil-works/pi,其版权声明与 MIT 许可证分别保留在 vendor/pi-agent-core/LICENSE 和 vendor/pi-evals/LICENSE;评测代码的来源另见 vendor/pi-evals/UPSTREAM.json。
Pi 发布包的 shrinkwrap 会安装私有原版核心,因此依赖接线是显式步骤:compile:pi 编译后运行 scripts/link-core.mjs,把这份依赖链接到本地核心。check 核对实际解析路径,会话工厂再检查 Agent 类与替换入口。重新安装依赖后需重跑 compile:pi。Vitest 对本地核心使用原生外部加载,使其与 Pi SDK 共享同一个 Agent 类。
模型输入未因追踪或评测而修改:Jev 指令仍为 Select the next action.,OTHER 为 Other.;GLM 没有 system prompt。工具描述只说明动作,不加入快慢脑身份、读取策略、验证策略或结束规则。JevPi 路径的多工具响应、空响应、截断和网络失败由代码处理,不当作成功。
目前提供 read、bash、edit、write 四个 Pi 工具。动作菜单仍是显式 JSON,绑定完整工具参数;未指定菜单时只有 LIST_FILES 和 OTHER。CandidateSource 保留为动态原语入口,尚未实现菜单自动生成、排序或学习。
自动压缩、用户扩展、skills、项目上下文发现和完整 TUI 仍未启用。下一阶段扩展 Jev 动态原语;当前评测的两道题是回归起点,不代表开放任务能力。