@mottyjs/adapters

中文文档
0.2.0发布于 2026/11/02Apache-2.0TypeScriptES Module构建来源已验证

大多数主机端适配器:模型提供程序、Redis和持久对象存储、jwt和承载认证。

中文使用文档

@mottyjs /适配器

Motty SDK的适配器:主机在其主机选项中传递的纯对象,一个导入路径 每一个。模型供应商: openai, anthropic, openrouter, deepseek, moonshot, zai, dashscope, minimax, groq, mistral, together, fireworks, ollama, local 和 typesafe. 储存: redis,这是Bun自己的客户端,因此只在Bun上运行 cloudflare, 一个持久对象,它只在Cloudflare Workers上运行。身份验证: jwt 和 bearer或者主人自己的物品。凭据保留在主机创建的适配器中 永远不要输入莫蒂的密码。这个包从来没有在motty's bundle中。

bun add @mottyjs/adapters
import { openai } from "@mottyjs/adapters/openai";

服务文件的适配器:

import { serve } from "@mottyjs/serve";
import { jwt } from "@mottyjs/adapters/jwt";
import { openai } from "@mottyjs/adapters/openai";
import { openrouter } from "@mottyjs/adapters/openrouter";
import { redis } from "@mottyjs/adapters/redis";
import desk from "./motty"; // Holds .use(auth())

export default serve(desk, ({ OPENAI_KEY, OPENROUTER_KEY, REDIS_URL, JWKS_URL }) => ({
  models: [
    openai({ key: OPENAI_KEY }),
    // A customer's message goes through a router only to providers that keep none of it
    openrouter({ key: OPENROUTER_KEY, body: { provider: { data_collection: "deny" } } }),
  ],
  storage: redis({ url: REDIS_URL }),
  auth: jwt({ jwks: JWKS_URL }),
}));

一个 auth 适配器只能证明来电者是谁,所以没有 .use(auth()) 为任何人运行。

在Worker上,存储是宿主自己的Worker的一个持久对象类。工人条目导出 MottyStorage, cloudflare 给出了它的绑定,从 env 那 cloudflare:workers 导出,因为绑定不是字符串,因此不在环境中 mount 写着:

// src/index.ts
import { env } from "cloudflare:workers";
import { mount } from "@mottyjs/serve";
import { cloudflare } from "@mottyjs/adapters/cloudflare";
import { openai } from "@mottyjs/adapters/openai";
import desk from "./motty";

export { MottyStorage } from "@mottyjs/adapters/cloudflare";

export default mount(desk, ({ OPENAI_KEY }) => ({
  models: [openai({ key: OPENAI_KEY })],
  storage: cloudflare({ binding: env.STORAGE }),
}));

的绑定及其迁移 wrangler.jsonc:

{
  "main": "src/index.ts",
  "compatibility_date": "2026-02-24",
  "compatibility_flags": ["nodejs_compat", "enable_request_signal"],
  "durable_objects": {
    "bindings": [{ "name": "STORAGE", "class_name": "MottyStorage" }]
  },
  "migrations": [{ "tag": "v1", "new_sqlite_classes": ["MottyStorage"] }]
}

类型 env.STORAGE 来自于文件 wrangler types 生成,所以运行它一次 那 main 名字存在。

这个 nodejs_compat 标志是必需的,如果没有它,则部署将失败 No such module "node:async_hooks".

第一次部署必须带着它的秘密。 mount 在全局作用域运行,该作用域作为 上载Worker,因此一个还不存在的键停止部署 The openai adapter was given no key 代码10021。把秘密从文件中上传 它不会出现在存储库中:

wrangler deploy --secrets-file <file>

同一个Cloudflare帐户上的上游Worker,到达其workers.dev地址,被看到 在实际部署中回答404,并打开 global_fetch_strictly_public 兼容性 Flag修复了它。为什么它回答404没有确认。

每个键都是自己的对象,所以键之间永远不会等待,对象的键 所有过期的全部删除。如果兼容性日期为2026-02-24或更高,则可以删除该内容 随身携带对象的警报器;较旧的日期只会在空对象上触发一次警报。 希望将相关密钥放在一起的主机通过 name,一个函数从一个键到它的名称 对象,而必须将数据保存在某个区域的对象传递限制到该区域的绑定,例如 env.STORAGE.jurisdiction("eu"). 绑定不是凭证,所以没有任何秘密可以到达motty。

连接需要 headers 对于它提出的每一个请求 body 字段,在提供者自己的 的名字。一个调用可以在它的选项中声明它自己的头文件,对于头文件位于上游的线束 预计。除非连接将其命名为,否则它们都不会被发送 forwardHeaders,在任何信件中 案例:

import { model, motty } from "@mottyjs/core";
import { anthropic } from "@mottyjs/adapters/anthropic";

// In the host
anthropic({ key: ANTHROPIC_KEY, forwardHeaders: ["user-agent", "x-app", "x-session"] });

// In the motty
export default motty({ name: "relay" }).handle(({ request, prompt }) => {
  const headers = {
    "user-agent": request.headers.get("user-agent"),
    "x-app": request.headers.get("x-app"),
    "x-session": request.headers.get("x-session"),
  };
  prompt.options = { ...prompt.options, headers };
  return model("anthropic/claude-sonnet-5-5").complete(prompt);
});

没有值的标头会被跳过。 forwardHeaders: true 转发每个头呼叫状态,但 下面这些。它信任motty在固定集之外的每个header,即选择的header 其中包括主机密钥下的帐户或项目,列表是安全的形式。一个网关 可能作用于主机从未设置的标头,例如指定在何处发送请求或 哪个帐户付款,因此列出通过一个帐户的连接的名称。

