Skip to content
查看原文

改成你自己的 ​

只需要改三处,其余都是管道。

1. 声明你的能力 ​

打开 src/operations.registry.ts。删掉三个 demo* operation,然后每个能力加一个 Operation。

这一条定义会生成:

  • HTTP 路由
  • OpenAPI 路径
  • /llms.txt 里的一行
  • 助手针对它的行为规则
ts
{
  id: "createVideo",              // 保持稳定;模型可能会引用它
  method: "post",
  path: "/v1/videos",
  summary: "根据提示词生成视频",
  description: "启动一次生成,返回一个需要跟踪的任务。",
  input: { schema: z.object({ prompt: z.string().min(1).max(4000) }) },
  spends: { kind: "credits", note: "消耗 1 个生成积分。" },
  async: { pollWith: "getVideo", typicalSeconds: 90 },
  handler: ({ provider, connection, body, idempotencyKey }) =>
    provider.createVideo(connection, body as any, idempotencyKey),
}

真正重要的字段 ​

字段作用
idoperationId。保持稳定 —— 模型可能会引用它,pollWith 也指向它
summary模型读的一句话,用祈使句
description一小段说明。必须写清它"不会"做什么
inputZod schema,在你的 handler 执行前完成校验
spends标记这个操作要花用户的钱
async标记它返回一个任务,并指明去轮询哪个操作
outputSchema200 响应的 JSON Schema,只用于 OpenAPI 文档

spends 和 async 在异步与付费里详述。 它们决定了一个 connector 是行为端正,还是会悄悄让用户被扣两次钱。

2. 实现你的服务 ​

在 src/providers/ 里对接你的真实 API,做完后删掉 placeholder.ts。

接口一开始故意做得很小:

ts
export interface ProviderPort {
  whoami(connection: ConnectionRecord): Promise<WhoAmI>;
  // 上面每声明一个 operation,这里就加一个方法
}

placeholder.ts 是一个完整示例。它也演示了幂等模式 —— 用 连接 + Idempotency-Key 映射到任务 id,这样重试会返回原来的任务。

控制调用方看到的状态码 ​

抛出带状态码的 UpstreamError。这是 connector 其余部分唯一依赖的约定:

ts
import { UpstreamError } from "../provider.js";

throw new UpstreamError(`no such job: ${id}`, 404);

能识别的状态码会原样透传,其他意外情况统一变成 502。

3. 命名 ​

SERVICE_NAME 控制 OpenAPI 标题、/health 和 llms.txt。默认是 Muse Connector。

包名、bin 名和仓库名随你改。改掉它们不会有任何影响 —— 没有东西依赖它们。

怎么检查改对了 ​

改完之后,确认生成的两份文档符合预期:

bash
curl -s localhost:8787/openapi.json | jq '.paths | keys'
curl -s localhost:8787/llms.txt

如果某个 operation 在两者里都不见了,说明它没进注册表。 如果它出现在 OpenAPI 里、但模型不知道什么时候该调用它,那问题在你的 description —— 那段文字才是接口。