Skip to content
direwolfiyPublic

About

A Jev-first agent loop on Pi, with a slow LLM fallback, full tracing, and paired evaluations.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

JevPi

在 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.env

CLI 默认 --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

使用官方 @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 动态原语;当前评测的两道题是回归起点,不代表开放任务能力。

About

A Jev-first agent loop on Pi, with a slow LLM fallback, full tracing, and paired evaluations.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages