@reinsjs/lowering-fetch

中文文档
0.5.1发布于 2026/11/02MITTypeScriptES Module

缰—获取上的零依赖降低层:事件当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种的当下一种

中文使用文档
文档目录8 节
  1. 选择 @reinsjs/lowering-fetch 和 @reinsjs/lowering-pi
  2. 运行时
  3. 选项
  4. 事件如何在聊天完成时发生
  5. 事件是如何登陆人类信息的
  6. 事件如何登陆OpenAI响应
  7. 错误和重试
  8. 文档

@reinsjs / lowering-fetch

的零依赖降低层 缰绳:时间线事件→提供程序连接协议→事件草稿,只使用 fetch 以及一个手写的SSE解析器。没有供应商SDK,没有 node:*在Node、Workers、Deno和Bun上使用相同的代码。

三种有线协议: OpenAI聊天完成 (兼容openai生态系统的前门:DeepSeek、Qwen、vLLM、网关) 人为的消息 (会话中系统放置,签名思考重播,显式缓存断点)和 OpenAI反应 (无状态 store: false、加密推理回放、开发者消息等)。

pnpm add @reinsjs/lowering-fetch
import { anthropic, anthropicMessages, deepseek, openai, openaiChat, openaiResponses, chatCompletions } from "@reinsjs/lowering-fetch"
import { createAgent } from "@reinsjs/agent"

const opus = anthropic("claude-opus-5", { apiKey: process.env.ANTHROPIC_API_KEY! })
const ds = deepseek("deepseek-flash", { apiKey: process.env.DEEPSEEK_API_KEY! })
const gpt = openai("gpt-5-mini", { apiKey: process.env.OPENAI_API_KEY!, requestOptions: { reasoning: { effort: "low", summary: "auto" } } })
const mini = openaiChat("gpt-4o-mini", { apiKey: process.env.OPENAI_API_KEY! })
// any Anthropic-protocol endpoint (DeepSeek's compatible port, a gateway)
const dsClaude = anthropicMessages("deepseek-v4-flash", {
  provider: "deepseek",
  baseUrl: "https://api.deepseek.com/anthropic",
  apiKey: process.env.DEEPSEEK_API_KEY!,
  reasoning: true,
  midConversationSystem: true,
})
const qwen = chatCompletions("qwen-max", {
  provider: "qwen",
  baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
  apiKey: process.env.DASHSCOPE_API_KEY!,
  contextWindow: 128_000,
})

export const agent = createAgent({ model: ds, store, tools })

每个工厂返回一个 BoundModel = { model, lowering }. apiKey 是必需的,并且从不从环境中读取。对于一个降低实例上的多个模型,构造 FetchLowering 你自己和传球 models.

选择 @reinsjs/lowering-fetch 和 @reinsjs/lowering-pi

两者实现相同 Lowering 界面与 @reinsjs/core 每一次降落都是a LOSS_MATRIX; createAgent 不在乎你经过哪一个。它们是有意共存的——选择每个主机,而不是每个项目。

@reinsjs/lowering-fetch@reinsjs/lowering-pi
协议OpenAI聊天完成,Anthropic消息,OpenAI响应Anthropic Messages, OpenAI Responses
延期工具(人为的) defer_loading + tool_reference,用于 lazyTools())是的, capabilities.deferredTools 官方Anthropic模型没有(请求整形是pi-ai的;引用以文本形式呈现)
依赖关系@reinsjs/core 仅(≈90 KB的ESM)pi-ai 及其10个依赖项(安装约65 MB)
请求体payload.body 是发送的内容pre-rewrite形状;真正的身体是在pi-ai中产生的 onPayload 钩
在交谈 system 在人为由编码器放置通过重写pi-ai的有效载荷来放置
无符号思维dropped (声明)可以退回到可见文本
模型表每个模型覆盖的最小内置表Pi-ai的桌子,维护在上游
运行时在最严格的层(2023兼容日期,no . 5)的Cloudflare workerd上验证 nodejs_compat)、Bun、Deno (--allow-net 只有)和Vercel edge-runtime,针对实时提供商的所有三个协议在相同的四个运行时上验证,两个协议;Deno需求 --allow-sys=osRelease, Edge运行时需要 process OpenAI路径的全局