连接的标头和凭据总是优于同名的调用,也是如此 API自己写的头,比如内容类型。在任何形式的 forwardHeaders, 连接本身的报头、凭据、cookie和描述调用者主体的报头 永远不会发送。说明请求来自何处的通用头被省略在下面 true, 主机列出的名称即使在它说明请求来自何处时也会发送。一个头 未发送的在调用的警告中被命名,宿主的报告携带该警告,因此是作者 明白为什么没到了吧。任何请求都不能携带其名称或值的标头将导致调用失败 作为motty中的一个错误,将被发送的报头也是如此,并且在两个中声明两次 信情况。

在人类活动的上游 anthropic-* header是发送的消息API的调用者,除了 版本,已经带着请求旅行而没有被列出,他们赢得了一个电话的 相同的名字。

jwt 仅针对密钥集地址(jwks),一个公钥 PEM (key)或共享的秘密(secret),并给出它的 sub 作为来电显示。默认情况下 检查签名和令牌本身所声明的时间,以及声明没有到期的令牌 接受。每进一步的检查都是主人的补充:除了验证的方式, jwt 以 选项的 jose的 jwtVerify,都是可选的。标识提供程序为其签名令牌的主机 使用一个密钥集的几个应用程序应该命名发行者和受众:

jwt({
  jwks: JWKS_URL,
  issuer: "https://id.acme.example/",
  audience: "desk",
  requiredClaims: ["exp"],
  clockTolerance: 30,
});

bearer,从相同的导入路径获取一个普通密钥,并向调用者提供主机的id 命名,用于持有长期凭据的服务:

import { bearer } from "@mottyjs/adapters/jwt";

bearer({ secret: OPS_TOKEN, id: "ops" });

两者都是便利。Auth是主人自己写的 auth 选项接受任何带有 verify 函数,它被赋予调用者发送并返回调用者的令牌,或者 undefined 对任何人,立即或作为一个承诺。在主机自己的表中查找API键,这里是它的 ownerOf:

import { ownerOf } from "./keys";

export default serve(desk, ({ OPENAI_KEY }) => ({
  models: [openai({ key: OPENAI_KEY })],
  auth: {
    verify: async (token) => {
      const owner = await ownerOf(token);
      return owner === undefined ? undefined : { id: owner };
    },
  },
}));

使用OpenAI API的服务器可以通过 openai 本身 address. 模型名称 开始 prefix,这是在呼叫之前取下的,它应该是一个独立的词 OpenAI本身也在其中 models. 适配器使用响应API,除非 api 说 "chat-completions":

// In the host
openai({
  key: ACME_KEY,
  address: "https://llm.acme.example/v1",
  prefix: "acme",
  api: "chat-completions",
});

// In the motty
model("acme/some-model").complete(prompt);

密钥是必需的,并作为承载令牌发送到该地址。主机本身运行的服务器 想要什么钥匙都没有 local. 适配器所知道的OpenAI自己的模型并不适用于 另一个地址,所以一个选项是按规定发送的,服务器可能会拒绝它。

每个提供程序的适配器都保存一个列表,从该提供程序的引用中读取 只有帮助,如 metadata, seed 和 cacheKey. 一个作者在电话里说了一个,比如 options: { serviceTier: "flex" },无论提供者是谁。在列表中发送一个选项 Provider的名称在不同的地方,其他的都被省略,并在调用时发出警告 命名选项。引用未启用的选项仅在提供者声明的地方才会出现在列表中 它会忽略它不知道的东西,就像OpenRouter一样。值按照写入的方式执行,所以层是 提供商自己的话。更改答案的字段,例如 stop, response_format 或者 parallel_tool_calls总是这样,作者的名字也一样 options.provider 或者在 连接,在上游自己的名字。 openai 没有名单,把他们都发了。 local 有一个 这些服务器共享的默认列表及其 fields 选项替换它,如 fields: { ...localFields, maxTokens: "max_tokens" }. 没有的列表 streamOptions 要求拒绝 用法。

每个模型提供者的适配器经过验证的程度是不同的。 openai, anthropic, openrouter 和 typesafe 通过进行实际调用并在?下运行的测试,针对实时API进行了验证 bun run test:live. 其他的仅针对每个提供者自己编写的存根进行验证 文件; mistral, together 和 fireworks 有一个实时测试,运行后,该提供商 设置Key。

SDK作为一个整体在 根的自述,以及其设计背后的原因 ARCHITECTURE.md.

版本与发布记录

@mottyjs/adapters 共发布 4 个版本,首次发布于 2026/10/12;过去 12 个月发布了 4 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.2.0latest2026/11/021 天前
0.1.12026/10/1321 天前
0.1.02026/10/1222 天前
0.0.0-stage2026/10/1222 天前

关于 @mottyjs/adapters 的常见问题

@mottyjs/adapters 是什么?

大多数主机端适配器:模型提供程序、Redis和持久对象存储、jwt和承载认证。

如何安装 @mottyjs/adapters?

在项目目录运行 npm install @mottyjs/adapters,或使用 pnpm add / yarn add / bun add。

@mottyjs/adapters 支持 TypeScript 吗?

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

@mottyjs/adapters 支持 ESM 还是 CommonJS?

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

@mottyjs/adapters 可以商用吗?

@mottyjs/adapters 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@mottyjs/adapters 还在维护吗?

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