Docs

快速上手

sift 以 npm 包 @agent-context/sift 提供 Node.js API,核心为纯 Rust(napi-rs 绑定)。安装时自动命中当前平台的二进制子包。适合"上下文里塞了大量机器产出"的场景——这些内容 token 多、冗余高,但真正对任务有用的信息密度低。

安装

npm install @agent-context/sift

直接接入 Coding Agent

sift-plugins 已为 Codex、Pi、OpenCode、Claude Code 和 DeepSeek Harness 提供现成适配器。无需自己编写 hook:适配器会自动压缩新产生的工具输出,并注册 sift_retrieve,让 Agent 在需要时取回 stash 原文。

Codex CLI / App

当前预览版要求 Codex CLI ≥ 0.145.0 与本机 Node.js ≥ 18。CLI 和桌面 App 共用本地主机上的插件、hook 与 MCP 配置:

codex plugin marketplace add agents-sdk/sift-plugins
codex plugin add codex-sift-plugin@agent-context

Pi

pi install npm:@agent-context/pi-sift

OpenCode

要求 OpenCode ≥ 1.18.26 且 < 2。推荐使用 CLI 安装,它会同时注册压缩服务与 TUI token 统计入口:

opencode plugin @agent-context/opencode-sift

Claude Code

@agent-context/claude-code-sift 要求 Claude Code ≥ 2.1 且本机 Node.js ≥ 18。在 Claude Code 中依次执行:

/plugin marketplace add agents-sdk/sift-plugins
/plugin install claude-code-sift@agent-context

插件安装后默认启用,通过 PostToolUse hook 压缩工具输出,并由内置 MCP server 提供 sift_retrieve。

DeepSeek Harness

要求 Node.js ^22.19 或 ≥ 24.2。把插件安装到需要启用的 dsh profile,然后启动对应宿主:

dsh plugin --profile web add @agent-context/dsh-sift
dsh web

完整安装、配置、stash 存储与排障说明见 agents-sdk/sift-plugins。

最小示例

import { createSift, siftRequest, siftText, retrieve, retrieveLines } from "@agent-context/sift";

// 1. 压缩请求体:自动检测 Anthropic /v1/messages、
//    OpenAI Chat Completions、OpenAI Responses 三种格式
const { body, changed, tokensSaved } = siftRequest(requestBody, "用户当前的问题");

// 2. 或压缩源码;折叠点直接指向落盘 stash 文件
const r = siftText(fileContent, "error mismatched");
// // ... 30 lines omitted from file "/home/agent/.sift/stash/HASH", starting at line 32

if (r.lossy) {
  // 有损:原文已入 stash store,输出尾部带 «stash:HASH» 标记
  const original = retrieve(r.stashKey!);
  // 若输出提示给出省略行范围,也可以只取回所需分片
  const fragment = retrieveLines(r.stashKey!, 120, 80);
}

指定 stash 目录

直接导入的 siftRequest、siftText、retrieve 和 retrieveLines 使用共享的默认 store:优先读取 SIFT_STASH_DIR,其次是 ~/.sift/stash,最后才回退到系统临时目录。如果应用需要隔离租户、任务或测试数据,用 createSift 创建绑定到指定目录的实例:

import { createSift } from "@agent-context/sift";

const sift = createSift({
  stashDir: "/var/lib/my-app/sift-stash",
});

const result = sift.siftText(toolOutput, "error mismatched");
const original = result.stashKey
  ? sift.retrieve(result.stashKey)
  : null;

stashDir 必须是非空字符串;相对路径按调用 createSift 时的工作目录解析。每次调用都会创建独立实例,所以同一 Node.js 进程可以同时使用多个 stash 目录。压缩和恢复要使用同一个实例,顶层 retrieve 不会读取实例的独立目录。

典型场景

Agent 的工具输出

编码 Agent 每轮都会往上下文里塞构建日志、grep 结果、git diff。几轮之后,工具输出占了绝大部分 token,而且旧轮次的输出早就没用了。