从……开始 lowering-fetch 对于一个新主持人来说,它涵盖了一切 lowering-pi 覆盖和openai兼容的生态系统,除了这个包什么都没有,你调试的请求就是发送的请求。呆在 lowering-pi 当您已经在它上运行时(没有什么需要迁移的),或者当您希望提供程序表和新的有线协议特性通过pi-ai而不是通过这个包到达时。由一层编写的事件通过另一层重放: replay.thinkingSignature 在两者上使用相同的形状,因此切换不会使存储的时间轴失效。

运行时

否 node:*,没有 process,没有 Buffer -一样 dist/index.js 运行在节点≥22和Cloudflare worker上的2023 compatibility_date 没有兼容性标志(spikes/edge-runtime-check层:模块负载,针对本地假端点的字节切片SSE流,以及每个协议一个实时请求)。Bun 1.4, Deno 2.9(仅限) --allow-net 需要-层不读取系统信息)和Vercel的 edge-runtime (裸vm,不 process,没有 eval)通过相同的探测,所有三个协议都针对活动提供商(spikes/runtime-matrix)。

选项

选项意义
apiKey要求;使用 auth: "none" 当凭证存在时 headers (Cloudflare AI Gateway的 cf-aig-authorization)
baseUrl协议根; /chat/completions (OpenAI: …/v1(DeepSeek:裸主机); /messages (人为: …/v1)或 /responses (OpenAI: …/v1)是附加的
contextWindow, maxOutputTokens, reasoning, images, cost, midConversationSystem覆盖内置表;未知模型从保守默认值开始(128k / 16k /无推理/无图像)
chat.reasoningContentDeepSeek方言:重放 reasoning_content (默认在 deepseek(),见下文)
chat.liftToolImages当模型获取图像时,将工具结果中的图像移动到a中 user 消息后的批次 tool 消息(默认 true); 集 false 对于上游,拒绝形状和图像再次成为占位符
anthropic.betas的值 anthropic-beta 头;只在设置时发送(会话中系统不需要)
anthropic.cacheBreakpoints, anthropic.cacheTtl, anthropic.midSystemCacheBreakpoint显式缓存断点在Anthropic(默认开启,5分钟);当请求结束时该怎么办 "automatic" (默认,顶级 cache_control), "previous-user", "drop"
anthropic.deferredTools是否 ToolSpec.deferLoading 变成了 defer_loading: true 和 tool_reference 内容部分变成原生的 tool_reference 块。默认值:开启 provider: "anthropic",对于第三方Anthropic-protocol端点(DeepSeek的兼容端点忽略)关闭 defer_loading,所以每个工具都是可见的)。当关闭时,延迟的工具将不会被发送,并且引用将被呈现为文本
responses.systemRole应答中的系统提示和注释的角色:default developer 对于推理模型, system 否则;把它钉在上游,拒绝其中一个
responses.encryptedReasoning推理模型默认为: include: ["reasoning.encrypted_content"] 是不是总是发这样的推理题下可以重播 store: false;关闭拒绝的上游 include (当时 thinkingReplay 报告 false)
requestOptions扩散到体内(max_tokens, temperature, thinking, OpenAI parallel_tool_calls,反应 reasoning / max_output_tokens / prompt_cache_key…); messages / input / tools / system / model / stream / store / previous_response_id 不能被覆盖。在人为 max_tokens 默认为模型的 maxOutputTokens 和 thinking 留给你(Opus 5+默认为自适应服务器端;Haiku 4.5仍然需要 budget_tokens); 在反应 reasoning 你的(gpt-5默认值是? medium, gpt-5.1+ to none)
timeoutMs整个请求截止日期包括流,默认为600000;超时是一个可重试的错误,一个主机 signal 流产是 aborted
trustMarkers默认开启:工具输出被封装在 <untrusted source="tool:…"> 在请求中;日志保存原件

事件如何在聊天完成时发生

