npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@context-chef/ai-sdk-middleware

v3.1.1

Published

AI SDK middleware for context-chef. Transparent history compression, tool result truncation, and token budget management.

Readme

@context-chef/ai-sdk-middleware

npm version npm downloads License TypeScript AI SDK

基于 context-chefVercel AI SDK 中间件。透明的历史压缩、工具结果截断和 token 预算管理 — 无需修改任何代码。

📖 文档站: https://myprototypewhat.github.io/context-chef/zh/packages/ai-sdk-middleware · English

Quick Start

安装

npm install @context-chef/ai-sdk-middleware ai

快速开始

import { withContextChef } from '@context-chef/ai-sdk-middleware';
import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';

const model = withContextChef(openai('gpt-4o'), {
  contextWindow: 128_000,
  compress: { model: openai('gpt-4o-mini') },
  truncate: { threshold: 5000, headChars: 500, tailChars: 1000 },
});

// 下面的代码完全不变 — 兼容 generateText、streamText 和 ToolLoopAgent
const result = await generateText({
  model,
  messages: conversationHistory,
  tools: myTools,
});

就这样。历史压缩、工具结果截断和 token 预算追踪在后台自动完成。

功能

历史压缩

当对话超出 token 预算时,中间件会压缩旧消息以腾出空间。两种模式:

不配置压缩模型(默认)— 旧消息被丢弃,仅保留近期消息:

const model = withContextChef(openai('gpt-4o'), {
  contextWindow: 128_000,
});

配置压缩模型 — 旧消息由便宜模型生成摘要后替换:

const model = withContextChef(openai('gpt-4o'), {
  contextWindow: 128_000,
  compress: {
    model: openai('gpt-4o-mini'),  // 用于摘要的便宜模型
    preserveRatio: 0.8,             // 保留 80% 的上下文给近期消息
  },
});

In-flight 与 durable 的区别。 中间件的 compressin-flight 的:它只重写每次发出去的请求,不会改动你的消息存储。所以对于持续超预算的对话(长聊天,或长的多步 loop),摘要每次调用后即被丢弃、历史随即回胀 —— 压缩实际上只会隔次触发,payload 还会持续增长。一次性尖峰无所谓;若是持续场景,请通过 onCompress 持久化摘要,或用 compactModelMessages 压缩你自己的存储(推荐)。若 compress 反复触发却没配 onCompress,中间件会打印一次告警。

溢出策略(Overflow)

compress 是用一组选项去描述一套压缩策略;overflow.strategy本身就是那套策略。传入 @context-chef/core 里的策略 —— summarize()anchored()reset(),以及 chain() / background() 组合,或你自己实现的对象 —— 它会整体取代 compress 所描述的策略:

import { chain, InMemoryBackend, reset, Store, summarize } from '@context-chef/core';

const archive = new Store(new InMemoryBackend()).namespace('archive');

const model = withContextChef(openai('gpt-4o'), {
  contextWindow: 128_000,
  overflow: {
    strategy: chain(summarize({ compressionModel }), reset()),
    archive: { store: async (serialized) => (await archive.put(serialized)).uri },
  },
});
  • 只配策略也会开启预算检查 —— 不需要再写 compress 块。但一旦配置了策略,contextWindow 就是必填的,否则 createMiddleware / withContextChef 会抛错:预算检查没有可比较的基准。
  • overflow.strategy 覆盖 compress 的调参项preserveRatiominShrinkRatiotoolResultStubThreshold,以及 compress.model)—— 同一件事有两套描述必然打架。summarize() 自带 compressionModel 回调,签名是 (messages: Message[]) => Promise<string>
  • runner 侧的配置继续生效,与用哪套策略无关:contextWindowtokenizercompress.triggerRatiocompress.usagePreferenceonCompressonBeforeCompressmaxSessionslogger
  • overflow.archive 只接受显式的 { store } 形式。 'vfs' 简写会替换成 ContextChef 自己的 Offloader,而中间件没有它。被驱逐的片段以 JSON.stringify({ version: 1, messages }) 传入,返回的 URI 会被摘要引用。

这里不提供 overflow.handofftools handoff 提示走的是 tail 通道,只有 ContextChef.compile() 才有;而本包只重写 prompt,从不产出工具定义,所以 tools 模式在这里没有作用对象。需要这两者时,请直接使用 @context-chef/core,在 ContextChef 上注册 getContextToolDefinition()

工具结果截断

大体积工具输出(终端日志、API 响应)会被自动截断,同时保留头部和尾部:

const model = withContextChef(openai('gpt-4o'), {
  contextWindow: 128_000,
  truncate: {
    threshold: 5000,   // 超过 5000 字符时截断
    headChars: 500,    // 保留开头 500 字符
    tailChars: 1000,   // 保留结尾 1000 字符
  },
});

可选地把原始内容持久化到 context store,方便后续被工具、审计流水线或回放层取回:

import { FileSystemBackend } from '@context-chef/core';

const model = withContextChef(openai('gpt-4o'), {
  contextWindow: 128_000,
  truncate: {
    threshold: 5000,
    headChars: 500,
    tailChars: 1000,
    store: new FileSystemBackend('.context'), // 也可以是 InMemoryBackend 或自定义 StorageBackend
  },
});

store 接受一个 StorageBackendInMemoryBackendFileSystemBackend 或你自己的实现),也接受一个已构造好的 Store —— 把同一个 Store 同时交给 overflow.archive,一个后端就能同时服务截断和归档。无论哪种方式,截断后的内容都会带上 context://vfs/ URI。

truncate.storage 在 4.2 中已废弃(5.0 移除)—— 请改传 store。旧的 VFSStorageAdapter 仍然可用:它会被 Store.fromVfsAdapter 包装,用其单一扁平键空间同时服务 vfsarchive 两个 namespace。两者同时配置时,store 胜出。

当后端暴露物理路径(FileSystemBackend 与旧的 FileSystemAdapter 都通过 getPhysicalPath 支持),截断 marker 会把该路径作为首选的取回句柄输出 —— 模型用现成的 file-read 工具直接读取即可,不必另写一个识别自定义 URI 的工具。不映射到文件系统的后端(DB、内存)则不实现 getPhysicalPath,marker 退化为单独的 context://vfs/ URI。

通过 perTool 做按工具覆写 —— 字符串条目完全保留该工具(同时跳过 VFS 写入),对象条目则只针对该工具覆盖 threshold / headChars / tailChars

const model = withContextChef(openai('gpt-4o'), {
  contextWindow: 128_000,
  truncate: {
    threshold: 5000,
    tailChars: 1000,
    perTool: [
      'read_file',                                 // 永不截断;也不写入 VFS
      { name: 'fetch_logs', threshold: 50_000 },   // 提高阈值
      { name: 'big_query', tailChars: 5000 },      // 保留更多尾部
    ],
  },
});

未列出的工具继续使用顶层默认值。查找键是 tool-result.toolName,过滤粒度是单个 tool-result part —— 因此同一条 tool 消息可以混合保留与截断的 part。(TanStack 中间件的同名选项粒度是单条消息,因为 TanStack 的一条 tool 消息对应一次 tool 调用。)不支持通配符,store / storage 也无法按工具覆写。perTool 只控制 truncate 这一步 —— 保留下来的消息仍可能被 compact 整条删除(若 compact.toolCalls 命中)、被 compress 在超出 token 预算时摘要,或被 transformContext 改写。

Token 预算追踪

中间件自动从 generateTextstreamText 响应中提取 token 用量,并回传给压缩引擎。无需手动调用 reportTokenUsage()

Compact(机械裁剪)

零 LLM 成本的消息裁剪,基于 AI SDK 的 pruneMessages — 移除 reasoning、工具调用和空消息:

const model = withContextChef(openai('gpt-4o'), {
  contextWindow: 128_000,
  compact: {
    reasoning: 'all',                          // 移除所有 reasoning
    toolCalls: 'before-last-message',          // 仅保留最后一条消息中的工具调用
  },
});

也支持按工具名称精细控制:

compact: {
  toolCalls: [
    { type: 'before-last-message', tools: ['search', 'calculator'] },
  ],
}

API

withContextChef(model, options)

用 context-chef 中间件包装 AI SDK 语言模型。

import { withContextChef } from '@context-chef/ai-sdk-middleware';

const wrappedModel = withContextChef(model, options);

参数:

| 选项 | 类型 | 必填 | 说明 | |---|---|---|---| | contextWindow | number | 是 | 模型的上下文窗口大小(token 数) | | compress | CompressOptions | 否 | 启用基于 LLM 的压缩 | | compress.model | LanguageModelV3 | 是(如启用 compress) | 用于摘要的便宜模型 | | compress.preserveRatio | number | 否 | 保留上下文的比例(默认:0.8) | | compress.triggerRatio | number | 否 | 触发压缩的 contextWindow 比例(0–1]。默认 0.7("pre-rot" — 模型质量在触及硬窗口上限之前就已下降,所以提前压缩)。设为 1 可恢复 4.0 之前"到窗口才触发"的行为。配置了 tokenizer 时,preserveRatio 作用于 contextWindow * triggerRatio 这个有效预算,而不是原始窗口。 | | compress.minShrinkRatio | number | 否 | 压缩结果必须把被压缩片段的字符长度至少缩小该比例(0–1,默认 0.5)。未达标的摘要按压缩失败处理:历史保持不变,并计入熔断器。设为 0 可关闭该检查。 | | compress.toolResultStubThreshold | number | 否 | 在把待摘要历史送给 compression model 之前,将超过该字符数的 tool-result 内容替换为一行元信息桩([Tool name returned N chars; omitted before summarization])。近期保留的 tool-result 不动。默认:undefined(关闭)。 | | compress.usagePreference | 'max' \| 'feedFirst' \| 'tokenizerFirst' | 否 | 当 tokenizer 与 AI SDK 上报的 usage 同时存在时,决定触发判断使用哪个 token 来源。默认 'max'(最保守 — Math.max(tokenizer, fed))。'feedFirst' 信任 API 真值,避免 tokenizer 高估导致的提前压缩;'tokenizerFirst' 完全忽略上报的 usage。'tokenizerFirst' 需要 tokenizer,缺失时构造期会被消毒为 'max' 并打印控制台警告。 | | truncate | TruncateOptions | 否 | 启用工具结果截断 | | truncate.threshold | number | 是(如启用 truncate) | 触发截断的字符数 | | truncate.headChars | number | 否 | 保留开头的字符数(默认:0) | | truncate.tailChars | number | 否 | 保留结尾的字符数(默认:1000) | | truncate.store | StorageBackend \| Store | 否 | 承载 vfs namespace 的 context store —— InMemoryBackendFileSystemBackend、自定义实现,或与 overflow.archive 共用的 Store。截断后的内容带 context://vfs/ URI。优先级高于 storage。 | | truncate.storage | VFSStorageAdapter | 否 | 4.2 起废弃 → truncate.store 旧的存储适配器,会被 Store.fromVfsAdapter 包装。 | | truncate.perTool | Array<string \| { name; threshold?; headChars?; tailChars? }> | 否 | 按工具覆写。字符串 = 保留(同时跳过存储);对象 = 为该工具覆写参数。重复名称时后者胜出。 | | compact | CompactConfig | 否 | 机械消息裁剪(reasoning、工具调用)。委托给 AI SDK 的 pruneMessages | | tokenizer | (msgs) => number | 否 | 自定义分词器用于精确计数 | | onCompress | (summary, count, details) => void | 否 | 压缩完成后的回调。details.compressedMessages 是被摘要替换掉的 AI SDK 格式(LanguageModelV3Prompt)切片,可用于在自有存储中持久化摘要边界。 | | logger | ChefLogger | 否 | 降级警告的输出目标(存储写入失败、缺少 usage 数据、配置异常等),默认 console。转发给底层 Janitor 和 Offloader。 | | overflow | { strategy?, archive? } | 否 | 溢出轴 —— 见溢出策略(Overflow)。 | | overflow.strategy | OverflowStrategy | 否 | 来自 @context-chef/coresummarize() / anchored() / reset() / chain() / background(),或自定义实现。会覆盖 compress 的调参项(含 compress.model);runner 侧配置继续生效。配置后 contextWindow 变为必填。 | | overflow.archive | CompressionArchiveConfig | 否 | { store: (serialized, { messageCount }) => uri } —— 让被驱逐的片段仍可通过摘要引用的 URI 取回。'vfs' 简写仅 core 支持。 | | clear | ClearTarget[] | 否 | 占位符式的 tool-result 清除。被清除的工具结果变为 '[Old tool result content cleared]'——消息结构保持完整,与删除内容的 compact 不同。在压缩之后执行。当工具结果被清除时,自动注入一条系统消息以避免模型将占位符读作错误。仅 'tool-result' 目标生效;'thinking' 目标为空操作(会记录一条警告)——请用 compact: { reasoning: ... } 删除 reasoning。ClearTarget@context-chef/core 导出。 |

