mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-07 17:09:13 -10:00
fix(tui): gate the OrcaRouter offer by region and disclose its terms (§46)
Hide the OrcaRouter offer row and F7 shortcut in zh-Hans (mainland), keep
it for zh-Hant and other locales, and disclose the offer terms in the
picker and docs/PROVIDERS.md. Localized in all 15 packs. Re-derived the
web agent-docs JSON from HEAD plus this patch only.
Patch authored by the Living Codewhale logo session.
Verified on the Boat farm (Linux, local tests, base 5ba1aa63 overlay):
codewhale-localization 55 passed, 0 failed; codewhale-tui --lib
provider_picker model_picker orca_offer 202 passed, 0 failed. Rerun on
this exact tree follows before push.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
deefd0e0f8
commit
b3d18fe6bc
21 files changed
+94
-27
No files matched your search
@@ -17,6 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- **OrcaRouter offer:** no longer shown when Codewhale is in Simplified Chinese
|
||||
or your computer is set to mainland China, and its note now says the link is
|
||||
part of a referral campaign.
|
||||
- **Website:** recovered warm paper, clear-blue actions and original drawn water accents; added Computer Use and automatically refreshed terminal/plugin release links; shortened copy, clarified contribution paths and checked setup guidance against published versions.
|
||||
|
||||
## [0.10.3] - 2026-11-06
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · Recomanat",
|
||||
"OrcaRouterOfferAction": "Mostra l’oferta d’OrcaRouter a /provider o /model",
|
||||
"OrcaRouterOfferBody": "Aconsegueix un 30% de crèdit addicional per a DeepSeek V4.1 Flash en les recàrregues amb l’oferta Codewhale × OrcaRouter. Consulta les condicions vigents a la pàgina de l’oferta.",
|
||||
"OrcaRouterOfferDisclosure": "Codewhale rep una comissió de recomanació d’OrcaRouter.",
|
||||
"OrcaRouterOfferDisclosure": "Aquest enllaç forma part d’una campanya de referits; Codewhale pot rebre una recompensa per les recàrregues fetes a través seu.",
|
||||
"ShellWaitNoActive": "No s'està esperant cap ordre de l'intèrpret.",
|
||||
"ShellWaitInteractive": "Les ordres interactives no poden continuar en segon pla. Cancel·la el torn o espera que acabin.",
|
||||
"ShellWaitUnavailable": "Aquesta eina no pot continuar en segon pla. Cancel·la el torn o espera que acabi.",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · Empfohlen",
|
||||
"OrcaRouterOfferAction": "OrcaRouter-Angebot in /provider oder /model anzeigen",
|
||||
"OrcaRouterOfferBody": "Erhalte mit dem Angebot Codewhale × OrcaRouter bei Aufladungen 30% zusätzliches Guthaben für DeepSeek V4.1 Flash. Die aktuellen Bedingungen stehen auf der Angebotsseite.",
|
||||
"OrcaRouterOfferDisclosure": "Codewhale erhält von OrcaRouter eine Vermittlungsprovision.",
|
||||
"OrcaRouterOfferDisclosure": "Dieser Link gehört zu einer Empfehlungsaktion; Codewhale erhält für Aufladungen über diesen Link möglicherweise eine Prämie.",
|
||||
"ShellWaitNoActive": "Aktuell wird auf keinen Shell-Befehl gewartet.",
|
||||
"ShellWaitInteractive": "Interaktive Befehle können nicht im Hintergrund weiterlaufen. Brich den aktuellen Durchgang ab oder warte, bis der Befehl fertig ist.",
|
||||
"ShellWaitUnavailable": "Dieses Werkzeug kann nicht im Hintergrund weiterlaufen. Brich den aktuellen Durchgang ab oder warte, bis es fertig ist.",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · Recommended",
|
||||
"OrcaRouterOfferAction": "View OrcaRouter offer in /provider or /model",
|
||||
"OrcaRouterOfferBody": "Get a 30% top-up match for DeepSeek V4.1 Flash with the Codewhale × OrcaRouter offer. Check the offer page for current terms.",
|
||||
"OrcaRouterOfferDisclosure": "Codewhale earns a referral fee from OrcaRouter.",
|
||||
"OrcaRouterOfferDisclosure": "This link is part of a referral campaign; Codewhale may earn a referral reward on top-ups made through it.",
|
||||
"ShellWaitNoActive": "No shell wait is active.",
|
||||
"ShellWaitInteractive": "Interactive commands cannot continue in the background. Cancel the turn, or wait for completion.",
|
||||
"ShellWaitUnavailable": "This tool cannot continue in the background. Cancel the turn, or wait for completion.",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · Recomendado",
|
||||
"OrcaRouterOfferAction": "Ver oferta de OrcaRouter en /provider o /model",
|
||||
"OrcaRouterOfferBody": "Obtén un 30% de crédito extra para DeepSeek V4.1 Flash en tus recargas con la oferta Codewhale × OrcaRouter. Consulta las condiciones vigentes en la página de la oferta.",
|
||||
"OrcaRouterOfferDisclosure": "Codewhale recibe una comisión por recomendación de OrcaRouter.",
|
||||
"OrcaRouterOfferDisclosure": "Este enlace forma parte de una campaña de referidos; Codewhale puede recibir una recompensa por las recargas hechas a través de él.",
|
||||
"ShellWaitNoActive": "No hay ninguna espera de shell activa.",
|
||||
"ShellWaitInteractive": "Los comandos interactivos no pueden continuar en segundo plano. Cancela el turno o espera a que terminen.",
|
||||
"ShellWaitUnavailable": "Esta herramienta no puede continuar en segundo plano. Cancela el turno o espera a que termine.",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · Recommandé",
|
||||
"OrcaRouterOfferAction": "Voir l’offre OrcaRouter dans /provider ou /model",
|
||||
"OrcaRouterOfferBody": "Obtenez 30% de crédit supplémentaire pour DeepSeek V4.1 Flash sur vos recharges avec l’offre Codewhale × OrcaRouter. Consultez les conditions en vigueur sur la page de l’offre.",
|
||||
"OrcaRouterOfferDisclosure": "Codewhale reçoit une commission de recommandation d’OrcaRouter.",
|
||||
"OrcaRouterOfferDisclosure": "Ce lien fait partie d’une campagne de parrainage ; Codewhale peut recevoir une récompense sur les recharges effectuées par ce lien.",
|
||||
"ShellWaitNoActive": "Aucune attente de commande shell en cours.",
|
||||
"ShellWaitInteractive": "Les commandes interactives ne peuvent pas continuer en arrière-plan. Annulez le tour ou attendez la fin de la commande.",
|
||||
"ShellWaitUnavailable": "Cet outil ne peut pas continuer en arrière-plan. Annulez le tour ou attendez la fin de son exécution.",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · सुझाया गया",
|
||||
"OrcaRouterOfferAction": "/provider या /model में OrcaRouter का ऑफ़र देखें",
|
||||
"OrcaRouterOfferBody": "Codewhale × OrcaRouter ऑफ़र के साथ टॉप-अप पर DeepSeek V4.1 Flash के लिए 30% अतिरिक्त क्रेडिट पाएँ। मौजूदा शर्तों के लिए ऑफ़र पेज देखें।",
|
||||
"OrcaRouterOfferDisclosure": "Codewhale को OrcaRouter से रेफ़रल शुल्क मिलता है।",
|
||||
"OrcaRouterOfferDisclosure": "यह लिंक एक रेफ़रल अभियान का हिस्सा है; इसके ज़रिए किए गए टॉप-अप पर Codewhale को रेफ़रल इनाम मिल सकता है।",
|
||||
"ShellWaitNoActive": "अभी किसी शेल कमांड के पूरा होने का इंतज़ार नहीं हो रहा है।",
|
||||
"ShellWaitInteractive": "इंटरैक्टिव कमांड बैकग्राउंड में जारी नहीं रह सकतीं। इस बारी को रद्द करें या कमांड पूरी होने की प्रतीक्षा करें।",
|
||||
"ShellWaitUnavailable": "यह टूल बैकग्राउंड में जारी नहीं रह सकता। इस बारी को रद्द करें या इसके पूरा होने की प्रतीक्षा करें।",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · Direkomendasikan",
|
||||
"OrcaRouterOfferAction": "Lihat penawaran OrcaRouter di /provider atau /model",
|
||||
"OrcaRouterOfferBody": "Dapatkan tambahan kredit DeepSeek V4.1 Flash sebesar 30% dari isi ulang melalui penawaran Codewhale × OrcaRouter. Lihat ketentuan terbaru di halaman penawaran.",
|
||||
"OrcaRouterOfferDisclosure": "Codewhale menerima komisi rujukan dari OrcaRouter.",
|
||||
"OrcaRouterOfferDisclosure": "Tautan ini bagian dari kampanye rujukan; Codewhale mungkin menerima imbalan atas isi ulang yang dilakukan melalui tautan ini.",
|
||||
"ShellWaitNoActive": "Tidak ada perintah shell yang sedang ditunggu.",
|
||||
"ShellWaitInteractive": "Perintah interaktif tidak dapat berjalan di latar belakang. Batalkan giliran atau tunggu hingga selesai.",
|
||||
"ShellWaitUnavailable": "Alat ini tidak dapat berjalan di latar belakang. Batalkan giliran atau tunggu hingga selesai.",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · おすすめ",
|
||||
"OrcaRouterOfferAction": "/provider または /model で OrcaRouter の特典を表示",
|
||||
"OrcaRouterOfferBody": "Codewhale × OrcaRouter の特典で、DeepSeek V4.1 Flash 向けチャージ額の30%が追加されます。最新の条件は特典ページでご確認ください。",
|
||||
"OrcaRouterOfferDisclosure": "Codewhale は OrcaRouter から紹介料を受け取ります。",
|
||||
"OrcaRouterOfferDisclosure": "このリンクは紹介キャンペーンの一部です。このリンク経由のチャージに対して、Codewhale が紹介報酬を受け取る場合があります。",
|
||||
"ShellWaitNoActive": "待機中のシェルコマンドはありません。",
|
||||
"ShellWaitInteractive": "対話型コマンドはバックグラウンドで続行できません。ターンをキャンセルするか、完了をお待ちください。",
|
||||
"ShellWaitUnavailable": "このツールはバックグラウンドで続行できません。ターンをキャンセルするか、完了をお待ちください。",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · 추천",
|
||||
"OrcaRouterOfferAction": "/provider 또는 /model에서 OrcaRouter 혜택 보기",
|
||||
"OrcaRouterOfferBody": "Codewhale × OrcaRouter 혜택으로 충전 금액의 30%를 DeepSeek V4.1 Flash 크레딧으로 추가 적립하세요. 최신 조건은 혜택 페이지에서 확인하세요.",
|
||||
"OrcaRouterOfferDisclosure": "Codewhale은 OrcaRouter로부터 추천 수수료를 받습니다.",
|
||||
"OrcaRouterOfferDisclosure": "이 링크는 추천 캠페인의 일부이며, 이 링크를 통한 충전에 대해 Codewhale이 추천 보상을 받을 수 있습니다.",
|
||||
"ShellWaitNoActive": "현재 완료를 기다리는 셸 명령이 없습니다.",
|
||||
"ShellWaitInteractive": "대화형 명령은 백그라운드에서 계속 실행할 수 없습니다. 턴을 취소하거나 명령이 완료될 때까지 기다리세요.",
|
||||
"ShellWaitUnavailable": "이 도구는 백그라운드에서 계속 실행할 수 없습니다. 턴을 취소하거나 완료될 때까지 기다리세요.",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · Recomendado",
|
||||
"OrcaRouterOfferAction": "Ver oferta da OrcaRouter em /provider ou /model",
|
||||
"OrcaRouterOfferBody": "Receba 30% de crédito extra para DeepSeek V4.1 Flash nas recargas com a oferta Codewhale × OrcaRouter. Confira os termos atuais na página da oferta.",
|
||||
"OrcaRouterOfferDisclosure": "A Codewhale recebe uma comissão por indicação da OrcaRouter.",
|
||||
"OrcaRouterOfferDisclosure": "Este link faz parte de uma campanha de indicação; a Codewhale pode receber uma recompensa pelas recargas feitas por meio dele.",
|
||||
"ShellWaitNoActive": "Não há espera ativa por um comando do shell.",
|
||||
"ShellWaitInteractive": "Comandos interativos não podem continuar em segundo plano. Cancele o turno ou aguarde a conclusão.",
|
||||
"ShellWaitUnavailable": "Esta ferramenta não pode continuar em segundo plano. Cancele o turno ou aguarde a conclusão.",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · Рекомендуем",
|
||||
"OrcaRouterOfferAction": "Посмотреть предложение OrcaRouter в /provider или /model",
|
||||
"OrcaRouterOfferBody": "Получите 30% дополнительного кредита для DeepSeek V4.1 Flash при пополнении по предложению Codewhale × OrcaRouter. Актуальные условия указаны на странице предложения.",
|
||||
"OrcaRouterOfferDisclosure": "Codewhale получает от OrcaRouter комиссию за рекомендации.",
|
||||
"OrcaRouterOfferDisclosure": "Эта ссылка — часть реферальной кампании; Codewhale может получить вознаграждение за пополнения, сделанные по ней.",
|
||||
"ShellWaitNoActive": "Сейчас нет ожидания команды оболочки.",
|
||||
"ShellWaitInteractive": "Интерактивные команды не могут продолжать работу в фоне. Отмените ход или дождитесь завершения команды.",
|
||||
"ShellWaitUnavailable": "Этот инструмент не может продолжать работу в фоне. Отмените ход или дождитесь его завершения.",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · Рекомендуємо",
|
||||
"OrcaRouterOfferAction": "Переглянути пропозицію OrcaRouter у /provider або /model",
|
||||
"OrcaRouterOfferBody": "Отримайте 30% додаткового кредиту для DeepSeek V4.1 Flash за поповнення з пропозицією Codewhale × OrcaRouter. Актуальні умови наведено на сторінці пропозиції.",
|
||||
"OrcaRouterOfferDisclosure": "Codewhale отримує від OrcaRouter комісію за рекомендації.",
|
||||
"OrcaRouterOfferDisclosure": "Це посилання є частиною реферальної кампанії; Codewhale може отримати винагороду за поповнення, зроблені через нього.",
|
||||
"ShellWaitNoActive": "Зараз немає очікування команди оболонки.",
|
||||
"ShellWaitInteractive": "Інтерактивні команди не можуть продовжувати роботу у фоні. Скасуйте хід або дочекайтеся завершення команди.",
|
||||
"ShellWaitUnavailable": "Цей інструмент не може продовжувати роботу у фоні. Скасуйте хід або дочекайтеся його завершення.",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · Đề xuất",
|
||||
"OrcaRouterOfferAction": "Xem ưu đãi OrcaRouter trong /provider hoặc /model",
|
||||
"OrcaRouterOfferBody": "Nhận thêm 30% tín dụng DeepSeek V4.1 Flash khi nạp tiền với ưu đãi Codewhale × OrcaRouter. Xem điều kiện hiện hành trên trang ưu đãi.",
|
||||
"OrcaRouterOfferDisclosure": "Codewhale nhận phí giới thiệu từ OrcaRouter.",
|
||||
"OrcaRouterOfferDisclosure": "Liên kết này thuộc một chiến dịch giới thiệu; Codewhale có thể nhận thưởng cho các lần nạp tiền qua liên kết này.",
|
||||
"ShellWaitNoActive": "Không có lệnh shell nào đang được chờ.",
|
||||
"ShellWaitInteractive": "Lệnh tương tác không thể tiếp tục chạy nền. Hãy hủy lượt hoặc chờ lệnh hoàn tất.",
|
||||
"ShellWaitUnavailable": "Công cụ này không thể tiếp tục chạy nền. Hãy hủy lượt hoặc chờ công cụ hoàn tất.",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · 推荐",
|
||||
"OrcaRouterOfferAction": "在 /provider 或 /model 中查看 OrcaRouter 优惠",
|
||||
"OrcaRouterOfferBody": "通过 Codewhale × OrcaRouter 优惠,充值可额外获得 30% 的 DeepSeek V4.1 Flash 额度。最新条款请查看优惠页面。",
|
||||
"OrcaRouterOfferDisclosure": "Codewhale 会从 OrcaRouter 获得推荐佣金。",
|
||||
"OrcaRouterOfferDisclosure": "此链接属于一项推广活动;通过此链接充值时,Codewhale 可能获得推广奖励。",
|
||||
"ShellWaitNoActive": "当前没有正在等待的 shell 命令。",
|
||||
"ShellWaitInteractive": "交互式命令无法在后台继续运行。请取消当前回合,或等待命令完成。",
|
||||
"ShellWaitUnavailable": "此工具无法在后台继续运行。请取消当前回合,或等待它完成。",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"OrcaRouterOfferRecommended": "OrcaRouter · 推薦",
|
||||
"OrcaRouterOfferAction": "在 /provider 或 /model 中查看 OrcaRouter 優惠",
|
||||
"OrcaRouterOfferBody": "透過 Codewhale × OrcaRouter 優惠,儲值可額外獲得 30% 的 DeepSeek V4.1 Flash 額度。最新條款請查看優惠頁面。",
|
||||
"OrcaRouterOfferDisclosure": "Codewhale 會從 OrcaRouter 獲得推薦佣金。",
|
||||
"OrcaRouterOfferDisclosure": "此連結屬於一項推廣活動;透過此連結儲值時,Codewhale 可能獲得推廣獎勵。",
|
||||
"ShellWaitNoActive": "目前沒有正在等待的 shell 命令。",
|
||||
"ShellWaitInteractive": "互動式命令無法在背景繼續執行。請取消目前回合,或等待命令完成。",
|
||||
"ShellWaitUnavailable": "此工具無法在背景繼續執行。請取消目前回合,或等待它完成。",
|
||||
|
||||
@@ -72,6 +72,7 @@ pub mod mouse_ui;
|
||||
pub mod notifications;
|
||||
pub mod ocean;
|
||||
pub mod onboarding;
|
||||
pub mod orca_offer;
|
||||
pub mod output_rows_cache;
|
||||
pub mod pager;
|
||||
pub mod paste;
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
//! The Codewhale × OrcaRouter offer. It is hidden when the interface is in
|
||||
//! Simplified Chinese or the computer is set to a mainland China time zone or
|
||||
//! locale. A VPN, a remote shell or a time zone set by hand elsewhere is not
|
||||
//! detected.
|
||||
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use codewhale_localization::Locale;
|
||||
|
||||
pub(crate) const OFFER_URL: &str =
|
||||
"https://www.orcarouter.ai/redeem/1a6250545fdc4e0aaccb0a4470159e67";
|
||||
|
||||
const MAINLAND_ZONES: &[&str] = &[
|
||||
"Asia/Shanghai",
|
||||
"Asia/Chongqing",
|
||||
"Asia/Chungking",
|
||||
"Asia/Harbin",
|
||||
"Asia/Urumqi",
|
||||
"Asia/Kashgar",
|
||||
"PRC",
|
||||
];
|
||||
|
||||
pub(crate) fn available(locale: Locale) -> bool {
|
||||
locale != Locale::ZhHans && !mainland_china()
|
||||
}
|
||||
|
||||
fn mainland_china() -> bool {
|
||||
static MAINLAND: OnceLock<bool> = OnceLock::new();
|
||||
*MAINLAND.get_or_init(|| {
|
||||
let zone = std::env::var("TZ")
|
||||
.ok()
|
||||
.filter(|zone| !zone.is_empty())
|
||||
.or_else(|| {
|
||||
std::fs::read_link("/etc/localtime")
|
||||
.ok()
|
||||
.map(|link| link.to_string_lossy().into_owned())
|
||||
});
|
||||
let locale = ["LC_ALL", "LC_MESSAGES", "LANG"]
|
||||
.iter()
|
||||
.filter_map(|name| std::env::var(name).ok())
|
||||
.find(|value| !value.is_empty());
|
||||
mainland(zone.as_deref(), locale.as_deref())
|
||||
})
|
||||
}
|
||||
|
||||
fn mainland(zone: Option<&str>, locale: Option<&str>) -> bool {
|
||||
let zone_is_mainland = zone.is_some_and(|zone| {
|
||||
let zone = zone.trim_start_matches(':');
|
||||
MAINLAND_ZONES.iter().any(|name| {
|
||||
zone == *name
|
||||
|| zone
|
||||
.strip_suffix(name)
|
||||
.is_some_and(|prefix| prefix.ends_with('/'))
|
||||
})
|
||||
});
|
||||
let locale_is_mainland = locale.is_some_and(|value| {
|
||||
let tag = value.split(['.', '@']).next().unwrap_or_default();
|
||||
tag.ends_with("_CN") || tag.ends_with("-CN")
|
||||
});
|
||||
zone_is_mainland || locale_is_mainland
|
||||
}
|
||||
@@ -75,9 +75,6 @@ use codewhale_config::descriptors::defaults::{
|
||||
DS4_BASE_URL, DS4_DEFAULT_MODEL, LM_STUDIO_BASE_URL,
|
||||
};
|
||||
|
||||
pub(crate) const ORCAROUTER_OFFER_URL: &str =
|
||||
"https://www.orcarouter.ai/redeem/1a6250545fdc4e0aaccb0a4470159e67";
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct ProviderOffer {
|
||||
hitbox: RefCell<Option<Rect>>,
|
||||
@@ -93,18 +90,20 @@ impl ProviderOffer {
|
||||
ViewAction::Emit(ViewEvent::OpenTextPager {
|
||||
title: tr(locale, MessageId::OrcaRouterOfferRecommended).into_owned(),
|
||||
content: format!(
|
||||
"{}\n\n{}\n\n{ORCAROUTER_OFFER_URL}",
|
||||
"{}\n\n{}\n\n{}",
|
||||
tr(locale, MessageId::OrcaRouterOfferBody),
|
||||
tr(locale, MessageId::OrcaRouterOfferDisclosure),
|
||||
crate::tui::orca_offer::OFFER_URL,
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn key_action(locale: Locale, key: &KeyEvent) -> Option<ViewAction> {
|
||||
crate::tui::shell_key_routing::binding(
|
||||
crate::tui::shell_key_routing::ShellBindingId::ProviderOffer,
|
||||
)
|
||||
.matches(key)
|
||||
(crate::tui::orca_offer::available(locale)
|
||||
&& crate::tui::shell_key_routing::binding(
|
||||
crate::tui::shell_key_routing::ShellBindingId::ProviderOffer,
|
||||
)
|
||||
.matches(key))
|
||||
.then(|| Self::open(locale))
|
||||
}
|
||||
|
||||
@@ -121,7 +120,7 @@ impl ProviderOffer {
|
||||
|
||||
pub(crate) fn render(&self, locale: Locale, area: Rect, buf: &mut Buffer) -> Rect {
|
||||
self.clear();
|
||||
if area.height < 4 || area.width < 20 {
|
||||
if area.height < 4 || area.width < 20 || !crate::tui::orca_offer::available(locale) {
|
||||
return area;
|
||||
}
|
||||
let chord = crate::tui::shell_key_routing::display_chord(
|
||||
|
||||
+4
-1
@@ -15,10 +15,13 @@ The `/provider` and `/model` pickers recommend OrcaRouter as a partner option.
|
||||
Click the recommendation or press F7 to view the Codewhale × OrcaRouter offer:
|
||||
a **30% top-up match for DeepSeek V4.1 Flash**. The pager includes the
|
||||
[redemption link](https://www.orcarouter.ai/redeem/1a6250545fdc4e0aaccb0a4470159e67)
|
||||
and can copy its text. Codewhale earns a referral fee from OrcaRouter.
|
||||
and can copy its text. This link is part of a referral campaign; Codewhale may
|
||||
earn a referral reward on top-ups made through it.
|
||||
Current eligibility and terms are owned by the linked offer page. Viewing it
|
||||
preserves the current provider, model and credentials; redemption happens on
|
||||
OrcaRouter's site.
|
||||
The recommendation is not shown when the interface is in Simplified Chinese or
|
||||
the computer is set to a mainland China time zone or locale.
|
||||
|
||||
DeepSeek remains the default provider, but every entry in `ProviderKind::ALL`
|
||||
is a first-class selectable provider route. `ALL` is the catalog/picker
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
"sources": [
|
||||
{
|
||||
"path": "docs/PROVIDERS.md",
|
||||
"sha256": "109ae691105d322a97b0540731715ad0accc3d9eb4f20cb456b8e6d67739e5f8",
|
||||
"content": "# Provider Registry\n\n> 阅读简体中文版:[zh_hans/PROVIDERS.md](zh_hans/PROVIDERS.md)\n\nSpeech recognition, synthesis, translation and video have separate execution\npaths. See [media models](MEDIA_MODELS.md) for current support and reviewed\nupstream candidates; a chat catalogue row alone does not add a media backend.\n\nThis registry describes provider behavior that is wired into the current\nCodewhale codebase. It is intentionally conservative: shipped entries are\nlimited to provider IDs, config keys, auth paths, base URLs, model resolution,\nand capability metadata that the code already knows about.\n\nThe `/provider` and `/model` pickers recommend OrcaRouter as a partner option.\nClick the recommendation or press F7 to view the Codewhale × OrcaRouter offer:\na **30% top-up match for DeepSeek V4.1 Flash**. The pager includes the\n[redemption link](https://www.orcarouter.ai/redeem/1a6250545fdc4e0aaccb0a4470159e67)\nand can copy its text. Codewhale earns a referral fee from OrcaRouter.\nCurrent eligibility and terms are owned by the linked offer page. Viewing it\npreserves the current provider, model and credentials; redemption happens on\nOrcaRouter's site.\n\nDeepSeek remains the default provider, but every entry in `ProviderKind::ALL`\nis a first-class selectable provider route. `ALL` is the catalog/picker\nsurface — one identity per vendor. Dual-wire dialect kinds (`*Anthropic`, e.g.\n`deepseek-anthropic`) and the Model Studio plan variants stay on the enum for\nserde and `provider_for_kind` but are deliberately **not** catalog rows:\na plan is `mode`/`base_url` and a dialect is `wire = openai|anthropic` on the\nprimary provider config (`crates/config/src/provider_kind.rs:221-226`). Hosted\nroutes, generic OpenAI-compatible endpoints, the OpenAI Codex/ChatGPT route,\nnative Anthropic, and local runtimes all run the same terminal harness against\nthe selected provider/model/base URL.\n\nA host reached over plain Chat Completions is an ordinary named provider,\nnot a `ProviderKind`: enum variants are reserved for distinct *wires*\n(Anthropic Messages, Codex Responses, Google thought signatures). Any such\nhost is a `[providers.<name>]` table with a base URL, a model, and a key env\n(`docs/CONFIGURATION.md`); `/provider` and `/setup` keep a \"paste a Base URL\nand a key\" path for exactly this. Where available, offerings come from live\n`GET /v1/models` plus the Codewhale catalog (#5350, #6289).\n\nBundled compatible hosts. These ship as descriptor rows in\n`crates/config/assets/provider_descriptors.json` (compiled in by\n`crates/config/src/descriptors.rs`): each row says how to reach the host — wire,\nbase URL, key env, aliases — while model IDs come from configured models, the\nCodewhale catalog, and a live `GET /v1/models` when supported. The example model\nis only a bootstrap hint. Verify\nagainst the vendor's own docs before trusting any value here:\n\n| Host | Base URL | Example models | API key env |\n| --- | --- | --- | --- |\n| Thinking Machines Tinker (beta) | `https://tinker.thinkingmachines.dev/services/tinker-prod/oai/api/v1` | `thinkingmachines/Inkling-2-Small:peft:262144:sampling-nvfp4` | `TINKER_API_KEY` |\n| SenseNova | `https://token.sensenova.cn/v1` | `deepseek-v4-flash` | `SENSENOVA_API_KEY` |\n| Baseten | `https://inference.baseten.co/v1` | `deepseek-ai/DeepSeek-V4-Pro` | `BASETEN_API_KEY` |\n| Groq | `https://api.groq.com/openai/v1` | `llama-3.3-70b-versatile` | `GROQ_API_KEY` |\n| Cerebras | `https://api.cerebras.ai/v1` | `llama-3.3-70b` | `CEREBRAS_API_KEY` |\n| Command Code | `https://api.commandcode.ai/provider/v1` | `deepseek/deepseek-v4-flash` | `COMMAND_CODE_API_KEY` |\n| Alibaba Model Studio (DashScope) | `https://dashscope-intl.aliyuncs.com/compatible-mode/v1` | `qwen3.8-flash` | `DASHSCOPE_API_KEY` |\n| AICraft | `https://aicraftapi.com/v1` | `claude-4.6-sonnet`; DeepSeek / Claude / Gemini / Qwen / GLM / MiniMax / Doubao families | `AICRAFT_API_KEY` |\n| Tsubasa | `https://api.tsubasa.sh/v1` | `tsubasa-pro`, `tsubasa-fast` (32,768-token context) | `TSUBASA_API_KEY` |\n| Cheaper Inference | `https://api.cheaperinference.com/v1` | `gpt-5.4-mini`, `claude-sonnet-5`, `gemini-3.1-pro` | `CHEAPER_INFERENCE_API_KEY` |\n| Yolo-Auto | `https://yolo-auto.com/v1` | `qwen3.8-flash`; `yolo` / `yolo-small` | `YOLO_AUTO_API_KEY` |\n| Standard Compute | `https://api.stdcmpt.com/v1` | `standardcompute` (router); `deepseek/deepseek-v4-pro`, `anthropic/claude-sonnet-5.5` | `STANDARDCOMPUTE_API_KEY` |\n| Runcrate | `https://api.runcrate.ai/v1` | `deepseek-ai/DeepSeek-V4.1-Flash`, `zai-org/GLM-5.3`, `openai/gpt-oss-120b` | `RUNCRATE_API_KEY` |\n| Opper | `https://api.opper.ai/v3/compat` | `claude-sonnet-4-6`, `gpt-5.4-mini` (pool names); `anthropic/claude-sonnet-4-6` | `OPPER_API_KEY` |\n| Tencent TokenHub | `https://tokenhub-intl.tencentcloudmaas.com/v1` | `hy4` | `TENCENT_API_KEY` |\n\nTinker's OpenAI-compatible API and serverless inference are beta. SelLine truncated
|
||||
"sha256": "57dece0ceb6ba40a64cfc504f175de4749ff704084634a566533f4c70b863789",
|
||||
"content": "# Provider Registry\n\n> 阅读简体中文版:[zh_hans/PROVIDERS.md](zh_hans/PROVIDERS.md)\n\nSpeech recognition, synthesis, translation and video have separate execution\npaths. See [media models](MEDIA_MODELS.md) for current support and reviewed\nupstream candidates; a chat catalogue row alone does not add a media backend.\n\nThis registry describes provider behavior that is wired into the current\nCodewhale codebase. It is intentionally conservative: shipped entries are\nlimited to provider IDs, config keys, auth paths, base URLs, model resolution,\nand capability metadata that the code already knows about.\n\nThe `/provider` and `/model` pickers recommend OrcaRouter as a partner option.\nClick the recommendation or press F7 to view the Codewhale × OrcaRouter offer:\na **30% top-up match for DeepSeek V4.1 Flash**. The pager includes the\n[redemption link](https://www.orcarouter.ai/redeem/1a6250545fdc4e0aaccb0a4470159e67)\nand can copy its text. This link is part of a referral campaign; Codewhale may\nearn a referral reward on top-ups made through it.\nCurrent eligibility and terms are owned by the linked offer page. Viewing it\npreserves the current provider, model and credentials; redemption happens on\nOrcaRouter's site.\nThe recommendation is not shown when the interface is in Simplified Chinese or\nthe computer is set to a mainland China time zone or locale.\n\nDeepSeek remains the default provider, but every entry in `ProviderKind::ALL`\nis a first-class selectable provider route. `ALL` is the catalog/picker\nsurface — one identity per vendor. Dual-wire dialect kinds (`*Anthropic`, e.g.\n`deepseek-anthropic`) and the Model Studio plan variants stay on the enum for\nserde and `provider_for_kind` but are deliberately **not** catalog rows:\na plan is `mode`/`base_url` and a dialect is `wire = openai|anthropic` on the\nprimary provider config (`crates/config/src/provider_kind.rs:221-226`). Hosted\nroutes, generic OpenAI-compatible endpoints, the OpenAI Codex/ChatGPT route,\nnative Anthropic, and local runtimes all run the same terminal harness against\nthe selected provider/model/base URL.\n\nA host reached over plain Chat Completions is an ordinary named provider,\nnot a `ProviderKind`: enum variants are reserved for distinct *wires*\n(Anthropic Messages, Codex Responses, Google thought signatures). Any such\nhost is a `[providers.<name>]` table with a base URL, a model, and a key env\n(`docs/CONFIGURATION.md`); `/provider` and `/setup` keep a \"paste a Base URL\nand a key\" path for exactly this. Where available, offerings come from live\n`GET /v1/models` plus the Codewhale catalog (#5350, #6289).\n\nBundled compatible hosts. These ship as descriptor rows in\n`crates/config/assets/provider_descriptors.json` (compiled in by\n`crates/config/src/descriptors.rs`): each row says how to reach the host — wire,\nbase URL, key env, aliases — while model IDs come from configured models, the\nCodewhale catalog, and a live `GET /v1/models` when supported. The example model\nis only a bootstrap hint. Verify\nagainst the vendor's own docs before trusting any value here:\n\n| Host | Base URL | Example models | API key env |\n| --- | --- | --- | --- |\n| Thinking Machines Tinker (beta) | `https://tinker.thinkingmachines.dev/services/tinker-prod/oai/api/v1` | `thinkingmachines/Inkling-2-Small:peft:262144:sampling-nvfp4` | `TINKER_API_KEY` |\n| SenseNova | `https://token.sensenova.cn/v1` | `deepseek-v4-flash` | `SENSENOVA_API_KEY` |\n| Baseten | `https://inference.baseten.co/v1` | `deepseek-ai/DeepSeek-V4-Pro` | `BASETEN_API_KEY` |\n| Groq | `https://api.groq.com/openai/v1` | `llama-3.3-70b-versatile` | `GROQ_API_KEY` |\n| Cerebras | `https://api.cerebras.ai/v1` | `llama-3.3-70b` | `CEREBRAS_API_KEY` |\n| Command Code | `https://api.commandcode.ai/provider/v1` | `deepseek/deepseek-v4-flash` | `COMMAND_CODE_API_KEY` |\n| Alibaba Model Studio (DashScope) | `https://dashscope-intl.aliyuncs.com/compatible-mode/v1` | `qwen3.8-flash` | `DASHSCOPE_API_KEY` |\n| AICraft | `https://aicraftapi.com/v1` | `claude-4.6-sonnet`; DeepSeek / Claude / Gemini / Qwen / GLM / MiniMax / Doubao families | `AICRAFT_API_KEY` |\n| Tsubasa | `https://api.tsubasa.sh/v1` | `tsubasa-pro`, `tsubasa-fast` (32,768-token context) | `TSUBASA_API_KEY` |\n| Cheaper Inference | `https://api.cheaperinference.com/v1` | `gpt-5.4-mini`, `claude-sonnet-5`, `gemini-3.1-pro` | `CHEAPER_INFERENCE_API_KEY` |\n| Yolo-Auto | `https://yolo-auto.com/v1` | `qwen3.8-flash`; `yolo` / `yolo-small` | `YOLO_AUTO_API_KEY` |\n| Standard Compute | `https://api.stdcmpt.com/v1` | `standardcompute` (router); `deepseek/deepseek-v4-pro`, `anthropic/claude-sonnet-5.5` | `STANDARDCOMPUTE_API_KEY` |\n| Runcrate | `https://api.runcrate.ai/v1` | `deepseek-ai/DeepSeek-V4.1-Flash`, `zai-org/GLM-5.3`, `openai/gpt-oss-120b` | `RUNCRATE_API_KEY` |\n| Opper | `https://api.opper.ai/v3/compat` | `claude-sonnet-4-6`, `gpt-5.4-mini` (pool names); `anthropic/claude-soLine truncated
|
||||
},
|
||||
{
|
||||
"path": "docs/MODEL_LAB.md",
|
||||
|
||||
Reference in new issue
Block a user