@cluski/pi-by-the-way
v0.1.0
Published
A /btw (by-the-way) side-question extension for pi, ported from kimi-code's btw feature
Downloads
262
Readme
pi-by-the-way
为 pi 开发的 /btw(by the way) 侧问扩展,移植自 kimi-code 的 btw 功能(packages/agent-core-v2/src/session/btw/)。
/btw 会打开一个侧信道:当前对话的一个轻量 fork,继承完整上下文但禁用所有工具调用。这样你就能在主 agent 不受影响、继续干活的同时,随口问一句"对了,这段为什么这么写?"。后续追问会在同一条侧信道里继续;关闭面板后状态保留,下次 /btw 还能接着用。
╭─ 💬 by the way — side channel, tools disabled ─────────────────╮
│ Q: 这段代码为什么用 reduce 而不是 for 循环? │
│ │
│ 这里的 reduce 是为了把 map+filter 两步合成一次遍历,避免中间 │
│ 数组。如果后续要加 break 语义,再换成 for-of 也可以… │
│ … │
│ ❯ _ │
│ Enter 发送 · Esc 关闭 · ↑/↓ 滚动 · /btw reset 重新 fork │
╰─────────────────────────────────────────────────────────────────╯安装
这是一个 npm pi 包(package.json 里带 pi manifest 和 pi-package 关键字)。有三种用法:
1) 本地开发 / 试跑(不发布) —— 直接用本地路径加载:
pi -e . # 临时加载(本次运行有效,不写入设置)
pi install . # 安装到用户设置(~/.pi/agent/settings.json)
pi install -l . # 安装到项目设置(.pi/settings.json,可随仓库共享给团队)2) 发布到 npm 后安装:
npm publish --access public # 先登录拥有 @cluski scope 的 npm 账号
pi install npm:@cluski/pi-by-the-way # 别人/别的项目这样装3) 从 git 安装(推到 GitHub 后):
pi install git:github.com/<user>/[email protected]包里的 5 个
@earendil-works/*+typebox是 peerDependencies(*),不打包进 tarball —— pi 运行时自带这些核心包,版本自动对齐。
用法
| 命令 | 行为 |
| ------------- | ------------------------------------------------------------------------------------------- |
| /btw <问题> | 重新 fork 一份快照并提问(与 kimi-code 一致:每次 /btw <q> 都启动一个新的侧 agent)。 |
| /btw | 直接打开面板:若已有侧信道对话则继续,否则打开一个空面板,在面板内输入问题。 |
| /btw reset | 丢弃快照和对话记录,下次 /btw 从当前主对话重新 fork。 |
面板内操作:
- Enter —— 发送追问
- Esc(流式输出中)→ 取消当前这轮;Esc(空闲时)→ 关闭面板
- ↑ / ↓ / PgUp / PgDn —— 滚动对话记录
从 kimi-code 到 pi 的映射
kimi-code 有进程内的 agent 运行时,提供 fork + 权限策略服务。pi 没有把这些暴露给扩展,但扩展 API 提供了等价的积木:
| kimi-code | 本扩展 |
| ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| IAgentLifecycleService.fork('main') 复制 profile + 全量消息历史 | ctx.sessionManager.getBranch() → convertToLlm() 生成一个定格的 Message[] 快照;model = ctx.model,thinking = pi.getThinkingLevel() |
| 给子 agent 追加 SIDE_QUESTION_SYSTEM_REMINDER | 追加到 ctx.getSystemPrompt() 末尾,从而保持 provider 的 prompt-cache 前缀 |
| DenyAllPermissionPolicyService(工具可见,但每次调用都拒绝) | 工具定义照发(前缀相同、缓存命中);每个 toolUse 响应回灌一个 TOOL_CALL_DISABLED_MESSAGE 的 toolResult,然后重试(由 MAX_TOOL_REJECTION_ROUNDS 限制次数) |
| 子 agent_id + prompt 路由(追问复用同一个子 agent) | 内存里的 state.messages 在面板存活期内随追问累积 |
| BtwPanelController + 按 agentId 路由 assistant.delta 事件 | BtwPanelComponent overlay,直接消费 pi-ai 的 AssistantMessageEventStream(text_delta / thinking_delta) |
| session.cancel() | 每轮一个独立的 AbortController |
LLM 调用本身用的是 @earendil-works/pi-ai/compat 的 streamSimple(),鉴权通过 ctx.modelRegistry.getApiKeyAndHeaders(ctx.model) 解析 —— 与 pi 官方 handoff.ts 示例同一套模式。
两个值得说明的设计决策
上下文快照是定格的。 和 kimi-code 的 fork 一样,侧信道只在(首次
/btw <q>时)抓取一次分支;之后主 agent 的新对话不会流入侧信道。/btw reset重新抓取;/btw(无参)则重新打开已有的对话记录。工具照发但拒绝调用(kimi 的"方案 B")。 发送真实工具定义能让请求前缀与主 agent 逐字节一致,从而命中 Anthropic 等 provider 的 prompt cache。如果模型仍然发起工具调用,我们就回一条 disabled-message 的
toolResult,让它改用文本回答 —— 完全复刻 kimi-code 的行为。更简单的做法(完全不传工具)也能跑,但会损失这层缓存命中率。
项目结构
pi-by-the-way/
├── package.json npm 包清单(name/version/keywords=pi-package/pi.extensions manifest/peerDependencies)
├── extensions/
│ └── btw/
│ ├── index.ts 扩展工厂、/btw 命令、侧信道引擎
│ ├── context.ts 会话分支 → pi-ai Message[] 快照(处理 compaction)
│ └── panel.ts overlay 面板组件:对话记录 + markdown + 输入框 + 滚动
├── tsconfig.json
└── README.md
pi.extensions指向./extensions/btw/index.ts这个文件(而不是目录),加载零歧义;context.ts/panel.ts由index.ts通过相对 import 引入,不会被当成独立扩展加载。
类型检查
npm install # dev 依赖:typescript;pi 核心包通过软链提供类型
npm run typecheck注意:
node_modules/@earendil-works/*和node_modules/typebox是指向全局安装的pi-coding-agent的软链,用来在本地对齐运行时类型(因为它们是 peerDependencies,npm install不会自动装)。如果npm install把软链 prune 掉了,重新执行一遍ln -sfn即可。
注意事项
- 仅支持交互式(TUI)模式 —— 在
rpc/json/print模式下/btw只会通知并直接返回。 - 侧信道对话是易失的(内存中),和 kimi-code 一样;不会写入 session 文件。
/reload和切换会话都会清空它。
