Skip to content

feat: ListModels 填充 OpenRouter 与 Anthropic 的模型元数据 - #128

Open
sheepbox8646 wants to merge 1 commit into
mainfrom
feat/twi-15-openrouter-model-metadata
Open

sheepbox8646 wants to merge 1 commit into
mainfrom
feat/twi-15-openrouter-model-metadata

Conversation

@sheepbox8646

Copy link
Copy Markdown
Member

概要

sdk.Model 已经有 Modalities、ContextWindow、MaxOutputTokens、ToolCall、StructuredOutput、Reasoning 等元数据字段,但没有任何 provider 填充它们。completions 与 responses 指向 OpenRouter 时,列出的 462 个模型全部没有元数据。Anthropic Messages 指向 OpenRouter 时只列出 20 个模型,原因是它不分页。

  • 共享 /models 解析:新增 internal/openaimodels,completions 与 responses 共用,替换原来两份重复的类型。识别 OpenRouter 的扩展字段:
    • ContextWindow:取 context_length,缺失时用 top_provider.context_length。
    • MaxOutputTokens:取 top_provider.max_completion_tokens。
    • Modalities:取 architecture.input_modalities 与 output_modalities,file 映射为 pdf。
    • ToolCall:supported_parameters 含 tools。
    • StructuredOutput:只认 structured_outputs。单有 response_format 不算,因为它可能只是不带 schema 的 JSON mode。
    • Reasoning:结合 supported_parameters 与模型的 reasoning 对象(mandatory、default_enabled、supported_efforts、default_effort、supports_max_tokens),填入 Efforts、Budget、Off 和 Default。
    • DisplayName 与 Description:取 name 与 description。
  • 字段不存在时保持零值:OpenAI 官方 /models 的解析结果不变。扩展字段类型对不上时,只丢弃该模型的元数据,不会让整个列表失败。
  • 不过滤模型:fix: filter chat model discovery by endpoint capability #119 的过滤已被 Revert "fix: filter chat model discovery by endpoint capability" #121 回滚,本 PR 只填充元数据。
  • Anthropic 分页:
    • 以 limit=1000 请求,has_more 为真时用 last_id 作 after_id 继续翻页。
    • 本页没有新模型、没有游标或游标不前进时停止。最多读 100 页。
    • 首页因 limit 被拒(400 或 422)时,不带 limit 重试一次,兼容上限更低的兼容服务。原实现不发送 limit,所以这里需要回退。
    • Anthropic 官方 /v1/models 同样默认每页 20 个,所以这个问题不止影响 OpenRouter。
  • Anthropic 元数据:
    • ContextWindow 取 max_input_tokens。Claude 的输出与输入共用同一个上下文窗口,所以输入上限就是整个窗口。
    • MaxOutputTokens 取 max_tokens。
    • capabilities 中的 image_input、pdf_input、structured_outputs、thinking、effort 映射到模态、结构化输出与推理。
    • capabilities 里没有工具调用这一项,所以 ToolCall 保持 false。
  • 文档:docs/providers.md 补充了映射规则与分页说明,docs/api-reference.md 更新了 Model 的说明。

关联

验证

  • 新增单元测试:
    • OpenRouter 映射,用 7 个从真实响应裁剪的样本。
    • OpenAI 官方格式的结果不变,只有 ID 与 Provider。
    • 扩展字段类型错误时丢弃该模型的元数据,不让列表失败。
    • completions 与 responses 的端到端测试。
    • Anthropic 跨 3 页分页,校验 limit 与 after_id 的序列。
    • 游标不前进、缺少 last_id。
    • 首页 limit 被拒后不带 limit 重试;后续页出错不重试。
    • 官方 capabilities 映射。
  • 本地运行 go build ./...、go vet ./...、go vet -tags integration ./...、go test ./... -short -count=1 -race、internal/sdkdiff 的测试、golangci-lint run ./...,全部通过。go mod tidy 无变化。
  • 真实接口(OpenRouter):
provider 模型数 ContextWindow MaxOutputTokens Modalities ToolCall StructuredOutput Reasoning
completions 462 462 454 462 393 382 332
responses 462 462 454 462 393 382 332
anthropic messages 426(修复前 20) 426 393 0 0 0 0

OpenRouter 的 Anthropic 兼容端点 capabilities 全是 null,所以没有模态与推理信息。

  • 样本:anthropic/claude-sonnet-5.5 上下文 1000000、输出 128000,输入 text、image、pdf,支持工具与结构化输出,effort 为 low 到 max。openai/gpt-4o 上下文 128000、输出 16384,Reasoning 为 nil。

未验证与已知限制

  • 没有 OpenAI 官方与 Anthropic 官方的 Key。OpenAI 官方样本按已知格式手写。Anthropic 带 capabilities 的样本按官方文档 schema 手写,没有用真实官方响应验证。
  • OpenRouter 的 Anthropic 兼容端点填写 max_input_tokens 不统一。例如 openai/gpt-5.5 报 922000,即总窗口减去最大输出。这种情况下 ContextWindow 会偏小,偏保守。代码注释与文档中已说明。

🤖 Generated with Claude Code

completions 与 responses 的 ListModels 改用共享的 internal/openaimodels 解析 /models,OpenRouter 的 context_length、top_provider.max_completion_tokens、architecture 模态、supported_parameters 与 reasoning 对象会映射到 sdk.Model 元数据;字段不存在时保持零值,OpenAI 官方结果不变。

Anthropic Messages 的 ListModels 原来不分页,只拿到第一页 20 个模型。现在以 limit=1000 按 has_more/after_id 翻页,首页因 limit 被拒(400/422)时不带 limit 重试一次;并把 max_input_tokens、max_tokens、capabilities 映射为元数据。

Linear: TWI-15

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant