Headroom TypeScript SDK 全解:通过代理压缩 LLM 上下文,无缝接入 Vercel AI、OpenAI 与 Anthropic SDK
【免费下载链接】headroomCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.项目地址: https://gitcode.com/GitHub_Trending/head/headroom
Headroom 的 TypeScript SDK(npm 包headroom-ai)让任意 JavaScript/TypeScript 应用能够在消息发送给 LLM 之前完成上下文压缩:省 token、降成本、把更多上下文塞进每次请求。本文基于仓库中的 TypeScript SDK 文档、SDK 源码 与 代理端点实现,完整讲解compress()核心 API、可复用客户端、三个框架适配器、错误与回退机制,以及多轮对话下的缓存安全注意事项。
架构定位:SDK 是一个纯 HTTP 客户端
理解 TypeScript SDK 的第一步是认清它的边界:压缩逻辑不在 Node.js 里运行。当你调用compress()时,SDK 把消息 POST 到 Headroom 代理的/v1/compress端点,代理在内部执行完整的压缩管线(ContentRouter 及各压缩器,包括 SmartCrusher),再把压缩后的消息返回。
Your TypeScript App │ │ compress(messages) ▼ headroom-ai (npm) ← HTTP client │ │ POST /v1/compress ▼ Headroom Proxy (loopback) ← compression pipeline (Python) │ │ compressed messages ▼ Your TypeScript App │ │ openai.chat.completions.create(compressed) ▼ LLM Provider这条数据流在源码中有直接对应:
- SDK 入口 compress():自动检测输入格式(OpenAI / Anthropic / Vercel AI / Gemini),统一转成 OpenAI 格式,经 HeadroomClient 发起
POST /v1/compress,完成后转回原格式。 - 代理路由注册:
/v1/compress默认挂载Depends(_require_loopback)依赖——默认仅回环地址(loopback)可访问。非回环调用方会收到404(而不是 403,路由对扫描器保持不可见)。若你要让同一内网里的 sidecar/网关(如 Kong、LiteLLM)访问该端点,需要启动代理时设置HEADROOM_COMPRESS_ALLOW_REMOTE=1,该开关只解除这一条路由(连同/v1/usage)的回环限制,其余回环路由不受影响;HEADROOM_PROXY_TOKEN入站鉴权仍然生效。
/v1/compress是一个"仅压缩"端点:它从不向 LLM 提供商发起补全请求,因此不需要提供商 API key;但它会运行本地 ML 模型(Kompress 编码器做 token 保留度打分、Magika 做内容类型分类),这是 代理文档 明确说明的行为。
端点请求/响应契约
TypeScript SDK 封装了如下请求体(字段说明来自 proxy 文档,SDK 侧的构造逻辑见 client.ts 的 _doCompress):
{ "messages": [ ... ], // OpenAI 或 Anthropic 两种线格式均可 "model": "gpt-4o", // 选择 tokenizer 与上下文上限(可带网关前缀,如 bedrock/anthropic.claude-3-5-sonnet) "token_budget": 8000, // 可选:覆盖上下文上限(对应 SDK 的 tokenBudget 参数) "config": { // 可选 "mode": "lossy_inline", // ccr | lossy_inline | lossless_then_lossy "frozen_message_count": 12, // 固定已缓存的头部前缀 "compress_user_messages": false, "target_ratio": 0.5, "protect_recent": 2, "protect_analysis_context": true } }响应字段:
{ "messages": [ ... ], // 压缩后的消息 "tokens_before": 15000, "tokens_after": 3500, "tokens_saved": 11500, "compression_ratio": 0.23, // tokens_after / tokens_before,越低越好 "transforms_applied": ["router:smart_crusher:0.35"], "transforms_summary": {"router:smart_crusher:0.35": 1}, "ccr_hashes": [] // 仅 mode="ccr" 时非空 }从源码看,SDK 的CompressResult与代理响应的对应关系是 camelCase 一一映射(tokensBefore/tokensAfter/tokensSaved/compressionRatio/transformsApplied/ccrHashes),并在成功路径上把compressed置为true;回退路径则返回compressed: false。
两个容易踩坑的契约细节(proxy 文档 原文强调):
- 不做格式转换:
messages传什么形状就返回什么形状。OpenAI 形状(role: "tool"+tool_call_id)或 Anthropic 形状(tool_use/tool_result内容块)都可以,但混用会出问题。 system与tools被忽略:Anthropic 会把二者放在带外传输,该端点接收但不压缩、不返回——需要自行保留。若需要 system prompt 压缩或 tool-schema 压缩,应把 Headroom 当作完整代理(passthrough 模式)运行,而不是仅调用/v1/compress。
端点还有两个运维特性:Fail-open——压缩超时时返回 200 并附compression_skipped: true、skip_reason: "compression_timeout",原始消息原样返回;x-headroom-bypass: true请求头可跳过压缩。错误响应为 400(字段缺失/非法)、401(HEADROOM_PROXY_TOKEN校验失败)、404(非回环且未开启HEADROOM_COMPRESS_ALLOW_REMOTE)、503(压缩失败)。
安装与运行前提
npm install headroom-ai前提是一个运行中的 Headroom 代理(Python 侧headroom proxy)。从 package.json 可以确认:
- 运行时要求 Node.js
>= 18(engines字段); - 包名
headroom-ai,当前仓库版本 0.37.0,Apache-2.0 许可; - 零运行时依赖:Vercel AI、OpenAI、Anthropic SDK 全部是
peerDependencies且标记optional: true——用哪个就装哪个,不用就不装; - 子路径导出有四个:
headroom-ai/vercel-ai、headroom-ai/openai、headroom-ai/anthropic,此外源码中还有 Gemini 适配器 并暴露为headroom-ai/gemini(这一点在 wiki 文档中未展开,以 package.json exports 与适配器源码为准)。
SDK 支持 CJS 与 ESM 双格式输出(main/module分别指向dist/index.cjs与dist/index.js),构建工具为 tsup,测试框架为 vitest(见 vitest 配置)。
快速上手:compress()
import { compress } from 'headroom-ai'; const result = await compress(messages, { model: 'gpt-4o' }); console.log(`Saved ${result.tokensSaved} tokens`); const response = await openai.chat.completions.create({ model: 'gpt-4o', messages: result.messages, });完整参数与默认值(默认值已与 client.ts 中的常量 核对):
import { compress } from 'headroom-ai'; const result = await compress(messages, { model: 'gpt-4o', // 模型名(用于 token 计数) baseUrl: 'http://localhost:8787', // 代理地址(默认值) apiKey: 'your-api-key', // 可选,用于启用鉴权的端点 timeout: 30000, // 毫秒(默认 30_000) fallback: true, // 代理不可达时返回未压缩消息(默认 true) retries: 1, // 瞬时错误重试次数(默认 1,即最多请求 2 次) }); result.messages // 压缩后的消息(与输入同格式) result.tokensBefore // 原始 token 数 result.tokensAfter // 压缩后 token 数 result.tokensSaved // 节省的 token 数 result.compressionRatio // tokensAfter / tokensBefore result.transformsApplied // 例如 ['router:smart_crusher:0.35'] result.compressed // 回退触发时为 false消息使用标准 OpenAI chat 格式:{ role, content, tool_calls?, tool_call_id? }。类型定义见 types.ts 中的 OpenAIMessage 联合类型,覆盖system/user/assistant(可带tool_calls)/tool(必带tool_call_id)四种角色,user 消息的content还可为text+image_url内容块数组。
除了 wiki 文档列出的六项,从 CompressOptions 类型 看还有三个可选参数:
tokenBudget:压缩到不超过该 token 预算(用于会话压缩/compaction 场景),会写入请求体token_budget;hooks:压缩前后钩子(preCompress/computeBiases/postCompress),可注入逐消息压缩偏置;stack:集成来源标识,会以X-Headroom-Stack请求头发送(如"adapter_ts_openai"),便于代理侧区分流量来源。
环境变量
不传 options 时可改用环境变量(client.ts 构造逻辑 的解析顺序:显式 options → 环境变量 → 默认值):
HEADROOM_BASE_URL— 代理地址,默认http://localhost:8787;HEADROOM_API_KEY— 鉴权端点的可选 API key,会以Authorization: Bearer <key>发送。
可复用客户端 HeadroomClient
对高频调用场景,创建一个客户端实例复用其连接配置与超时设置:
import { HeadroomClient } from 'headroom-ai'; const client = new HeadroomClient({ baseUrl: 'http://localhost:8787', apiKey: 'your-api-key', }); const r1 = await client.compress(messages1, { model: 'gpt-4o' }); const r2 = await client.compress(messages2, { model: 'gpt-4o' });compress()每次调用都会新建一个临时HeadroomClient(见 compress.ts 第 59 行),因此多调用场景复用实例可以省去重复的环境解析,也可通过client选项把已有实例注入compress()。
从源码看,HeadroomClient远不止一个压缩客户端,它同时是代理运维 API 的 TypeScript 门面:
- 透传调用:
client.chat.completions.create()(走POST /v1/chat/completions)与client.messages.create()(走POST /v1/messages,Anthropic 风格),支持流式(stream: true时返回 SSE 解析器),并支持headroomMode(audit/optimize/simulate)等x-headroom-mode控制头; - 观测端点:
health()、proxyStats()、prometheusMetrics()、statsHistory()、memoryUsage(); - CCR 取回:
retrieve(hash)从压缩缓存中取回被 CCR 模式移出上下文的原始内容(POST /v1/retrieve),以及getCCRStats()、handleToolCall()(处理 LLM 发出的headroom_retrieve工具调用); - 遥测/反馈/TOIN:
telemetry.*、feedback.getHints(toolName)、toin.getPatterns()等统计接口; - simulate():
client.chat.completions.simulate({ model, messages })以default_mode: "simulate"调用/v1/compress并请求生成 diff 工件,用于"不调 LLM 先看看压缩结果"的演练。
框架适配器
Vercel AI SDK
headroomMiddleware 直接对接 Vercel AI SDK 的wrapLanguageModel():
import { headroomMiddleware } from 'headroom-ai/vercel-ai'; import { wrapLanguageModel, generateText } from 'ai'; import { openai } from '@ai-sdk/openai'; const model = wrapLanguageModel({ model: openai('gpt-4o'), middleware: headroomMiddleware(), }); // 经过该模型的所有调用自动压缩 const { text } = await generateText({ model, messages });从 适配器源码 看,中间件实现的是transformParams钩子:取出 Vercel 内部prompt→vercelToOpenAI()转成 OpenAI 格式 → 调compress()(自动带stack: "adapter_ts_vercel_ai"标识)→ 仅在result.compressed为真时把openAIToVercel(result.messages)写回prompt;回退时原样返回params,业务代码零改动。
也可以绕过中间件直接压缩 Vercel 消息:
import { compressVercelMessages } from 'headroom-ai/vercel-ai'; const result = await compressVercelMessages(modelMessages, { model: 'gpt-4o' }); // result.messages 保持 Vercel ModelMessage[] 格式OpenAI SDK
用withHeadroom()包裹 OpenAI 客户端,每次chat.completions.create()自动压缩:
import { withHeadroom } from 'headroom-ai/openai'; import OpenAI from 'openai'; const client = withHeadroom(new OpenAI()); // 消息在发送前被压缩——对业务代码透明 const response = await client.chat.completions.create({ model: 'gpt-4o', messages: longConversation, });OpenAI 适配器 的实现是三层Proxy对象(client → chat → completions),仅劫持create方法:取出params.messages调compress()(stack: "adapter_ts_openai"),再用压缩结果替换messages后调用原方法。其余方法(embeddings、images、audio 等)全部原样透传。
Anthropic SDK
同样的包裹模式:
import { withHeadroom } from 'headroom-ai/anthropic'; import Anthropic from '@anthropic-ai/sdk'; const client = withHeadroom(new Anthropic()); const response = await client.messages.create({ model: 'claude-sonnet-4-5-20250929', messages: longConversation, max_tokens: 1024, });仅messages.create()被拦截,适配器负责在 Anthropic 内容块格式与 OpenAI 格式之间自动转换。
更多示例
仓库的 examples 目录 提供了 12 个可直接参考的示例脚本,包括基本压缩(basic-compress.ts)、CCR 取回(ccr-retrieve.ts)、多提供者(multi-provider.ts)、OpenAI/Anthropic 适配器(openai-anthropic-adapters.ts)、Vercel 中间件(with-headroom-vercel.ts)、流式对话(streaming-chat.ts)、工具调用 Agent(tool-calling-agent.ts)、共享上下文多 Agent(shared-context-multi-agent.ts)以及模拟演练(simulation-dry-run.ts)等。
错误处理与回退行为
SDK 的错误层次与 Python 侧的headroom.exceptions对齐,定义见 errors.ts:
import { compress, HeadroomConnectionError, HeadroomAuthError } from 'headroom-ai'; try { const result = await compress(messages, { model: 'gpt-4o', fallback: false }); } catch (error) { if (error instanceof HeadroomAuthError) { // API key 无效(401) } else if (error instanceof HeadroomConnectionError) { // 代理不可达 } }除HeadroomAuthError、HeadroomConnectionError外,还有携带statusCode与errorType的HeadroomCompressError,以及一组按代理错误类型映射的子类:ConfigurationError、ProviderError、StorageError、TokenizationError、CacheError、ValidationError、TransformError。映射逻辑在 mapProxyError:401 一律映射为HeadroomAuthError,其余按代理返回的error.type字符串查表,查不到则兜底为HeadroomCompressError。
回退矩阵
默认fallback: true时,compress()永远不会阻塞应用。行为矩阵(与 client.ts 的重试循环 一致):
| 场景 | fallback: true(默认) | fallback: false |
|---|---|---|
| 代理不可达 | 返回未压缩消息,compressed: false | 抛出HeadroomConnectionError |
| 代理 503 | 重试后返回未压缩消息 | 抛出HeadroomCompressError |
| API key 无效(401) | 抛出HeadroomAuthError | 抛出HeadroomAuthError |
| 请求非法(400) | 抛出HeadroomCompressError | 抛出HeadroomCompressError |
源码里的重试语义值得注意:maxAttempts = 1 + retries,即默认retries: 1表示最多尝试 2 次;循环中401(HeadroomAuthError)和所有 4xx(statusCode < 500的HeadroomCompressError)立即抛出、不重试——只有连接错误和 5xx 才消耗重试次数。回退结果由 makeFallbackResult 构造:原消息原样返回,tokensBefore/After/Saved归零,compressionRatio为 1.0,compressed: false。
多轮调用:别把前缀缓存打爆
/v1/compress是无状态端点:它不像代理自身的请求路径那样运行 CacheAligner 并跨轮跟踪提供商缓存命中。由于提供商缓存的是你转发出去的字节(已被压缩修改过),你的原始消息与缓存前缀已不再相同,而且压缩强度随消息位置变化(旧的工具结果可能随对话变长而滑出"近期读取保护窗口",被压得更狠),因此"重新压缩原始消息"不能保证复现上一轮的输出。代理文档 给出两条规则:
- 传
config.frozen_message_count= 上游已缓存的头部消息数量; - 回传上一轮转发出去的消息,而不是原始消息。
frozen_message_count会把头部消息按传入内容原样返回,喂原始消息等于给提供商喂了与上轮不同的字节,缓存照样失效。
forwarded = [] def next_turn(new_messages): r = requests.post( f"{proxy}/v1/compress", json={ "messages": forwarded + new_messages, "model": "claude-sonnet-4-6", "config": {"frozen_message_count": len(forwarded)}, }, ).json() forwarded[:] = r["messages"] # 下一轮的冻结前缀 return forwarded在 TypeScript 侧,config对象可以经 ExtendedClientOptions.config(HeadroomConfig类型,会deepSnakeCase后写入请求体)传入,frozen_message_count等字段即通过该通道下发。
与 Python SDK 的对比
| 特性 | Python SDK | TypeScript SDK |
|---|---|---|
compress() | 原生(本地运行) | HTTP 客户端(调用代理) |
| 代理 | 内置服务器 | 连接已有代理 |
| Vercel AI SDK | N/A | 中间件适配器 |
| OpenAI SDK | HeadroomClient封装 | withHeadroom()封装 |
| Anthropic SDK | HeadroomClient封装 | withHeadroom()封装 |
| LangChain | HeadroomChatModel | 直接调用compress() |
| 记忆系统 | 完整(SQLite + HNSW) | 暂无(走代理) |
| MCP 服务器 | 内置 | 暂无 |
| CLI 工具 | headroom proxy、headroom wrap等 | N/A(使用 Python CLI) |
OpenClaw 插件:SDK 的生产级用法
headroom-ai同时驱动 headroom-openclaw 插件。该插件在assemble()生命周期钩子中调用HeadroomClient压缩 OpenClaw Agent 的上下文。推荐安装方式是headroom wrap openclaw;直接安装插件的命令为openclaw plugins install --dangerously-force-unsafe-install headroom-ai/openclaw。插件源码见仓库 plugins/openclaw 目录。
小结
TypeScript SDK 的设计取舍非常清晰:Node 侧只保留一个零依赖的 HTTP 客户端、格式转换层和框架适配器,所有压缩智能留在代理侧。落地时的关键检查清单是——代理已在本机 8787 端口运行;跨主机部署时配置HEADROOM_COMPRESS_ALLOW_REMOTE=1并保留HEADROOM_PROXY_TOKEN;生产代码依赖fallback: true的静默降级(用result.compressed判断是否真正压缩);多轮会话按frozen_message_count+ "回传已转发消息"两条规则保护前缀缓存。想进一步验证行为,仓库提供了完整的单元测试(client.test.ts、compress.test.ts、errors.test.ts 及四个适配器的测试),以及 12 个可运行的集成示例。
【免费下载链接】headroomCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.项目地址: https://gitcode.com/GitHub_Trending/head/headroom
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考