diff --git a/docs/reference/providers.md b/docs/reference/providers.md index aeaac74..d8be961 100644 --- a/docs/reference/providers.md +++ b/docs/reference/providers.md @@ -13,7 +13,7 @@ OpenAgentPack targets multiple agent platforms behind one declarative config. Ea | Skill | native | native | native | native | Claude uploads via `files[]`; the other providers upload zip archives. Volcengine Ark is create + attach only. | | Agent | native | native | native | native | Core managed-agent resource. | | MCP Server | native | native | native | native | Bailian uses official managed servers referenced by name. | -| Memory Store | unsupported | native | unsupported | native | Available on Qoder and Volcengine Ark. | +| Memory Store | unsupported | native | unsupported | native | Qoder and Ark are implemented. Claude's upstream API now has Memory Stores, but its OpenAgentPack adapter does not yet. | | Multi-Agent | unsupported | unsupported | native | native | Coordinator topology is available on Claude and Volcengine Ark. | | Deployment | emulated | emulated | native | emulated | Non-Claude providers expand a deployment into a session at `run` time. | | Session | native | native | native | native | Runtime sessions are native on every provider. | @@ -24,6 +24,71 @@ OpenAgentPack targets multiple agent platforms behind one declarative config. Ea This matrix is verified against the SDK capability declarations in `packages/sdk/src/internal/providers/*/capabilities.ts` by `scripts/provider-docs.test.ts`. +## Adapter implementation matrix + +The resource matrix above answers whether a declaration can be applied. The table below answers a different question: which optional workflows the **current OpenAgentPack adapter** actually implements. It is intentionally scoped to this repository, rather than every feature a provider may advertise. + +| Adapter workflow | Bailian | Qoder | Claude | Volcengine Ark | Implementation notes | +|------------------|:-------:|:-----:|:------:|:--------------:|----------------------| +| List agents, environments, and vaults | yes | yes | yes | yes | Powers resource discovery in the Web UI. | +| Export resources to YAML (`sync`) | yes | yes | yes | limited | Ark cannot enumerate skills, so skill export is skipped. | +| Full drift comparison | Environment, Agent | Environment, Agent | no | no | Other supported resources degrade to existence checks; emulated deployments are local state. | +| List uploaded files | yes | yes | yes | yes | File upload, metadata lookup, and deletion are also implemented by all adapters. | +| Resolve artifact download URL | no | yes | no | no | Qoder exposes a short-lived file content URL. | +| List skills | yes | yes | yes | no | Ark supports lookup by ID, but its adapter cannot enumerate skills. | +| Download skill source during `sync` | no | no | yes | no | Only Claude currently materializes remote skill packages locally. | +| Non-blocking skill creation for Web UI polling | yes | no | no | no | Bailian can create from an uploaded file ID and let the UI poll scan status. | +| List provider models | no | yes | yes | no | Used for model selection where a provider exposes a model catalog. | +| Stream and page session events | yes | yes | yes | yes | All adapters normalize provider events to the shared session event shape. | +| Resume event stream from send cursor | no | yes | no | no | Qoder returns an event cursor; the others connect before sending to avoid missed events. | + +`yes` means the corresponding optional `ProviderAdapter` facet is implemented. `no` means OpenAgentPack currently soft-degrades that workflow; it does not necessarily mean the upstream platform can never support it. `limited` means the workflow is implemented with the restriction described in the notes. + +### Notable provider-specific behavior + +- **Bailian:** skill upload uses the Files API and supports scan-status polling; agent updates create provider-side versions. Official MCP servers are referenced by name. +- **Qoder:** tool names are translated from the lowercase config vocabulary to PascalCase. Session sends return a cursor, enabling resumable event consumption. `system.message` is flattened to `user.message` when running an emulated deployment. +- **Claude:** deployments are native, including their server-side lifecycle. It is currently the only adapter that downloads remote skill packages during `sync`. +- **Volcengine Ark:** skills are create + get + attach only in the API behavior verified by this project. Updates re-upload a new skill; list and in-place update are unavailable; deletion is best-effort. Deployment is emulated as a session. + +### Claude and Volcengine Ark research notes + +Last reviewed: **2026-07-17**. The evidence labels below deliberately separate upstream product capability from OpenAgentPack support. + +| Area | Claude Managed Agents (official) | Claude adapter | Volcengine Ark (official/public) | Ark adapter | +|------|----------------------------------|----------------|-------------------------------|-------------| +| API status and protocol | Direct Claude API is GA for Messages/Models; Managed Agents, Files, and Skills are beta and require `managed-agents-2026-04-01` where applicable | Sends that beta header to `api.anthropic.com/v1` | Official Managed Agents API under `/api/v3`, authenticated with a Bearer API Key | Uses the documented base URL and wire shapes | +| Stateful sessions | Server-side history, sandbox state, event send/stream, interruption, and resume | Create/list/get/delete, send, SSE stream, and paged event history | Official APIs cover session CRUD, event send/list/stream, resources, and multi-agent threads | Create/list/get/delete, send, SSE stream, and paged event history; session update/resources/threads are not exposed | +| Environment | Isolated cloud sandbox per session; reusable environment config, package cache, and network policy | CRUD and list implemented | Official create/list/get/update/delete endpoints | CRUD/list implemented and existence drift checked | +| Skills | Built-in Anthropic skills plus custom zip or individual-file uploads; max 20 per session | CRUD/list/get/download implemented; adapter uploads `files[]` | Official documentation currently lists create and get only | Create/get/attach implemented; update recreates; list/delete are unavailable upstream | +| Multi-agent | Coordinator delegates to persistent, context-isolated threads sharing sandbox/files/vaults | Coordinator topology implemented | Agent schema includes `multiagent`; Session APIs expose thread list/detail/events/stream | Coordinator topology implemented; thread inspection is not exposed through `ProviderAdapter` | +| Deployment | Native scheduled deployments with cron/timezone and run history | Native lifecycle and run implemented | The official Managed Agents API catalog contains no Deployment resource | Emulated locally and expanded into a Session at run time | +| Memory Store | Official API supports persistent, versioned memories mounted read-only or read-write; up to 8 stores per session | **Gap:** not implemented, so capability remains `unsupported` in OpenAgentPack | Official CRUD for stores plus create/batch-create/list/get/update/delete for memories | Store create/delete and Session binding implemented; list/get/update and memory-content operations are adapter gaps | + +Primary references: [Claude API overview](https://platform.claude.com/docs/en/api/overview), [Claude Managed Agents overview](https://platform.claude.com/docs/en/managed-agents/overview), [sessions and event streaming](https://platform.claude.com/docs/en/managed-agents/events-and-streaming), [skills](https://platform.claude.com/docs/en/managed-agents/skills), [multi-agent sessions](https://platform.claude.com/docs/en/managed-agents/multi-agent), [scheduled deployments](https://platform.claude.com/docs/en/managed-agents/scheduled-deployments), [memory stores](https://platform.claude.com/docs/en/managed-agents/memory), and the [Volcengine Ark Managed Agents API reference](https://console.volcengine.com/ark/region:cn-beijing/docs/82379/2555910?lang=zh). + +The Ark API catalog confirms an important distinction for maintainers: some upstream operations are not yet represented in `ProviderAdapter` (session update/resources/threads, vault update and credential lifecycle, full Memory Store operations), while the narrow Skill lifecycle is an upstream limitation rather than merely missing adapter work. + +### Keeping this table current + +When adding a provider or optional adapter method: + +1. Update its `capabilities.ts` for resource-level support and implement the required lifecycle methods. +2. Re-check optional methods in `ProviderAdapter` (listing, sync/export, drift, files, skills, models, and session-event resume) and update this matrix. +3. Record API limitations in adapter comments with the endpoint or observed behavior; distinguish upstream limitations from missing OpenAgentPack work. +4. Run `bun test scripts/provider-docs.test.ts`. The test verifies both the resource matrix and the optional-method rows against adapter prototypes. + +### Provider documentation index + +Use these links as the starting point when refreshing the capability matrix or adding a provider method. Prefer official product/API pages over inferred behavior from this repository. + +| Provider | Primary source | Useful follow-up sources | Notes | +|----------|----------------|--------------------------|-------| +| Bailian | [Managed Agents quickstart](https://help.aliyun.com/zh/model-studio/managed-agents-quick-start) | [Model Studio docs root](https://www.alibabacloud.com/help/zh/model-studio/), [single-agent application guide](https://help.aliyun.com/zh/model-studio/single-agent-application) | Managed Agents quickstart shows the `/api/v1/agentstudio` endpoint family used by this adapter. | +| Qoder | [Cloud Agents API overview](https://docs.qoder.com/cloud-agents/api/conventions/overview) | [Cloud Agents overview](https://docs.qoder.com/cloud-agents/overview), [Agent Skills](https://docs.qoder.com/cloud-agents/skills), [Cloud Agents marketplace skill](https://qoder.com/marketplace/skill?id=official_FjWvobU0) | API docs are the canonical source for gateway URL, headers, resources, pagination, and event streaming. | +| Claude | [Claude API overview](https://platform.claude.com/docs/en/api/overview) | [Managed Agents overview](https://platform.claude.com/docs/en/managed-agents/overview), [events and streaming](https://platform.claude.com/docs/en/managed-agents/events-and-streaming), [skills](https://platform.claude.com/docs/en/managed-agents/skills), [multi-agent sessions](https://platform.claude.com/docs/en/managed-agents/multi-agent), [scheduled deployments](https://platform.claude.com/docs/en/managed-agents/scheduled-deployments), [memory stores](https://platform.claude.com/docs/en/managed-agents/memory) | API overview gives GA/beta status; Managed Agents pages give resource-specific behavior. | +| Volcengine Ark | [Managed Agents API reference](https://console.volcengine.com/ark/region:cn-beijing/docs/82379/2555910?lang=zh) | [Ark documentation center](https://docs.volcengine.com/docs/82379), [API key management](https://www.volcengine.com/docs/6257/64983?lang=en) | The console API reference is the source for `/api/v3` resources and confirms that Deployment is not a first-class resource. | + ## Provider configuration ### Bailian (Aliyun AgentStudio) diff --git a/docs/reference/providers.zh-CN.md b/docs/reference/providers.zh-CN.md index 66b5133..1e16016 100644 --- a/docs/reference/providers.zh-CN.md +++ b/docs/reference/providers.zh-CN.md @@ -32,11 +32,76 @@ OpenAgentPack 通过 Provider 适配器与不同的 AI Agent 平台交互。每 | Skill | native | native | native | native | Claude 使用 files[];其余 Provider 上传 zip | | Agent | native | native | native | native | 核心资源 | | MCP Server | native | native | native | native | 通过 Agent 的 MCP 配置挂载 | -| Memory Store | unsupported | native | unsupported | native | Qoder 与 火山方舟 原生支持 | +| Memory Store | unsupported | native | unsupported | native | Qoder、方舟已接入;Claude 上游已有 Memory Store,但 OpenAgentPack Adapter 尚未实现 | | Multi-Agent | unsupported | unsupported | native | native | Claude 与 火山方舟 支持 coordinator | | Deployment | emulated | emulated | native | emulated | 非 Claude Provider 在 `run` 时展开为 Session | | Session | native | native | native | native | 四者均原生支持 | +### Adapter 实现能力对照表 + +上表回答“某类资源能否声明和 apply”;下表回答“**当前 OpenAgentPack Adapter** 具体实现了哪些可选工作流”。表格描述的是本仓库代码,而不是 Provider 宣传的全部平台能力。 + +| Adapter 工作流 | 百炼 | Qoder | Claude | 火山方舟 | 实现说明 | +|----------------|:----:|:-----:|:------:|:--------:|----------| +| 枚举 Agent、Environment、Vault | yes | yes | yes | yes | 用于 Web UI 的云端资源发现 | +| 导出资源到 YAML(`sync`) | yes | yes | yes | limited | 方舟无法枚举 Skill,因此会跳过 Skill 导出 | +| 完整 Drift 内容比较 | Environment、Agent | Environment、Agent | no | no | 其他已支持资源降级为存在性检查;模拟 Deployment 仅有本地状态 | +| 枚举已上传文件 | yes | yes | yes | yes | 四个 Adapter 也都实现上传、元数据查询和删除 | +| 获取产物下载 URL | no | yes | no | no | Qoder 可返回短期有效的文件内容 URL | +| 枚举 Skill | yes | yes | yes | no | 方舟可按 ID 查询,但当前无法枚举 | +| `sync` 时下载 Skill 源文件 | no | no | yes | no | 当前仅 Claude 会把远端 Skill 包还原到本地 | +| Web UI 非阻塞创建 Skill 并轮询 | yes | no | no | no | 百炼可从已上传 file ID 创建,再由 UI 轮询扫描状态 | +| 枚举 Provider 模型 | no | yes | yes | no | Provider 暴露模型目录时用于模型选择 | +| 流式读取并分页查询 Session Event | yes | yes | yes | yes | 四个 Adapter 均转换为统一事件结构 | +| 从发送游标恢复事件流 | no | yes | no | no | Qoder 返回事件游标;其余 Provider 采用先连接、后发送避免漏事件 | + +`yes` 表示实现了对应的可选 `ProviderAdapter` 接口;`no` 表示 OpenAgentPack 当前会对该工作流软降级,并不等价于上游平台永远不支持;`limited` 表示已实现但存在备注中的限制。 + +#### Provider 特有实现与限制 + +- **百炼**:Skill 通过 Files API 上传并支持扫描状态轮询;Agent 更新会生成平台侧版本;官方 MCP Server 按名称引用。 +- **Qoder**:配置中的小写工具名会转换为 PascalCase;Session 发送返回游标,可恢复事件消费;模拟 Deployment 中的 `system.message` 会展平为 `user.message`。 +- **Claude**:Deployment 是原生资源,具有服务端生命周期;当前只有 Claude Adapter 会在 `sync` 时下载远端 Skill 包。 +- **火山方舟**:经本项目验证的 Skill API 行为仅支持创建、按 ID 查询和挂载。更新会重新上传,无法枚举和原地更新,删除为 best-effort;Deployment 由 Session 模拟。 + +#### Claude 与火山方舟专项调研 + +最后核验日期:**2026-07-17**。以下内容刻意区分“上游产品能力”和“OpenAgentPack 已实现能力”。 + +| 领域 | Claude Managed Agents(官方) | Claude Adapter | 火山方舟(官方公开资料) | Ark Adapter | +|------|-------------------------------|----------------|--------------------------|-------------| +| API 状态与协议 | Claude 直连 API 中 Messages/Models 为 GA;Managed Agents、Files、Skills 为 beta,相关接口要求 `managed-agents-2026-04-01` | 向 `api.anthropic.com/v1` 发送该 Beta Header | 官方 Managed Agents API 位于 `/api/v3`,使用 Bearer API Key | 使用官方文档中的 Base URL 和数据结构 | +| 有状态 Session | 服务端保存历史和沙箱状态,支持事件发送/流式读取、中断与恢复 | 已实现创建、枚举、查询、删除、发送、SSE 和事件历史分页 | 官方提供 Session CRUD、Event 发送/查询/流式读取、Session Resource 和 Multi-Agent Thread 接口 | 已实现创建、枚举、查询、删除、发送、SSE 和事件历史分页;尚未暴露 Session 更新、Resource、Thread | +| Environment | 每个 Session 使用隔离云沙箱;环境配置可复用,支持包缓存和网络策略 | 已实现 CRUD 和枚举 | 官方提供创建、枚举、查询、更新、删除接口 | 已实现 CRUD/枚举及存在性 Drift 检查 | +| Skill | 支持 Anthropic 内置 Skill 与自定义 zip/多文件上传;每 Session 最多 20 个 | 已实现 CRUD、枚举、查询和下载;Adapter 使用 `files[]` 上传 | 官方文档当前仅列出创建和查询详情 | 已实现创建、查询和挂载;更新通过重建模拟;枚举、删除是上游缺失 | +| Multi-Agent | Coordinator 可调度持久、上下文隔离的线程;共享沙箱、文件和 Vault | 已实现 Coordinator 拓扑 | Agent Schema 含 `multiagent`;Session API 提供 Thread 列表、详情、事件查询和流式读取 | 已实现 Coordinator 拓扑;`ProviderAdapter` 尚未暴露 Thread 查询 | +| Deployment | 原生定时 Deployment,支持 cron、时区和运行历史 | 已实现原生生命周期和运行 | 官方 Managed Agents API 目录中没有 Deployment 资源 | 本地模拟,运行时展开为 Session | +| Memory Store | 官方 API 支持跨 Session 持久化、版本化记忆,可只读/读写挂载;每 Session 最多 8 个 | **能力缺口:尚未接入**,因此 OpenAgentPack 中仍为 `unsupported` | 官方提供记忆库 CRUD,以及记忆创建、批量创建、枚举、查询、更新、删除 | 已实现记忆库创建、删除和 Session 挂载;枚举、查询、更新及记忆内容操作尚未接入 | + +主要依据:[Claude API 总览](https://platform.claude.com/docs/en/api/overview)、[Claude Managed Agents 总览](https://platform.claude.com/docs/en/managed-agents/overview)、[Session Event Stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming)、[Skills](https://platform.claude.com/docs/en/managed-agents/skills)、[Multi-Agent](https://platform.claude.com/docs/en/managed-agents/multi-agent)、[Scheduled Deployments](https://platform.claude.com/docs/en/managed-agents/scheduled-deployments)、[Memory Stores](https://platform.claude.com/docs/en/managed-agents/memory),以及[火山方舟 Managed Agents API 参考](https://console.volcengine.com/ark/region:cn-beijing/docs/82379/2555910?lang=zh)。 + +方舟官方目录还揭示了维护者需要区分的两类差距:Session 更新/Resource/Thread、Vault 更新与 Credential 生命周期、完整 Memory Store 操作属于“上游已有但 Adapter 尚未暴露”;Skill 只有创建和查询则是上游当前生命周期本身较窄,并非单纯漏实现。 + +#### 后续维护规则 + +新增 Provider 或可选 Adapter 方法时: + +1. 在 `capabilities.ts` 更新资源级支持,并补齐对应生命周期方法。 +2. 逐项核对 `ProviderAdapter` 的可选方法(枚举、sync/export、drift、文件、Skill、模型和 Session Event 恢复),同步更新本表。 +3. 在 Adapter 注释中记录 API 端点或实测行为,并区分“上游 API 限制”和“本项目尚未实现”。 +4. 运行 `bun test scripts/provider-docs.test.ts`;测试会同时校验资源矩阵和 Adapter 可选方法行,防止文档随代码漂移。 + +#### Provider 文档索引 + +刷新能力矩阵或新增 Adapter 方法时,优先从这些官方入口重新核验。不要只依据本仓库已有实现反推平台能力。 + +| Provider | 主要来源 | 辅助来源 | 备注 | +|----------|----------|----------|------| +| 百炼 | [Managed Agents 快速开始](https://help.aliyun.com/zh/model-studio/managed-agents-quick-start) | [百炼文档首页](https://www.alibabacloud.com/help/zh/model-studio/)、[智能体应用指南](https://help.aliyun.com/zh/model-studio/single-agent-application) | 快速开始展示了本 Adapter 使用的 `/api/v1/agentstudio` 端点族。 | +| Qoder | [Cloud Agents API overview](https://docs.qoder.com/cloud-agents/api/conventions/overview) | [Cloud Agents overview](https://docs.qoder.com/cloud-agents/overview)、[Agent Skills](https://docs.qoder.com/cloud-agents/skills)、[Cloud Agents marketplace skill](https://qoder.com/marketplace/skill?id=official_FjWvobU0) | API 文档是 gateway、鉴权头、资源、分页和事件流的主要依据。 | +| Claude | [Claude API 总览](https://platform.claude.com/docs/en/api/overview) | [Managed Agents 总览](https://platform.claude.com/docs/en/managed-agents/overview)、[Session Event Stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming)、[Skills](https://platform.claude.com/docs/en/managed-agents/skills)、[Multi-Agent](https://platform.claude.com/docs/en/managed-agents/multi-agent)、[Scheduled Deployments](https://platform.claude.com/docs/en/managed-agents/scheduled-deployments)、[Memory Stores](https://platform.claude.com/docs/en/managed-agents/memory) | API 总览用于确认 GA/beta 状态;Managed Agents 页面用于确认资源行为。 | +| 火山方舟 | [Managed Agents API 参考](https://console.volcengine.com/ark/region:cn-beijing/docs/82379/2555910?lang=zh) | [火山方舟文档中心](https://docs.volcengine.com/docs/82379)、[API Key 管理](https://www.volcengine.com/docs/6257/64983?lang=en) | Console API 参考是 `/api/v3` 资源目录依据,也确认 Deployment 不是一级资源。 | + ### Drift Detection 支持 `plan` / `apply` 默认刷新远端状态。支持完整 drift detection 的资源会读取远端可比较内容并与上次 apply 的期望状态比较;检测到 drift 时,普通 `apply` 会把远端收敛回 YAML。其他资源会降级为存在性检查或标记为未检查。 @@ -64,8 +129,8 @@ Claude 的 drift detection 接口路径已预留;本仓库中的 live baseline ``` claude.memory_store.unsupported: - no memory store primitive on Claude. - use skill knowledge or MCP for context persistence + Claude exposes Memory Stores, but the OpenAgentPack adapter has not implemented them yet. + use skill knowledge or MCP until Claude Memory Store support is added to the adapter qoder.multiagent.unsupported: no multiagent primitive on Qoder. @@ -241,12 +306,3 @@ Claude 和 Qoder 的内置工具命名风格不同: | 网页获取 | `web_fetch` | `WebFetch` | OpenAgentPack 的 Adapter 层会自动处理这些差异,在配置中请使用目标 Provider 的原生命名。 - -## 数据来源 - -开发 Provider 适配器时,以下为各平台的官方 API 参考: - -| Provider | 数据来源 | 说明 | -|----------|----------|------| -| Claude | https://platform.claude.com/llms.txt | Claude Platform API 规范 | -| Qoder | https://qoder.com/marketplace/skill?id=official_FjWvobU0 | Qoder Cloud Agents Skill 文档 | diff --git a/packages/sdk/src/internal/providers/claude/capabilities.ts b/packages/sdk/src/internal/providers/claude/capabilities.ts index 026987b..d040e22 100644 --- a/packages/sdk/src/internal/providers/claude/capabilities.ts +++ b/packages/sdk/src/internal/providers/claude/capabilities.ts @@ -7,8 +7,8 @@ export const CLAUDE_CAPABILITIES: ProviderCapabilities = { agent: { tier: "native", reason: "managed agents API" }, memory_store: { tier: "unsupported", - reason: "no memory store primitive on Claude", - remediation: "use skill knowledge or MCP for context persistence", + reason: "Claude exposes Memory Stores, but the OpenAgentPack adapter has not implemented them yet", + remediation: "use skill knowledge or MCP until Claude Memory Store support is added to the adapter", }, mcp_server: { tier: "native", reason: "mcp_servers field on agent" }, multiagent: { tier: "native", reason: "coordinator + roster topology" }, diff --git a/scripts/provider-docs.test.ts b/scripts/provider-docs.test.ts index 01cde43..ab72cfb 100644 --- a/scripts/provider-docs.test.ts +++ b/scripts/provider-docs.test.ts @@ -1,9 +1,13 @@ import { describe, expect, test } from "bun:test"; import { readFileSync } from "node:fs"; import { resolve } from "node:path"; +import { ArkAdapter } from "../packages/sdk/src/internal/providers/ark/adapter.ts"; import { ARK_CAPABILITIES } from "../packages/sdk/src/internal/providers/ark/capabilities.ts"; +import { BailianAdapter } from "../packages/sdk/src/internal/providers/bailian/adapter.ts"; import { BAILIAN_CAPABILITIES } from "../packages/sdk/src/internal/providers/bailian/capabilities.ts"; +import { ClaudeAdapter } from "../packages/sdk/src/internal/providers/claude/adapter.ts"; import { CLAUDE_CAPABILITIES } from "../packages/sdk/src/internal/providers/claude/capabilities.ts"; +import { QoderAdapter } from "../packages/sdk/src/internal/providers/qoder/adapter.ts"; import { QODER_CAPABILITIES } from "../packages/sdk/src/internal/providers/qoder/capabilities.ts"; const root = resolve(import.meta.dirname, ".."); @@ -39,3 +43,30 @@ describe("canonical provider capability tables", () => { }); } }); + +const referenceDocs = ["docs/reference/providers.md", "docs/reference/providers.zh-CN.md"]; +const adapterPrototypes = [ + BailianAdapter.prototype, + QoderAdapter.prototype, + ClaudeAdapter.prototype, + ArkAdapter.prototype, +]; +const optionalMethodRows = [ + ["List skills", "枚举 Skill", "listSkills"], + ["Download skill source during `sync`", "`sync` 时下载 Skill 源文件", "downloadAllSkillFiles"], + ["Non-blocking skill creation for Web UI polling", "Web UI 非阻塞创建 Skill 并轮询", "createSkillFromFileId"], + ["List provider models", "枚举 Provider 模型", "listModels"], +] as const; + +describe("provider adapter implementation tables", () => { + for (const file of referenceDocs) { + test(`${file} matches optional adapter methods`, () => { + const markdown = readFileSync(resolve(root, file), "utf8").replaceAll("**", ""); + for (const [englishLabel, chineseLabel, method] of optionalMethodRows) { + const cells = adapterPrototypes.map((prototype) => (method in prototype ? "yes" : "no")).join(" | "); + const label = file.endsWith("zh-CN.md") ? chineseLabel : englishLabel; + expect(markdown).toContain(`| ${label} | ${cells} |`); + } + }); + } +});