每次降落都要申报 LOSS_MATRIX["openai-chat"] 并由测试断言——没有什么是无声地掉落的。

  • system_note →谈话中途 system 消息(exact;在OpenAI和DeepSeek上验证)。集 midConversationSystem: false 如果上游拒绝了它,音符就会以框架的形式发出 user 消息(lossy). 一张写着 directive: true (模型必须执行的指令,例如 compact(他的请求)总是被框出去 user 消息,在所有三个协议上。
  • 当工具结果仍然挂起时到达的用户消息或注释在连线上移动到它们之后(tool 消息必须直接跟随 assistant 这叫他们);记录用户留言 lossy(user),日志顺序不变。
  • 思考聊天完成没有重放槽(没有签名,没有加密项目)。关于官方API的思考事件是 dropped. 与 chat.reasoningContent (DeepSeek)它们被重播为 reasoning_content ——和DeepSeek 需要 每条历史助理信息上的字段 tools 是存在的(否则是400),所以层总是发送它,当没有什么可重放时为空。
  • 一个回合与几个文本块合并为一个回合 content 字符串(lossy(merged-text)); tool 消息只携带文本:当模型拍摄图像时,每个图像都会留下一个指针([image n attached in the next user message]),这些图像合二为一 user 整批后的消息 tool 消息-在批处理后移动的任何用户消息之前-每个结果用一行命名工具,调用id和图像计数,并说这是工具输出,而不是用户;不可信的结果保持不变 <untrusted> 标记(lossy(tool+lifted-images);在DeepSeek的官方API上验证-在依赖它之前检查其他openai兼容的上游,并将其关闭 chat.liftToolImages: false 如果他们拒绝这个形状)。没有图像支持,或有 chat.liftToolImages: false,图像成为占位符(lossy(tool-text-only)); isError 在此协议上没有标志,表示为 [tool error] 前缀(lossy)。
  • 此协议上不存在显式缓存断点;提供程序端自动前缀缓存应用和 cached_tokens 据报道为 cacheRead.
  • 用法遵循核心语义: input 未缓存的提示计数。 costUsd 使用内置价格表(DeepSeek:峰值费率,上限)。

事件是如何登陆人类信息的

中声明 LOSS_MATRIX["anthropic-messages"],细胞对细胞比较 @reinsjs/lowering-pi.

  • system_note →谈话中途 { role: "system" } 关于接受它的模范家庭的信息(表5)。x /神话;x / Opus 5 / Opus 4.8或 midConversationSystem: true). 提供者需要这样的消息来跟随 user 转过身来,后面跟着一个 assistant 转或结束请求,因此音符在下一个辅助转之前(或在结束时)保持并发出;当这个槽跟随助手的转-或者这张纸条将是第一条信息-这张纸条将作为一个框发出 user 文本(lossy(user-role)). 其他模型总是得到框架文本。

  • 工具结果和在它们之后移动的任何东西(在结果挂起时到达的用户消息)共享一个 user 消息,所以 tool_result 街区直接沿着 tool_use 转弯。 is_error 是本地携带的。

  • 思考 只有当事件带有 signature 来自同一个提供者,API 和模型 (thinking / redacted_thinking 块);未签名的思维(中断的流),来自另一个提供者的思维,或者来自同一提供者的另一个模型的思维 dropped 声明——它不会变成可见的文本(签名只对产生它的模型有效:跨模型重播一个签名是400)。带有签名的空文本思维块(display: "omitted")被保存和重播。

  • 缓存断点一个在最后一个系统模块上,一个在最后一个工具上,一个在最后一个模块上 user 消息。当注释是最后一条消息时,对话断点将成为顶级断点 cache_control (与未注射时相同)。总共不超过四个。

  • 用法: input_tokens 已经是未缓存计数; cache_read_input_tokens / cache_creation_input_tokens 映射到 cacheRead / cacheWrite. stop_reason: "refusal" 变成不可重试的 error 携带 stop_details.

  • 延期工具(ToolSpec.deferLoading,由 lazyTools() 当 capabilities.deferredTools 是真实的): defer_loading: true 在该工具上,缓存断点移动到最后一个非延迟工具(延迟工具不能携带) cache_control),如果每个工具都要延迟,那么没有一个工具会延迟(API会拒绝)。一个 tool_result 它的内容只有 tool_reference 部件,来自系统信任的结果,并命名此请求中出现的工具 tools 发送为 tool_reference 阻止了API的扩展——工具列表永远不会改变,所以缓存前缀会保留(exact / tool-reference); 在同一结果中的文本部分被移动到批后 tool_result 块(lossy / tool-reference,它们不能混合)。对不在此请求中的工具的引用,或者在不受信任的结果中对工具的引用,将被呈现为文本——API将验证整个历史记录中的每个引用,并对未知名称回答400。

事件如何登陆OpenAI响应