返回值: LanguageModelV3 — 包装后的模型,可在任何使用原模型的地方直接替换。

createMiddleware(options)

创建原始 LanguageModelMiddleware,可通过 wrapLanguageModel 自行应用:

import { createMiddleware } from '@context-chef/ai-sdk-middleware';
import { wrapLanguageModel } from 'ai';

const middleware = createMiddleware({ contextWindow: 128_000 });
const model = wrapLanguageModel({ model: openai('gpt-4o'), middleware });

fromAISDK(prompt) / toAISDK(messages)

AI SDK LanguageModelV3Prompt 与 context-chef Message[] IR 之间的底层转换器。适用于直接使用 context-chef 模块处理 AI SDK 消息格式的场景。

import { fromAISDK, toAISDK } from '@context-chef/ai-sdk-middleware';

const irMessages = fromAISDK(aiSdkPrompt);
// ... 用 context-chef 模块处理 ...
const aiSdkPrompt = toAISDK(irMessages);

summarizeMessages(prompt, model, options?)

将一段 AI SDK prompt 切片摘要为单个字符串,使用与在途压缩相同的流水线。它会先 fromAISDK、丢弃 system 消息,再以内置的角色扁平化适配器调用 core 的 summarizeHistory —— 因此你无需自行扁平化 tool 角色。返回提取出的摘要文本;空 prompt 不调用模型直接返回 '',模型调用失败时抛出异常。

适用于持久化压缩:由宿主自己拥有对话存储并自行持久化压缩结果,而非依赖中间件的透明压缩。

import { summarizeMessages } from '@context-chef/ai-sdk-middleware';

const summary = await summarizeMessages(promptSlice, model, {
  toolResultStubThreshold: 5000,
});
// 自行持久化 { summary, boundary };之后回放 [summary] + [recent]。

SummarizeMessagesOptions 是 core SummarizeHistoryOptions 的结构别名(customCompressionInstructionstoolResultStubThreshold)。如需「续接对话」的框架文本,用 @context-chef/coregetCompactSummaryWrapper 包裹返回值。

协调注意: 若以此方式驱动摘要,请不要在同一中间件路径上对同一对话再配置 compress(带 model)—— 那会重复压缩(调用时一次、持久化时再一次)。仅做通知的 onCompress,以及 truncatecleardynamicState 可安全并用。

compactModelMessages(messages, model, options)

一站式 durable 压缩 —— 当你拥有消息存储时(长 agent loop,或超预算的聊天),让长对话保持精简的推荐方式。它工作在 ModelMessage 层级 —— 即 generateTextprepareStep 实际交给你的 ModelMessage[] 类型。它在 turn 边界切分历史、对旧切片摘要,返回一份可直接持久化的新 ModelMessage[] —— [...system, <摘要>, ...最近若干轮]。可在你自己的 loop 里运行(拥有存储并把结果写回),或放进 ToolLoopAgent:

import { compactModelMessages } from '@context-chef/ai-sdk-middleware';

const agent = new ToolLoopAgent({
  model,
  tools,
  prepareStep: async ({ messages, model }) => ({
    messages: await compactModelMessages(messages, model, { keepRecentTurns: 4 }),
  }),
});

或在模型调用之间,当你持有 messages 时:

const next = await compactModelMessages(messages, summarizerModel, {
  keepRecentTurns: 4,           // 逐字保留最近 4 个原子轮次
  toolResultStubThreshold: 5000,
});
if (next !== messages) await save(next); // no-op 时跳过持久化
  • modelaiLanguageModel(string id | V3 | V2)—— 正是 prepareStep / generateText 交给你的类型。
  • 切点只落在 turn 边界(assistant 及其 tool 结果作为整体),所以不会 orphan tool 结果、也不会切进多 block 的 assistant 消息。
  • system 消息逐字保留、永不被摘要。
  • 当没有足够旧的内容可压(轮数不超过 keepRecentTurns)、或摘要器无输出时,原样返回同一个 messages 引用 —— 因此可通过 next !== messages 在 no-op 时跳过持久化。可无条件调用;仅当模型调用抛错时才抛错。
  • 接受与 summarizeMessages 相同的 SummarizeMessagesOptions(customCompressionInstructionstoolResultStubThreshold)。

对同一对话用这个 in-flight compress,二选一(同时用会重复压缩)。

keepRecentTurns 数的是消息级 turn,不是 ToolLoopAgent 的 step。 一个 turn 是一条 user/assistant 消息,或一条带 tool-calls 的 assistant 加它全部 tool 结果(绑成一体)。一次用工具的 step 往往是 2–3 个 turn,所以请按你最坏单 step 的消息数来设 keepRecentTurns —— 工具密集的 agent loop 要比纯聊天设得更大。摘要是按 user 消息插入的,所以当保留尾部也以 user turn 开头时,结果可能出现连续两条 user 消息 —— 这是合法的 ModelMessage[],AI SDK 的 provider 层会归一化(Anthropic 合并同角色、OpenAI 直接接受)。

内部实现: compactModelMessagesplanCompactionModelMessagessummarizeModelMessages@context-chef/core 中 provider 无关引擎的 AI-SDK 薄壳 —— 它们把 ModelMessage[] 转成 core 的 IR 再转回来。若你直接对接某个 provider(不经 AI SDK),请改用 core 的 planCompaction / compactHistory

全压(Claude Code 式)

keepRecentTurns: 0,把整段对话压成一条摘要 —— 结果只有 [...system, <摘要>],没有逐字尾巴。这是最易持久化的模式:因为没有保留的尾巴,就不存在跟你存储自身单元边界(一个多 step 的 agent turn、一条跨多个 step 的 UI 消息等)对齐的问题 —— 回写就是「用这两条结果替换存储」。每一轮都塌回 [system, summary]

代价是没有任何逐字近况留存 —— 模型完全从一份有损摘要继续。所以摘要质量就是一切;用 customCompressionInstructions 把它导向结构化交接:

const next = await compactModelMessages(messages, summarizerModel, {
  keepRecentTurns: 0, // 全压 —— 把一切塌进摘要
  customCompressionInstructions: [
    '把摘要写成可续作任务的交接文档:',
    '- 已完成的工作与当前状态',
    '- 做了哪些决策、为什么',
    '- 涉及的文件 / 资源',
    '- 下一步要做的确切动作',
  ].join('\n'),
});
// 此时 `next` 就是 [system, summary] —— 持久化极简,无需任何边界记账。

想保住「进行中那一轮」的逐字上下文时(无人值守的 loop 做事中更安全),用小的 keepRecentTurns(如 24);想最大化收缩、要一个干净无边界的存储时,用 0

planCompactionModelMessages(messages, options)

compactModelMessages 背后的同步切分函数,适用于只要边界、不想立刻摘要的场景(持久化你自己的标记,或用别的摘要器)。返回 { system, toSummarize, toKeep }(均为 ModelMessage[]),按 turn 边界切分:

import { planCompactionModelMessages, summarizeModelMessages } from '@context-chef/ai-sdk-middleware';
import { Prompts } from '@context-chef/core';

const { system, toSummarize, toKeep } = planCompactionModelMessages(messages, { keepRecentTurns: 4 });
if (toSummarize.length > 0) {
  const summary = await summarizeModelMessages(toSummarize, model);
  messages = [
    ...system,
    { role: 'user', content: [{ type: 'text', text: Prompts.getCompactSummaryWrapper(summary) }] },
    ...toKeep,
  ];
}

summarizeModelMessages(messages, model, options?)

summarizeMessages 的 ModelMessage 层级兄弟函数:用同一流水线(角色扁平化 + core summarizeHistory)把一段 ModelMessage[] 切片摘要为单个字符串。system 消息会被丢弃。空切片不调用模型直接返回 '',模型调用失败时抛出异常。当你想自行驱动摘要、而非用一站式的 compactModelMessages 时,配合 planCompactionModelMessages 使用。

compactHistory(prompt, model, options)

已废弃。 compactHistory / planCompaction 收发的是 LanguageModelV3Prompt —— provider 协议层级,没人会持久化这个类型。请改用 compactModelMessages / planCompactionModelMessages。仍然导出且可用;下个大版本移除。

compactModelMessages 的 V3-prompt 变体。它在 turn 边界切分历史、对旧切片摘要,返回一份可直接持久化的新 prompt —— [...system, <摘要>, ...最近若干轮]

import { compactHistory } from '@context-chef/ai-sdk-middleware';

// 在模型调用之间,当你持有 `messages` 时:
messages = await compactHistory(messages, summarizerModel, {
  keepRecentTurns: 4,           // 逐字保留最近 4 个原子轮次
  toolResultStubThreshold: 5000,
});
// 持久化结果 —— 历史真正变小并保持精简。
  • 切点只落在 turn 边界(assistant 及其 tool 结果作为整体),所以不会 orphan tool 结果、也不会切进多 block 的 assistant 消息。
  • system 消息逐字保留、永不被摘要。
  • 当没有足够旧的内容可压(轮数不超过 keepRecentTurns)、或摘要器无输出时,原样返回 prompt —— 可无条件调用。仅当模型调用抛错时才抛错。
  • 接受与 summarizeMessages 相同的 SummarizeMessagesOptions(customCompressionInstructionstoolResultStubThreshold)。

planCompaction(prompt, options)

已废弃。 请改用 planCompactionModelMessages。 这个 V3-prompt 变体是 provider 协议层级 —— 一个你永远不会持久化的类型。仍然导出且可用;下个大版本移除。

compactHistory 背后的同步切分函数,适用于只要边界、不想立刻摘要的场景(持久化你自己的标记,或用别的摘要器)。返回 { system, toSummarize, toKeep }(均为 LanguageModelV3Prompt),按 turn 边界切分:

import { planCompaction, summarizeMessages } from '@context-chef/ai-sdk-middleware';
import { Prompts } from '@context-chef/core';

const { system, toSummarize, toKeep } = planCompaction(messages, { keepRecentTurns: 4 });
if (toSummarize.length > 0) {
  const summary = await summarizeMessages(toSummarize, model);
  messages = [
    ...system,
    { role: 'user', content: [{ type: 'text', text: Prompts.getCompactSummaryWrapper(summary) }] },
    ...toKeep,
  ];
}

工作原理

generateText / streamText / ToolLoopAgent ({ model: wrappedModel, messages })
  |
  v
transformParams(LLM 调用前)
  1. 截断大体积工具结果(如已配置)
     - 可选持久化原始内容到存储适配器
  2. AI SDK 消息 -> context-chef IR
  3. 运行 Janitor 压缩(如超出 token 预算)
  4. 转换回 AI SDK 消息
  |
  v
LLM 调用正常执行
  |
  v
wrapGenerate / wrapStream(LLM 调用后)
  5. 从响应中提取 token 用量
  6. 回传给 Janitor 用于下次调用的预算检查
  |
  v
结果原样返回

中间件是有状态的 — 它跨调用追踪 token 用量以判断何时需要压缩。每个对话/会话创建一个包装模型实例。

需要更多控制?

中间件覆盖了最常见的场景:透明的压缩和截断。如需动态状态注入、工具命名空间、记忆、快照/恢复,或统一的 context 工具(tools: 'unified')与 handoff 预算(overflow.handoff)等高级功能,请直接使用 @context-chef/core

许可证

MIT