08 · Adapter、会话与上下文组装¶
一句话结论: Adapter 是 Paperclip 与具体 Agent runtime 之间的完整协议层:不仅启动模型,还声明配置、诊断、会话、技能、事件和 UI/CLI 展示能力;Heartbeat 负责治理与上下文,Adapter 负责把它翻译成目标运行时能执行的形式。
1. 为什么不能只抽象一个 execute(prompt)¶
Claude Code、Codex、Gemini CLI、HTTP bot 的差异远超过请求格式:
- 有的支持结构化 streaming event,有的只有 stdout;
- 有的用 session ID resume,有的需要完整 transcript;
- 有的从固定全局目录读 skills,有的支持额外目录参数;
- 有的能报告 token/模型/工具,有的只能估算;
- 有的在本机运行,有的是云端 job 或 gateway;
- stop 可能是进程组信号、HTTP cancel 或 provider API;
- config form 和输出展示也不同。
所以 Adapter contract 必须覆盖“执行生命周期”,而不仅是模型调用。
2. 三面一体的 adapter package¶
一个完整 adapter 通常有三类出口:
adapter package
├── server/
│ ├─ execute
│ ├─ environment test
│ ├─ session codec
│ └─ skills / model / instructions capabilities
├── ui/
│ ├─ metadata
│ ├─ config fields
│ └─ stdout / transcript parser
└── cli/
└─ terminal event formatter
这让同一 adapter 在:
- Server 中可执行;
- Board UI 中可配置并正确展示运行;
- CLI watch 中可读地输出事件。
某些通用 adapter 的 UI/CLI 实现在主 ui/cli registry 内,外部 adapter 则可以通过插件路径贡献。
3. ServerAdapterModule 能力面¶
从 Server 看,一个 adapter module 大致声明:
| 能力 | 作用 |
|---|---|
| metadata/config schema | 类型、显示信息、必填配置、secret ref |
execute(context) |
启动或调用 Agent runtime |
testEnvironment() |
在正式运行前诊断二进制/凭据/网络 |
| session codec | 解码、编码、清理 provider-specific session state |
| skills sync/materialization | 把选定技能放到运行时可发现的位置 |
| model metadata/profile | 模型列表、能力、成本或路由提示 |
| local JWT support | 是否接受 Paperclip 注入的短期身份 |
| instructions bundle support | 怎样交付 AGENTS/系统说明等文件 |
| runtime feature flags | 结构化事件、工具、workspace 等能力 |
调用方应按 capability 分支,而不是通过 adapter type 字符串猜行为。
4. Registry 把内建与外部实现统一¶
当前 registry 能装载:
- 通用
process、http; claude_local、codex_local;cursor_cloud、cursor_local;gemini_local、grok_local;- Hermes local/gateway;
- OpenClaw gateway;
opencode_local、pi_local;- 插件贡献的 external adapter。
flowchart LR
CFG["agent.adapterType"] --> REG["Server Adapter Registry"]
BUILTIN["built-in modules"] --> REG
PLUGIN["plugin adapter store"] --> REG
REG --> MOD["resolved ServerAdapterModule"]
MOD --> HB["Heartbeat executeRun"]
Registry bootstrap 还会 reconcile metadata,使旧 Agent 配置、disabled adapter 和插件状态在启动时保持一致。
5. Context 的内容来自控制平面¶
Adapter 不应该自己重新查询整套业务。Heartbeat 组装 execution context,典型内容包括:
身份¶
- company/agent/run/issue/project IDs;
- responsible user;
- 短期 Paperclip API token;
- invocation source/reason。
工作¶
- Issue 标题、描述、状态、优先级;
- 父任务、目标祖先和项目背景;
- wake comment/interaction;
- 当前 checkout 和 execution policy。
运行环境¶
- cwd/workspace identity;
- environment/provider reference;
- runtime services;
- allowed file roots;
- stop/timeout callbacks。
能力与约束¶
- materialized skills;
- MCP/tool gateway config;
- secret/env projections;
- trust preset;
- instructions bundle;
- log/progress/event/session callbacks。
Adapter 的职责是把这些字段翻译成 CLI args、env、stdin、HTTP body 或 provider job。
6. Prompt 不是一段字符串,而是分层上下文¶
可把组装顺序理解为:
flowchart TB
SYS["Paperclip runtime protocol"]
ID["Agent identity + org instructions"]
GOAL["Company / goal / project context"]
TASK["Issue + thread + wake reason"]
ENV["Workspace / tools / skills / secrets contract"]
TRUST["Trust boundary + governance constraints"]
SESSION["Adapter session continuation"]
SYS --> OUT["Adapter-ready input"]
ID --> OUT
GOAL --> OUT
TASK --> OUT
ENV --> OUT
TRUST --> OUT
SESSION --> OUT
这比每次把完整数据库 dump 进 Prompt 更可控。部分内容通过文件、env 或 MCP 暴露,不一定全部变成 token。
7. Instructions bundle¶
Agent 可以拥有 instructions path/bundle,包含 AGENTS.md 等运行说明。Server 会:
- 验证路径或数据库保存的 bundle;
- 选择适配目标 runtime 的文件布局;
- 在 workspace/scratch 中安全 materialize;
- 避免路径逃逸或覆盖不允许的文件;
- 把可见位置传给 adapter。
这样组织角色和操作协议不必硬编码在 adapter 中。
8. Skills 注入因运行时而异¶
共同逻辑是:运行前解析 selected company skills,创建受控快照;具体注入由 adapter 负责。
| Adapter 类型 | 可能的注入方式 |
|---|---|
| Claude local | 临时目录/符号链接并通过额外目录参数暴露 |
| Codex local | 对接其 skills 目录与选择规则 |
| 其他 CLI | materialized runtime skills + runtime-specific config |
| 不支持 skills | capability 明确为不可用,不能静默假装成功 |
Skill 的 frontmatter name + description 先作为路由索引,正文按需加载,降低初始上下文。
9. Session:跨 Run 的 Provider 连续性¶
sequenceDiagram
participant H as Heartbeat
participant S as agent_task_sessions
participant C as Session Codec
participant A as Adapter
H->>S: load(company, agent, adapter, taskKey)
S-->>H: encoded provider state
H->>C: decode + validate workspace compatibility
C-->>H: resume input
H->>A: execute(resume input)
A-->>H: result + new session state
H->>C: encode / sanitize
H->>S: upsert latest state
Session codec 的存在避免 Heartbeat 知道每家 provider 的内部字段。
9.1 Session 与 cwd 的关系¶
本地 coding agent 的会话可能隐含 cwd/repository。如果新的 execution workspace 不兼容,盲目 resume 可能让 Agent 引用旧文件或错误分支。因此 Server/adapter 会记录 session workspace context,并在复用前校验。
9.2 Reset session¶
UI/CLI/API 可以显式 reset Agent session。Reset 不删除历史 run,只清理下一轮的 continuation state,这是排查“上下文污染”的重要运维动作。
10. 结构化事件质量有层级¶
不同执行引擎提供的观测质量不同:
结构化程度越高,UI 越能可靠显示:当前工具、assistant snippet、token usage、tool arguments/result、stop reason。低层 adapter 只能提供 best-effort parser,不应把解析失败等同运行失败。
Adapter event 最终被规范化后进入:
- heartbeat run events;
- run log store;
- live WebSocket;
- UI transcript parser;
- CLI formatter。
11. Process metadata 为什么要尽早上报¶
本地 adapter 一启动子进程,就通过 callback 保存:
- PID;
- process group ID;
- command/runtime identity;
- provider job/session reference;
- start time。
这使 stop、timeout、hot restart adoption 和 orphan reaping 有证据。等进程结束才记录 PID 没有恢复价值。
12. Stop 与取消¶
取消路径依据 adapter/runtime:
- local process:优先对进程组发送温和信号,再有界升级;
- provider job:调用取消 API;
- HTTP/gateway:发送协议级 interrupt;
- 无原生取消:标记 control-plane cancellation,并防晚到结果覆盖终态。
无论底层能否立即停,Run 的状态写入仍用 CAS,晚到 callback 不能复活 terminal run。
13. 用量与成本归一化¶
Adapter result 可以报告:
- input/output/cache tokens;
- model/provider/biller;
- provider cost;
- subscription/local execution 等非 token 账务信息。
Server 把它们归一成 run usage 和 cost events,并连接 company/agent/issue/project/goal。Adapter 不直接修改预算;预算服务消费规范化成本事实。
14. 本地与远程 Git 的边界¶
Paperclip 明确避免让 adapter 假设远程环境能直接操作本地 Git remote:
- local execution workspace 是持久化边界;
- SSH 可用 Git bundle/import/export;
- sandbox 可用 archive upload/download;
- provider 插件可以定义自己的同步协议;
- 核心执行路径不应擅自
git push。
这是安全与可移植性共同驱动的决定:远程环境可能没有用户凭据,也不应默认拥有发布权限。
15. 新增 Adapter 的真实工作量¶
不仅是实现 execute:
- shared adapter type/metadata;
- Server module 和 config validation;
- environment test;
- session codec;
- event/usage/process callbacks;
- stop/cancel;
- skills/instructions/workspace capabilities;
- UI config fields 与 transcript parser;
- CLI formatter;
- registry bootstrap;
- secret refs 和 redaction;
- integration tests、packaging、docs。
外部 adapter package 可以沿插件路径接入,但仍要满足相同的 Server contract。
16. 设计边界与风险¶
运行时能力不齐¶
统一 contract 无法让所有 provider 瞬间同质化。调用方必须按 capability 降级,UI 也要诚实展示缺失事件/usage/session。
Parser 是信任边界¶
UI parser 处理 adapter 输出。仓库使用 sandboxed parser worker 等机制降低 parser 卡死/污染主 UI 的风险,但 external parser/同源插件仍需信任评估。
Session 可能隐藏状态¶
Provider session 是便捷连续性,也是难以完全审计的外部状态。Paperclip 通过 task key、workspace compatibility、reset 和 context snapshot 尽量约束它。
17. 可复用经验¶
- Agent runtime SPI 应覆盖执行、诊断、会话、技能、事件和取消。
- 用 capability 描述差异,不要让调用方通过 type 名猜特性。
- 控制面组装受治理上下文,Adapter 只做 runtime translation。
- Provider session 要有 codec、task key、workspace 兼容检查和 reset。
- Process identity 越早持久化,恢复越可靠。
- 成本由 Adapter 报告、Server 归一、预算服务执行,职责要分开。
源码入口¶
packages/adapter-utils/src/types.ts及 package exportsserver/src/adapters/registry.ts、services/adapter-registry-bootstrap.tspackages/adapters/*/src/server/packages/adapters/*/src/ui/ui/src/adapters/registry.tscli/src/adapters/registry.tspackages/db/src/schema/agent_task_sessions.tsdocs/adapters/creating-an-adapter.md
Adapter 要在一个真实执行位置工作。下一章:09 · Workspace、Environment 与隔离。