mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-08 17:10:50 -10:00
feat(providers): add a Tsubasa descriptor on the compatible transport (#6695)
Tsubasa gets one bundled row in provider_descriptors.json on the existing OpenAI-compatible Chat Completions path, as @cenab proposed and the founder approved: base https://api.tsubasa.sh/v1, key env TSUBASA_API_KEY, bootstrap model tsubasa-pro, docs https://tsubasa.sh/docs. No new ProviderKind, no transport, no prices, capabilities or underlying-model claims. Discovery stays `models_endpoint`, like every neighbouring row: Tsubasa's published API contract (tsubasa.sh/docs) names GET /v1/models as the catalog authority, and the live 404 is not specific to discovery — on 2026-09-28 POST /v1/chat/completions also returned 404 without a key, and the public model page lists both models as Disabled. The descriptor schema has no context or output fields, so the 32,768-token window and the second public id (tsubasa-fast) reach the user through the row's guidance and docs/PROVIDERS.md, with the exact `codewhale config set providers.tsubasa.context_window 32768` command (an unknown custom model otherwise budgets 128,000 tokens). Pricing default-coverage ledger records the route as unknown billing basis and the compatible-default breadth receipt moves from 7 to 8. Tests (focused): - cargo test -p codewhale-config --lib -- descriptors route::export: 9 passed; 0 failed; 1 ignored (new tsubasa_is_a_compatible_row_with_its_own_key; golden_providers_export_matches_registry passes, golden unchanged) - cargo test -p codewhale-tui --lib pricing::default_coverage_tests: 1 passed; 0 failed - cargo test -p codewhale-tui --lib provider_picker: 148 passed; 0 failed - scripts/check-provider-registry.py: passed - cargo fmt --all -- --check: clean Closes #6695 Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_014ZwqatxgVFxHvovngywnks
This commit is contained in:
1 parent
11b2c18777
commit
0466194c7e
6 files changed
+41
-4
No files matched your search
@@ -102,6 +102,17 @@
|
||||
"meituan-sensenova",
|
||||
"meituan-sensenova-cn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "tsubasa",
|
||||
"label": "Tsubasa",
|
||||
"wire": "openai-compatible",
|
||||
"base_url": "https://api.tsubasa.sh/v1",
|
||||
"api_key_env": "TSUBASA_API_KEY",
|
||||
"default_model": "tsubasa-pro",
|
||||
"discovery": "models_endpoint",
|
||||
"docs_url": "https://tsubasa.sh/docs",
|
||||
"guidance": "OpenAI-compatible host (Chat Completions + GET /v1/models only). Public model ids: tsubasa-pro and tsubasa-fast, both with a 32,768-token context, so set context_window = 32768 on [providers.tsubasa]. Store TSUBASA_API_KEY, not a raw key."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -153,6 +153,26 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// #6695: Tsubasa is a data row on the existing compatible transport with
|
||||
/// its own key env. The row carries no context field, so the guidance is
|
||||
/// where the 32K window and the second public model id reach the user.
|
||||
#[test]
|
||||
fn tsubasa_is_a_compatible_row_with_its_own_key() {
|
||||
let tsubasa = provider_descriptor("tsubasa").expect("tsubasa");
|
||||
assert_eq!(tsubasa.wire, DescriptorWire::OpenaiCompatible);
|
||||
assert_eq!(tsubasa.base_url, "https://api.tsubasa.sh/v1");
|
||||
assert_eq!(tsubasa.api_key_env, "TSUBASA_API_KEY");
|
||||
assert_eq!(tsubasa.default_model, "tsubasa-pro");
|
||||
let guidance = tsubasa.guidance.as_deref().expect("tsubasa guidance");
|
||||
for needle in [
|
||||
"tsubasa-fast",
|
||||
"context_window = 32768",
|
||||
"Store TSUBASA_API_KEY",
|
||||
] {
|
||||
assert!(guidance.contains(needle), "{needle}: {guidance}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn descriptors_do_not_embed_model_rosters() {
|
||||
let raw = DESCRIPTORS_JSON;
|
||||
|
||||
@@ -123,7 +123,7 @@ fn shipped_default_routes_have_reviewed_pricing_coverage() {
|
||||
assert_eq!(built_in_count, 51, "review changed shipped-default breadth");
|
||||
assert_eq!(
|
||||
defaults.len() - built_in_count,
|
||||
7,
|
||||
8,
|
||||
"review compatible-default breadth"
|
||||
);
|
||||
let recorded_at = Utc.with_ymd_and_hms(2026, 9, 8, 12, 0, 0).unwrap();
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
},
|
||||
{
|
||||
"reason": "unknown_billing_basis",
|
||||
"review": "No mode/credential product is supplied. Both MiniMax dialects share a PAYG/plan endpoint that cannot prove product (route_billing.rs:253,402; pricing.rs:534); Ollama Cloud is unclassified possible spend, not local/free (pricing.rs:411). Generic Custom and six non-Baseten compatible defaults are transport descriptors without a reviewed product; production envelope refuses Unknown at cost_status.rs:239. AICraft is the sixth compatible default: dc170add3 restored its row from the closed PR #6171 with endpoint, credential env and bootstrap model only, and no billing product or pricing row was reviewed for it. Its default is claude-4.6-sonnet, which has no bundled/hand row either; that omission is recorded here on the shape of the descriptor, and a real source review of AICraft's billing basis is still owed.",
|
||||
"review": "No mode/credential product is supplied. Both MiniMax dialects share a PAYG/plan endpoint that cannot prove product (route_billing.rs:253,402; pricing.rs:534); Ollama Cloud is unclassified possible spend, not local/free (pricing.rs:411). Generic Custom and seven non-Baseten compatible defaults are transport descriptors without a reviewed product; production envelope refuses Unknown at cost_status.rs:239. AICraft is the sixth compatible default: dc170add3 restored its row from the closed PR #6171 with endpoint, credential env and bootstrap model only, and no billing product or pricing row was reviewed for it. Its default is claude-4.6-sonnet, which has no bundled/hand row either; that omission is recorded here on the shape of the descriptor, and a real source review of AICraft's billing basis is still owed. Tsubasa (#6695) is the seventh: endpoint, credential env and bootstrap model tsubasa-pro only; its public site lists prepaid-credit per-token rates, but no pricing row was reviewed or frozen for it, so it stays Unknown here too.",
|
||||
"routes": [
|
||||
["aicraft", "claude-4.6-sonnet", "https://aicraftapi.com/v1", "chat_completions", "unknown"],
|
||||
["cerebras", "llama-3.3-70b", "https://api.cerebras.ai/v1", "chat_completions", "unknown"],
|
||||
@@ -47,7 +47,8 @@
|
||||
["minimax", "MiniMax-M3", "https://api.minimax.io/v1", "chat_completions", "unknown"],
|
||||
["minimax-anthropic", "MiniMax-M3", "https://api.minimax.io/anthropic", "anthropic_messages", "unknown"],
|
||||
["ollama-cloud", "gpt-oss:120b", "https://ollama.com/v1", "chat_completions", "unknown"],
|
||||
["sensenova", "deepseek-v4-flash", "https://token.sensenova.cn/v1", "chat_completions", "unknown"]
|
||||
["sensenova", "deepseek-v4-flash", "https://token.sensenova.cn/v1", "chat_completions", "unknown"],
|
||||
["tsubasa", "tsubasa-pro", "https://api.tsubasa.sh/v1", "chat_completions", "unknown"]
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -42,11 +42,16 @@ against the vendor's own docs before trusting any value here:
|
||||
| Command Code | `https://api.commandcode.ai/provider/v1` | `deepseek/deepseek-v4-flash` | `COMMAND_CODE_API_KEY` |
|
||||
| Alibaba Model Studio (DashScope) | `https://dashscope-intl.aliyuncs.com/compatible-mode/v1` | `qwen3.8-flash` | `DASHSCOPE_API_KEY` |
|
||||
| AICraft | `https://aicraftapi.com/v1` | `claude-4.6-sonnet`; DeepSeek / Claude / Gemini / Qwen / GLM / MiniMax / Doubao families | `AICRAFT_API_KEY` |
|
||||
| Tsubasa | `https://api.tsubasa.sh/v1` | `tsubasa-pro`, `tsubasa-fast` (32,768-token context) | `TSUBASA_API_KEY` |
|
||||
|
||||
AICraft's roster spans DeepSeek, Anthropic Claude, Google Gemini, Qwen, GLM,
|
||||
MiniMax and Doubao ids on its OpenAI-compatible endpoint. The authority is
|
||||
`GET https://aicraftapi.com/v1/models` with your key — pick a model from that
|
||||
list, not from this table.
|
||||
Tsubasa implements only `GET /v1/models` and Chat Completions. Its two public
|
||||
model ids share a 32,768-token context, smaller than the 128,000 tokens Codewhale assumes
|
||||
for an unknown model, so set it on the route after saving:
|
||||
`codewhale config set providers.tsubasa.context_window 32768`.
|
||||
OpenCode Zen and OpenCode Go are first-class provider routes, configured like
|
||||
any other provider below; they are not part of this table. In `/provider`,
|
||||
type to filter the list (letters not bound to a row action); `Ctrl+T` probes the
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
DeepSeek 仍是默认提供商,但 `ProviderKind::ALL` 中的每个条目都是一等公民、可选的提供商路由。`ALL` 是目录/选择器表面——每个厂商一个身份。双线协议方言种类(`*Anthropic`,例如 `deepseek-anthropic`)和 Model Studio 套餐变体保留在枚举中用于 serde 和 `provider_for_kind`,但刻意**不**作为目录行:套餐是主提供商配置(`crates/config/src/provider_kind.rs:221-226`)上的 `mode`/`base_url`,方言则是 `wire = openai|anthropic`。托管路由、通用 OpenAI 兼容端点、OpenAI Codex/ChatGPT 路由、原生 Anthropic 以及本地运行时,都在所选提供商/模型/base URL 上运行同一个终端 harness。
|
||||
|
||||
经普通 Chat Completions 访问的主机是普通的具名 provider(`[providers.<name>]` 表:base URL、模型、密钥环境变量),而不是 `ProviderKind`;`/provider` 与 `/setup` 保留「粘贴 Base URL 和密钥」路径。英文版中的「已知可用主机」表列出 SenseNova、Baseten、Groq、Cerebras、Command Code、阿里云百炼(DashScope)与 AICraft 的 URL 和密钥变量;这些主机作为内置描述符行随附于 `crates/config/assets/provider_descriptors.json`(仅描述如何连接主机,模型 ID 以实时 `GET /v1/models` 与 Codewhale 目录为准),仅供参考,请以各厂商文档为准。AICraft 的模型列表涵盖 DeepSeek、Anthropic Claude、Google Gemini、Qwen、GLM、MiniMax 与 Doubao(例如 `claude-4.6-sonnet`),以带密钥请求 `GET https://aicraftapi.com/v1/models` 的结果为准。OpenCode Zen 与 OpenCode Go 是下方的一等路由。在 `/provider` 中直接输入即可筛选列表(已绑定行操作的字母除外);`Ctrl+T` 探测所选行的 `/models`,只记录可达性(2xx 并不代表模型可用)。
|
||||
经普通 Chat Completions 访问的主机是普通的具名 provider(`[providers.<name>]` 表:base URL、模型、密钥环境变量),而不是 `ProviderKind`;`/provider` 与 `/setup` 保留「粘贴 Base URL 和密钥」路径。英文版中的「已知可用主机」表列出 SenseNova、Baseten、Groq、Cerebras、Command Code、阿里云百炼(DashScope)、AICraft 与 Tsubasa 的 URL 和密钥变量;这些主机作为内置描述符行随附于 `crates/config/assets/provider_descriptors.json`(仅描述如何连接主机,模型 ID 以实时 `GET /v1/models` 与 Codewhale 目录为准),仅供参考,请以各厂商文档为准。AICraft 的模型列表涵盖 DeepSeek、Anthropic Claude、Google Gemini、Qwen、GLM、MiniMax 与 Doubao(例如 `claude-4.6-sonnet`),以带密钥请求 `GET https://aicraftapi.com/v1/models` 的结果为准。Tsubasa(`https://api.tsubasa.sh/v1`,`TSUBASA_API_KEY`)仅实现 `GET /v1/models` 与 Chat Completions,公开模型 `tsubasa-pro` 与 `tsubasa-fast` 的上下文均为 32,768 tokens;保存后请执行 `codewhale config set providers.tsubasa.context_window 32768`。OpenCode Zen 与 OpenCode Go 是下方的一等路由。在 `/provider` 中直接输入即可筛选列表(已绑定行操作的字母除外);`Ctrl+T` 探测所选行的 `/models`,只记录可达性(2xx 并不代表模型可用)。
|
||||
|
||||
需要保持同步的来源:
|
||||
|
||||
|
||||
Reference in new issue
Block a user