中声明 LOSS_MATRIX["openai-responses"],细胞对细胞比较 @reinsjs/lowering-pi.

  • 无国籍建筑。 每个请求都包含整个历史 input; store: false 是被迫的 previous_response_id 在 requestOptions 时间轴是唯一的真实来源,OpenAI的服务器端会话状态从不依赖。
  • 系统提示和 system_note 是 developer 消息(推理模型)或 system 消息(其他)在任何位置 input -永远没有放置规则 exact. compaction 是一个框架吗? user 文本(lossy)。
  • 推理:推理模型总是要求 include: ["reasoning.encrypted_content"];每个推理项都完整地存储在事件中 replay.thinkingSignature 并逐字重播(提供者验证加密的有效载荷—伪造的有效载荷是400)。项目没有 encrypted_content (一条中断的小溪, include 拒绝),来自另一个提供者,或来自另一个模型 dropped 而宣言,从未化作文字。具有加密有效负载但没有摘要的推理项目被保存为空文本思考事件,以便下一轮可以重播它们。
  • 辅助文本变成了 type: "message" 项,重播提供者的 msg_ id (replay.textSignature(也接受lower -pi的JSON格式)或生成的格式。工具调用是 function_call 项目: call_id 是事件的 toolCallId, fc_ 项目id驻留在 replay.itemId 并且只对相同的模型重播(OpenAI验证配对 fc_ 和 rs_ 项目); arguments 是一个JSON字符串,所以非对象参数不需要包装。工具随附 strict: false.
  • 工具结果如下 function_call_output 匹配的项目 call_id:纯文本时为字符串,为的数组 input_text / input_image 当结果包含图像并且模型接受它们时,将阻塞; isError 在此协议上没有标志,表示为 [tool error] 前缀(lossy)。
  • 用法: input_tokens 包括缓存和缓存写入令牌,所以 input 是 input_tokens − cached_tokens − cache_write_tokens,两者映射到 cacheRead / cacheWrite. status: "incomplete" 与 max_output_tokens 是 length;与 content_filter 一个non-retryable error; response.failed 和 error 帧是携带提供者代码和消息的错误。自动前缀缓存是OpenAI方面的最大努力;通过 prompt_cache_key 在 requestOptions 提高命中率。
  • 内置表:gpt-5系列(5.5 / 5.4 / 5.4-mini / 5.2 / 5.1 / 5 / 5-mini / 5-nano), o3 / o4-mini和gpt-4.1 / 4.1-mini / 40 -mini的响应;相同的OpenAI id也存在于聊天完成项中,其中 openaiChat() 按协议选择。一个光秃秃的 { provider: "openai", id } 在一个 FetchLowering 你构建自己的决心来回应。

错误和重试

非2xx响应抛出 HttpError 与 status, headers 生的身体("<status> <body>"(与官方sdk使用的形状相同),所以 runLoop408 / 409 / 429 / 5xx可以重试,其他的都不能。网络故障从 fetch 都没动。

文档

docs/archive/implementation-plans/2026-09-08-技术方案v1.0.md §11日 docs/系统全景图_模块盘点/lowering-fetch.md, spikes/f1-chat-live/, spikes/f2-anthropic-live/, spikes/f3-responses-live/ (对DeepSeek进行实时验证,并通过Cloudflare AI网关、OpenAI和Anthropic进行验证)和 spikes/edge-runtime-check/ (Cloudflare workerd) -中文,在存储库根目录。

MIT©2026 newate Limited

版本与发布记录

@reinsjs/lowering-fetch 共发布 7 个版本,首次发布于 2026/09/15;过去 12 个月发布了 7 个版本。

版本发布日期距今
0.5.1latest2026/11/021 天前
0.5.02026/10/313 天前
0.4.12026/10/303 天前
0.4.02026/10/277 天前
0.3.02026/09/221 个月前
0.2.12026/09/151 个月前

关于 @reinsjs/lowering-fetch 的常见问题

@reinsjs/lowering-fetch 是什么?

缰—获取上的零依赖降低层:事件当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种当下一种的当下一种

如何安装 @reinsjs/lowering-fetch?

在项目目录运行 npm install @reinsjs/lowering-fetch,或使用 pnpm add / yarn add / bun add。

@reinsjs/lowering-fetch 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@reinsjs/lowering-fetch 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@reinsjs/lowering-fetch 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@reinsjs/lowering-fetch 可以商用吗?

@reinsjs/lowering-fetch 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@reinsjs/lowering-fetch 还在维护吗?

最新版本 0.5.1 发布于 2026/11/02(1 天前);至今共发布 7 个版本,其中过去 12 个月发布了 7 个;首次发布于 2026/09/15。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。