for (const step of agentSteps) {
  const out = await runTool(step);
  // 送进模型前先压缩,query 用当前任务描述
  const r = siftText(out, step.intent);
  messages.push({ role: "tool", content: r.text });
  if (r.lossy) keepForRecovery(r.stashKey);
}

要点:query(当前意图)帮助相关性筛选的压缩器保留关键行;纯文本也会把 query 纳入 BM25 相关性评分。

长对话的历史消息

对话越长,每轮的输入成本越高。在发送请求前对整个 body 跑一遍 compress,早期消息里的日志、JSON、diff 会被压缩,而最近的轮次与冻结前缀保持原样。

// 发送前一步,自动检测 Anthropic / OpenAI 格式
const { body, tokensSaved, frozenMessages } = siftRequest(requestBody, userQuestion);
await fetch("/v1/messages", { method: "POST", body: JSON.stringify(body) });

要点:cache_control 以下的消息是缓存锚点,sift 一个字节都不动,不会破坏你的 prompt cache 命中。

把大文件喂给 LLM

分析线上问题、读监控数据时,原始文件往往几十 KB 起步。先 siftText 再送入:

API 一览

createSift({ stashDir })

创建绑定到独立 stash 目录的 API 实例。实例提供 siftRequest、siftText、retrieve、retrieveLines、detectContentType 和 detectRequestFormat;不影响直接导入的顶层 API 及其默认目录逻辑。

siftRequest(body, query?)

压缩请求 body(就地透传或压缩),返回:

字段说明
body压缩后的请求 body(格式与输入一致)
changed是否发生了实际压缩
blocksExamined / blocksCompressed / blocksReverted检查 / 压缩 / 因 token 校验回退的 text block 数
frozenMessages冻结前缀消息条数(cache 锚点,未被触碰;OpenAI 格式恒为 0)
stashStored写入 stash store 的原文条数
tokensSaved估算节省的 token 数

siftText(text, query?, sourcePath?)

压缩单个字符串(把工具输出原文送进任意 API 之前),返回 text / changed / lossy / stashKey / tokensSaved。使用落盘 stash 时,源码、搜索结果、日志以及显式保守模式的整行纯文本可在省略位置输出 [... 30 lines omitted from file "/home/agent/.sift/stash/HASH", starting at line 32],代码使用注释形式。文件是完整原文,起始行从 1 计数,不是搜索命中源码的行号。默认纯文本按句子抽取,不伪造行范围,通过末尾 stash 标记恢复。Git Diff 在逐段绝对路径会抵消收益时改用紧凑文件/hunk 汇总。可选的 sourcePath 仅用于按扩展名选择 8 种源码 grammar。单 block 最小 512 字节才参与压缩。

无损 CSV-schema / minify 不产生 stash 或省略提示。JSON 结构采样、行内片段、标签保护造成映射变化、非本地 store 等情况暂不输出文件行提示。纯文本默认按 query 相关性、位置、显著信息和近重复抑制进行抽取,保留的句段逐字来自原文。

日志首个非空行、可识别的命令回显(如 $ cargo build、shell tracing、npm script、PowerShell 提示符)及显式续行强制保留,不会被普通日志行数预算截掉或隐藏在模板中。能从 stash 恢复不等于允许省略执行命令。

retrieve(key)

按 stashKey 从 stash store 取回有损压缩的原文,端到端无损。

retrieveLines(key, startLine, lineCount)

按 stash 原文的 1-based 行号读取连续分片,单次最多 1000 行;返回 text / startLine / lineCount / totalLines / hasMore。这是非本地 stash 或文件工具不可用时的备选;代码内联提示本身不要求调用这个 API。

detectContentType(text) / detectRequestFormat(body)

类型探测:返回内容类型(JSON 对象或数组,也识别连续对象与 JSON 为主体的轻量 wrapper / 构建日志 / 搜索结果 / git diff / 源代码 / 纯文本 / HTML / YAML、TOML、INI 结构化配置 / CSV、TSV、Markdown 表格)或请求格式(anthropic / chat_completions / responses)。

最佳实践