From e9643a67f1f90bf1d1c6eb67e1c19e931a837c54 Mon Sep 17 00:00:00 2001 From: Barack Sokullu Date: Thu, 23 Jul 2026 17:12:06 +0300 Subject: [PATCH 1/2] Add 76 LLM providers and Ask streaming --- README.fr.md | 11 +- README.md | 10 +- README.zh-CN.md | 9 +- docs/fr/providers-and-models.md | 48 +++ docs/providers-and-models.md | 95 +++-- docs/zh-CN/providers-and-models.md | 42 +++ src/chrome/icons/providers/302ai.svg | 7 + src/chrome/icons/providers/SOURCES.md | 1 + src/chrome/icons/providers/abacus.svg | 14 + src/chrome/icons/providers/aihubmix.svg | 3 + .../providers/alibaba-coding-plan-cn.svg | 3 + .../icons/providers/alibaba-coding-plan.svg | 3 + .../providers/azure-cognitive-services.svg | 24 ++ src/chrome/icons/providers/bailing.svg | 3 + src/chrome/icons/providers/baseten.svg | 3 + src/chrome/icons/providers/berget.svg | 3 + src/chrome/icons/providers/cerebras.svg | 4 + src/chrome/icons/providers/chutes.svg | 24 ++ src/chrome/icons/providers/clarifai.svg | 24 ++ .../icons/providers/cloudferro-sherlock.svg | 5 + src/chrome/icons/providers/cohere.svg | 5 + src/chrome/icons/providers/cortecs.svg | 24 ++ src/chrome/icons/providers/deepinfra.svg | 4 + src/chrome/icons/providers/digitalocean.svg | 6 + src/chrome/icons/providers/dinference.svg | 1 + src/chrome/icons/providers/drun.svg | 8 + src/chrome/icons/providers/evroc.svg | 3 + src/chrome/icons/providers/fastrouter.svg | 3 + src/chrome/icons/providers/friendli.svg | 3 + .../providers/google-vertex-anthropic.svg | 24 ++ src/chrome/icons/providers/google-vertex.svg | 10 + src/chrome/icons/providers/helicone.svg | 6 + src/chrome/icons/providers/iflowcn.svg | 3 + src/chrome/icons/providers/inception.svg | 4 + src/chrome/icons/providers/inference.svg | 3 + src/chrome/icons/providers/io-net.svg | 5 + src/chrome/icons/providers/jiekou.svg | 4 + src/chrome/icons/providers/kilo.svg | 4 + .../icons/providers/kimi-for-coding.svg | 3 + .../providers/kuae-cloud-coding-plan.svg | 3 + src/chrome/icons/providers/llama.svg | 3 + src/chrome/icons/providers/lucidquery.svg | 3 + src/chrome/icons/providers/meganova.svg | 3 + .../providers/minimax-cn-coding-plan.svg | 24 ++ .../icons/providers/minimax-coding-plan.svg | 24 ++ src/chrome/icons/providers/moark.svg | 3 + src/chrome/icons/providers/modelscope.svg | 5 + src/chrome/icons/providers/morph.svg | 24 ++ src/chrome/icons/providers/nano-gpt.svg | 3 + src/chrome/icons/providers/nebius.svg | 4 + src/chrome/icons/providers/nova.svg | 3 + src/chrome/icons/providers/novita-ai.svg | 10 + src/chrome/icons/providers/ollama-cloud.svg | 7 + src/chrome/icons/providers/opencode-go.svg | 3 + src/chrome/icons/providers/opencode.svg | 3 + src/chrome/icons/providers/ovhcloud.svg | 3 + .../icons/providers/perplexity-agent.svg | 3 + src/chrome/icons/providers/perplexity.svg | 3 + src/chrome/icons/providers/poe.svg | 7 + src/chrome/icons/providers/privatemode-ai.svg | 5 + src/chrome/icons/providers/qihang-ai.svg | 9 + src/chrome/icons/providers/qiniu-ai.svg | 7 + src/chrome/icons/providers/requesty.svg | 24 ++ src/chrome/icons/providers/scaleway.svg | 5 + src/chrome/icons/providers/siliconflow-cn.svg | 3 + src/chrome/icons/providers/siliconflow.svg | 3 + src/chrome/icons/providers/stackit.svg | 4 + src/chrome/icons/providers/stepfun.svg | 24 ++ src/chrome/icons/providers/submodel.svg | 3 + src/chrome/icons/providers/synthetic.svg | 24 ++ .../icons/providers/tencent-coding-plan.svg | 5 + src/chrome/icons/providers/upstage.svg | 24 ++ src/chrome/icons/providers/v0.svg | 3 + src/chrome/icons/providers/venice.svg | 4 + src/chrome/icons/providers/vercel.svg | 3 + src/chrome/icons/providers/vivgrid.svg | 4 + src/chrome/icons/providers/vultr.svg | 6 + src/chrome/icons/providers/wandb.svg | 24 ++ src/chrome/icons/providers/xiaomi.svg | 3 + .../icons/providers/zai-coding-plan.svg | 3 + src/chrome/icons/providers/zenmux.svg | 4 + .../icons/providers/zhipuai-coding-plan.svg | 3 + src/chrome/icons/providers/zhipuai.svg | 3 + src/chrome/src/agent/agent.js | 39 ++ src/chrome/src/providers/anthropic.js | 18 +- src/chrome/src/providers/base.js | 9 + src/chrome/src/providers/manager.js | 18 +- src/chrome/src/providers/openai.js | 74 +++- src/chrome/src/providers/provider-catalog.js | 148 ++++++++ .../src/providers/provider-compatibility.js | 1 + src/chrome/src/providers/vertex-anthropic.js | 63 ++++ src/chrome/src/ui/locales/ar.js | 5 +- src/chrome/src/ui/locales/bn.js | 5 +- src/chrome/src/ui/locales/de.js | 5 +- src/chrome/src/ui/locales/en.js | 3 +- src/chrome/src/ui/locales/es.js | 5 +- src/chrome/src/ui/locales/fa.js | 5 +- src/chrome/src/ui/locales/fr.js | 5 +- src/chrome/src/ui/locales/he.js | 5 +- src/chrome/src/ui/locales/hi.js | 5 +- src/chrome/src/ui/locales/id.js | 5 +- src/chrome/src/ui/locales/ja.js | 5 +- src/chrome/src/ui/locales/ko.js | 5 +- src/chrome/src/ui/locales/ms.js | 5 +- src/chrome/src/ui/locales/nl.js | 5 +- src/chrome/src/ui/locales/pl.js | 5 +- src/chrome/src/ui/locales/pt.js | 5 +- src/chrome/src/ui/locales/ru.js | 5 +- src/chrome/src/ui/locales/th.js | 5 +- src/chrome/src/ui/locales/tl.js | 5 +- src/chrome/src/ui/locales/tr.js | 3 +- src/chrome/src/ui/locales/uk.js | 5 +- src/chrome/src/ui/locales/vi.js | 5 +- src/chrome/src/ui/locales/zh.js | 5 +- src/chrome/src/ui/provider-icons.js | 9 + src/chrome/src/ui/settings.js | 46 +++ src/chrome/src/ui/sidepanel.js | 3 + src/firefox/icons/providers/302ai.svg | 7 + src/firefox/icons/providers/SOURCES.md | 1 + src/firefox/icons/providers/abacus.svg | 14 + src/firefox/icons/providers/aihubmix.svg | 3 + .../providers/alibaba-coding-plan-cn.svg | 3 + .../icons/providers/alibaba-coding-plan.svg | 3 + .../providers/azure-cognitive-services.svg | 24 ++ src/firefox/icons/providers/bailing.svg | 3 + src/firefox/icons/providers/baseten.svg | 3 + src/firefox/icons/providers/berget.svg | 3 + src/firefox/icons/providers/cerebras.svg | 4 + src/firefox/icons/providers/chutes.svg | 24 ++ src/firefox/icons/providers/clarifai.svg | 24 ++ .../icons/providers/cloudferro-sherlock.svg | 5 + src/firefox/icons/providers/cohere.svg | 5 + src/firefox/icons/providers/cortecs.svg | 24 ++ src/firefox/icons/providers/deepinfra.svg | 4 + src/firefox/icons/providers/digitalocean.svg | 6 + src/firefox/icons/providers/dinference.svg | 1 + src/firefox/icons/providers/drun.svg | 8 + src/firefox/icons/providers/evroc.svg | 3 + src/firefox/icons/providers/fastrouter.svg | 3 + src/firefox/icons/providers/friendli.svg | 3 + .../providers/google-vertex-anthropic.svg | 24 ++ src/firefox/icons/providers/google-vertex.svg | 10 + src/firefox/icons/providers/helicone.svg | 6 + src/firefox/icons/providers/iflowcn.svg | 3 + src/firefox/icons/providers/inception.svg | 4 + src/firefox/icons/providers/inference.svg | 3 + src/firefox/icons/providers/io-net.svg | 5 + src/firefox/icons/providers/jiekou.svg | 4 + src/firefox/icons/providers/kilo.svg | 4 + .../icons/providers/kimi-for-coding.svg | 3 + .../providers/kuae-cloud-coding-plan.svg | 3 + src/firefox/icons/providers/llama.svg | 3 + src/firefox/icons/providers/lucidquery.svg | 3 + src/firefox/icons/providers/meganova.svg | 3 + .../providers/minimax-cn-coding-plan.svg | 24 ++ .../icons/providers/minimax-coding-plan.svg | 24 ++ src/firefox/icons/providers/moark.svg | 3 + src/firefox/icons/providers/modelscope.svg | 5 + src/firefox/icons/providers/morph.svg | 24 ++ src/firefox/icons/providers/nano-gpt.svg | 3 + src/firefox/icons/providers/nebius.svg | 4 + src/firefox/icons/providers/nova.svg | 3 + src/firefox/icons/providers/novita-ai.svg | 10 + src/firefox/icons/providers/ollama-cloud.svg | 7 + src/firefox/icons/providers/opencode-go.svg | 3 + src/firefox/icons/providers/opencode.svg | 3 + src/firefox/icons/providers/ovhcloud.svg | 3 + .../icons/providers/perplexity-agent.svg | 3 + src/firefox/icons/providers/perplexity.svg | 3 + src/firefox/icons/providers/poe.svg | 7 + .../icons/providers/privatemode-ai.svg | 5 + src/firefox/icons/providers/qihang-ai.svg | 9 + src/firefox/icons/providers/qiniu-ai.svg | 7 + src/firefox/icons/providers/requesty.svg | 24 ++ src/firefox/icons/providers/scaleway.svg | 5 + .../icons/providers/siliconflow-cn.svg | 3 + src/firefox/icons/providers/siliconflow.svg | 3 + src/firefox/icons/providers/stackit.svg | 4 + src/firefox/icons/providers/stepfun.svg | 24 ++ src/firefox/icons/providers/submodel.svg | 3 + src/firefox/icons/providers/synthetic.svg | 24 ++ .../icons/providers/tencent-coding-plan.svg | 5 + src/firefox/icons/providers/upstage.svg | 24 ++ src/firefox/icons/providers/v0.svg | 3 + src/firefox/icons/providers/venice.svg | 4 + src/firefox/icons/providers/vercel.svg | 3 + src/firefox/icons/providers/vivgrid.svg | 4 + src/firefox/icons/providers/vultr.svg | 6 + src/firefox/icons/providers/wandb.svg | 24 ++ src/firefox/icons/providers/xiaomi.svg | 3 + .../icons/providers/zai-coding-plan.svg | 3 + src/firefox/icons/providers/zenmux.svg | 4 + .../icons/providers/zhipuai-coding-plan.svg | 3 + src/firefox/icons/providers/zhipuai.svg | 3 + src/firefox/src/agent/agent.js | 39 ++ src/firefox/src/providers/anthropic.js | 18 +- src/firefox/src/providers/base.js | 9 + src/firefox/src/providers/manager.js | 18 +- src/firefox/src/providers/openai.js | 74 +++- src/firefox/src/providers/provider-catalog.js | 148 ++++++++ .../src/providers/provider-compatibility.js | 1 + src/firefox/src/providers/vertex-anthropic.js | 63 ++++ src/firefox/src/ui/locales/ar.js | 5 +- src/firefox/src/ui/locales/bn.js | 5 +- src/firefox/src/ui/locales/de.js | 5 +- src/firefox/src/ui/locales/en.js | 3 +- src/firefox/src/ui/locales/es.js | 5 +- src/firefox/src/ui/locales/fa.js | 5 +- src/firefox/src/ui/locales/fr.js | 5 +- src/firefox/src/ui/locales/he.js | 5 +- src/firefox/src/ui/locales/hi.js | 5 +- src/firefox/src/ui/locales/id.js | 5 +- src/firefox/src/ui/locales/ja.js | 5 +- src/firefox/src/ui/locales/ko.js | 5 +- src/firefox/src/ui/locales/ms.js | 5 +- src/firefox/src/ui/locales/nl.js | 5 +- src/firefox/src/ui/locales/pl.js | 5 +- src/firefox/src/ui/locales/pt.js | 5 +- src/firefox/src/ui/locales/ru.js | 5 +- src/firefox/src/ui/locales/th.js | 5 +- src/firefox/src/ui/locales/tl.js | 5 +- src/firefox/src/ui/locales/tr.js | 3 +- src/firefox/src/ui/locales/uk.js | 5 +- src/firefox/src/ui/locales/vi.js | 5 +- src/firefox/src/ui/locales/zh.js | 5 +- src/firefox/src/ui/provider-icons.js | 9 + src/firefox/src/ui/settings.js | 46 +++ src/firefox/src/ui/sidepanel.js | 3 + test/run.js | 343 +++++++++++++++++- web/docs/providers/index.html | 6 +- web/docs/zh/providers/index.html | 5 +- 231 files changed, 2662 insertions(+), 155 deletions(-) create mode 100644 src/chrome/icons/providers/302ai.svg create mode 100644 src/chrome/icons/providers/abacus.svg create mode 100644 src/chrome/icons/providers/aihubmix.svg create mode 100644 src/chrome/icons/providers/alibaba-coding-plan-cn.svg create mode 100644 src/chrome/icons/providers/alibaba-coding-plan.svg create mode 100644 src/chrome/icons/providers/azure-cognitive-services.svg create mode 100644 src/chrome/icons/providers/bailing.svg create mode 100644 src/chrome/icons/providers/baseten.svg create mode 100644 src/chrome/icons/providers/berget.svg create mode 100644 src/chrome/icons/providers/cerebras.svg create mode 100644 src/chrome/icons/providers/chutes.svg create mode 100644 src/chrome/icons/providers/clarifai.svg create mode 100644 src/chrome/icons/providers/cloudferro-sherlock.svg create mode 100644 src/chrome/icons/providers/cohere.svg create mode 100644 src/chrome/icons/providers/cortecs.svg create mode 100644 src/chrome/icons/providers/deepinfra.svg create mode 100644 src/chrome/icons/providers/digitalocean.svg create mode 100644 src/chrome/icons/providers/dinference.svg create mode 100644 src/chrome/icons/providers/drun.svg create mode 100644 src/chrome/icons/providers/evroc.svg create mode 100644 src/chrome/icons/providers/fastrouter.svg create mode 100644 src/chrome/icons/providers/friendli.svg create mode 100644 src/chrome/icons/providers/google-vertex-anthropic.svg create mode 100644 src/chrome/icons/providers/google-vertex.svg create mode 100644 src/chrome/icons/providers/helicone.svg create mode 100644 src/chrome/icons/providers/iflowcn.svg create mode 100644 src/chrome/icons/providers/inception.svg create mode 100644 src/chrome/icons/providers/inference.svg create mode 100644 src/chrome/icons/providers/io-net.svg create mode 100644 src/chrome/icons/providers/jiekou.svg create mode 100644 src/chrome/icons/providers/kilo.svg create mode 100644 src/chrome/icons/providers/kimi-for-coding.svg create mode 100644 src/chrome/icons/providers/kuae-cloud-coding-plan.svg create mode 100644 src/chrome/icons/providers/llama.svg create mode 100644 src/chrome/icons/providers/lucidquery.svg create mode 100644 src/chrome/icons/providers/meganova.svg create mode 100644 src/chrome/icons/providers/minimax-cn-coding-plan.svg create mode 100644 src/chrome/icons/providers/minimax-coding-plan.svg create mode 100644 src/chrome/icons/providers/moark.svg create mode 100644 src/chrome/icons/providers/modelscope.svg create mode 100644 src/chrome/icons/providers/morph.svg create mode 100644 src/chrome/icons/providers/nano-gpt.svg create mode 100644 src/chrome/icons/providers/nebius.svg create mode 100644 src/chrome/icons/providers/nova.svg create mode 100644 src/chrome/icons/providers/novita-ai.svg create mode 100644 src/chrome/icons/providers/ollama-cloud.svg create mode 100644 src/chrome/icons/providers/opencode-go.svg create mode 100644 src/chrome/icons/providers/opencode.svg create mode 100644 src/chrome/icons/providers/ovhcloud.svg create mode 100644 src/chrome/icons/providers/perplexity-agent.svg create mode 100644 src/chrome/icons/providers/perplexity.svg create mode 100644 src/chrome/icons/providers/poe.svg create mode 100644 src/chrome/icons/providers/privatemode-ai.svg create mode 100644 src/chrome/icons/providers/qihang-ai.svg create mode 100644 src/chrome/icons/providers/qiniu-ai.svg create mode 100644 src/chrome/icons/providers/requesty.svg create mode 100644 src/chrome/icons/providers/scaleway.svg create mode 100644 src/chrome/icons/providers/siliconflow-cn.svg create mode 100644 src/chrome/icons/providers/siliconflow.svg create mode 100644 src/chrome/icons/providers/stackit.svg create mode 100644 src/chrome/icons/providers/stepfun.svg create mode 100644 src/chrome/icons/providers/submodel.svg create mode 100644 src/chrome/icons/providers/synthetic.svg create mode 100644 src/chrome/icons/providers/tencent-coding-plan.svg create mode 100644 src/chrome/icons/providers/upstage.svg create mode 100644 src/chrome/icons/providers/v0.svg create mode 100644 src/chrome/icons/providers/venice.svg create mode 100644 src/chrome/icons/providers/vercel.svg create mode 100644 src/chrome/icons/providers/vivgrid.svg create mode 100644 src/chrome/icons/providers/vultr.svg create mode 100644 src/chrome/icons/providers/wandb.svg create mode 100644 src/chrome/icons/providers/xiaomi.svg create mode 100644 src/chrome/icons/providers/zai-coding-plan.svg create mode 100644 src/chrome/icons/providers/zenmux.svg create mode 100644 src/chrome/icons/providers/zhipuai-coding-plan.svg create mode 100644 src/chrome/icons/providers/zhipuai.svg create mode 100644 src/chrome/src/providers/provider-catalog.js create mode 100644 src/chrome/src/providers/vertex-anthropic.js create mode 100644 src/firefox/icons/providers/302ai.svg create mode 100644 src/firefox/icons/providers/abacus.svg create mode 100644 src/firefox/icons/providers/aihubmix.svg create mode 100644 src/firefox/icons/providers/alibaba-coding-plan-cn.svg create mode 100644 src/firefox/icons/providers/alibaba-coding-plan.svg create mode 100644 src/firefox/icons/providers/azure-cognitive-services.svg create mode 100644 src/firefox/icons/providers/bailing.svg create mode 100644 src/firefox/icons/providers/baseten.svg create mode 100644 src/firefox/icons/providers/berget.svg create mode 100644 src/firefox/icons/providers/cerebras.svg create mode 100644 src/firefox/icons/providers/chutes.svg create mode 100644 src/firefox/icons/providers/clarifai.svg create mode 100644 src/firefox/icons/providers/cloudferro-sherlock.svg create mode 100644 src/firefox/icons/providers/cohere.svg create mode 100644 src/firefox/icons/providers/cortecs.svg create mode 100644 src/firefox/icons/providers/deepinfra.svg create mode 100644 src/firefox/icons/providers/digitalocean.svg create mode 100644 src/firefox/icons/providers/dinference.svg create mode 100644 src/firefox/icons/providers/drun.svg create mode 100644 src/firefox/icons/providers/evroc.svg create mode 100644 src/firefox/icons/providers/fastrouter.svg create mode 100644 src/firefox/icons/providers/friendli.svg create mode 100644 src/firefox/icons/providers/google-vertex-anthropic.svg create mode 100644 src/firefox/icons/providers/google-vertex.svg create mode 100644 src/firefox/icons/providers/helicone.svg create mode 100644 src/firefox/icons/providers/iflowcn.svg create mode 100644 src/firefox/icons/providers/inception.svg create mode 100644 src/firefox/icons/providers/inference.svg create mode 100644 src/firefox/icons/providers/io-net.svg create mode 100644 src/firefox/icons/providers/jiekou.svg create mode 100644 src/firefox/icons/providers/kilo.svg create mode 100644 src/firefox/icons/providers/kimi-for-coding.svg create mode 100644 src/firefox/icons/providers/kuae-cloud-coding-plan.svg create mode 100644 src/firefox/icons/providers/llama.svg create mode 100644 src/firefox/icons/providers/lucidquery.svg create mode 100644 src/firefox/icons/providers/meganova.svg create mode 100644 src/firefox/icons/providers/minimax-cn-coding-plan.svg create mode 100644 src/firefox/icons/providers/minimax-coding-plan.svg create mode 100644 src/firefox/icons/providers/moark.svg create mode 100644 src/firefox/icons/providers/modelscope.svg create mode 100644 src/firefox/icons/providers/morph.svg create mode 100644 src/firefox/icons/providers/nano-gpt.svg create mode 100644 src/firefox/icons/providers/nebius.svg create mode 100644 src/firefox/icons/providers/nova.svg create mode 100644 src/firefox/icons/providers/novita-ai.svg create mode 100644 src/firefox/icons/providers/ollama-cloud.svg create mode 100644 src/firefox/icons/providers/opencode-go.svg create mode 100644 src/firefox/icons/providers/opencode.svg create mode 100644 src/firefox/icons/providers/ovhcloud.svg create mode 100644 src/firefox/icons/providers/perplexity-agent.svg create mode 100644 src/firefox/icons/providers/perplexity.svg create mode 100644 src/firefox/icons/providers/poe.svg create mode 100644 src/firefox/icons/providers/privatemode-ai.svg create mode 100644 src/firefox/icons/providers/qihang-ai.svg create mode 100644 src/firefox/icons/providers/qiniu-ai.svg create mode 100644 src/firefox/icons/providers/requesty.svg create mode 100644 src/firefox/icons/providers/scaleway.svg create mode 100644 src/firefox/icons/providers/siliconflow-cn.svg create mode 100644 src/firefox/icons/providers/siliconflow.svg create mode 100644 src/firefox/icons/providers/stackit.svg create mode 100644 src/firefox/icons/providers/stepfun.svg create mode 100644 src/firefox/icons/providers/submodel.svg create mode 100644 src/firefox/icons/providers/synthetic.svg create mode 100644 src/firefox/icons/providers/tencent-coding-plan.svg create mode 100644 src/firefox/icons/providers/upstage.svg create mode 100644 src/firefox/icons/providers/v0.svg create mode 100644 src/firefox/icons/providers/venice.svg create mode 100644 src/firefox/icons/providers/vercel.svg create mode 100644 src/firefox/icons/providers/vivgrid.svg create mode 100644 src/firefox/icons/providers/vultr.svg create mode 100644 src/firefox/icons/providers/wandb.svg create mode 100644 src/firefox/icons/providers/xiaomi.svg create mode 100644 src/firefox/icons/providers/zai-coding-plan.svg create mode 100644 src/firefox/icons/providers/zenmux.svg create mode 100644 src/firefox/icons/providers/zhipuai-coding-plan.svg create mode 100644 src/firefox/icons/providers/zhipuai.svg create mode 100644 src/firefox/src/providers/provider-catalog.js create mode 100644 src/firefox/src/providers/vertex-anthropic.js diff --git a/README.fr.md b/README.fr.md index 99e667128..44bc2950b 100644 --- a/README.fr.md +++ b/README.fr.md @@ -41,11 +41,12 @@ - **MiniMax**, **Kimi**, **Alibaba Cloud (Qwen)**, **z.ai GLM** - **Cloudflare Workers AI**, **Nvidia NIM**, **Groq**, **Together AI**, **Hugging Face Inference**, **Fireworks** - **OpenRouter** (modèle par défaut : `openrouter/free` ; accès à plus de 100 modèles) + - **76 API directes et routeurs supplémentaires** — 103 cartes intégrées au total ; voir le [catalogue des fournisseurs](docs/fr/providers-and-models.md#catalogue-étendu-de-fournisseurs) - **Assistant d'intégration** — Visite guidée au premier lancement couvrant la sécurité du mode Act et la configuration des fournisseurs - **Interface en panneau latéral** — Interface de chat épurée qui accompagne votre navigation - **Réponses longues pensées pour la lecture** — La nouvelle question reste visible pendant que la réponse s'allonge, avec des commandes flottantes pour suivre la réponse, aller au contenu le plus récent ou revenir à la question - **Conversations par onglet** — Chaque onglet possède son propre historique de chat -- **Streaming Ask** — Les chats Ask interactifs affichent le texte de l'API Responses officielle d'OpenAI à mesure qu'il arrive ; les outils et l'historique attendent `response.completed`, avec un interrupteur avancé et un repli non-streaming automatique en cas d'interruption +- **Streaming Ask** — Les chats Ask interactifs affichent les réponses des fournisseurs compatibles à mesure qu'elles arrivent ; les outils et l'historique attendent un événement terminal du flux, avec un interrupteur avancé et un repli non-streaming automatique en cas d'interruption - **Contexte intelligent** — Auto-compactage tenant compte des jetons (résume les tours plus anciens lorsque la conversation approche de la fenêtre de contexte du modèle, avec un avis visible « Contexte automatiquement compacté »), limites de résultats d'outils et récupération d'urgence en cas de débordement - **Contrôle de l'historique du navigateur** — Le mode Act peut utiliser les outils natifs d'historique `go_back` / `go_forward` au lieu du JavaScript de page sensible à la CSP - **Indices de raccourcis API** — Les clics répétés qui déclenchent la même requête XHR/fetch peuvent afficher une suggestion `fetch_url` correspondante tout en préservant la règle UI-d'abord et la politique de mutation `/allow-api` @@ -119,7 +120,11 @@ Cliquez sur l'icône d'engrenage ou accédez à la page Options de l'extension p **Fournisseurs :** -Les URL de base sont préremplies dans les paramètres lorsque vous choisissez un fournisseur. Les serveurs locaux utilisent le port par défaut indiqué ci-dessous. +Les URL de base sont préremplies dans les paramètres lorsque vous choisissez +un fournisseur. Les serveurs locaux utilisent le port par défaut indiqué +ci-dessous. Ce tableau présente les fournisseurs historiques ; le +[catalogue complet](docs/fr/providers-and-models.md#catalogue-étendu-de-fournisseurs) +contient 103 cartes intégrées. | Fournisseur | Clé API | Modèle par défaut | |-------------|----------|-------------------| @@ -136,7 +141,7 @@ Les URL de base sont préremplies dans les paramètres lorsque vous choisissez u | OpenAI | Requise | gpt-5.6-terra | | Anthropic Claude | Requise | claude-sonnet-4-6 | | Google Gemini | Requise | gemini-3.1-flash | -| Cloudflare Workers AI | Requise (+ Account ID) | @cf/zai-org/glm-5.2 | +| Cloudflare AI Gateway / Workers AI | Requise (+ Account ID) | @cf/zai-org/glm-5.2 | | Mistral AI | Requise | mistral-large-latest | | DeepSeek | Requise | deepseek-v4-flash | | xAI Grok | Requise | grok-4.3 | diff --git a/README.md b/README.md index 29f621e94..5557d9ae6 100644 --- a/README.md +++ b/README.md @@ -41,12 +41,13 @@ - **MiniMax**, **Kimi**, **Alibaba Cloud (Qwen)**, **z.ai GLM** - **Cloudflare Workers AI**, **Nvidia NIM**, **Groq**, **Together AI**, **Hugging Face Inference**, **Fireworks** - **OpenRouter** (default model: `openrouter/free`; access 100+ models) + - **76 additional direct APIs and routers** — 103 built-in provider cards in total; see the [provider catalog](docs/providers-and-models.md#extended-provider-catalog) - **Onboarding Wizard** — First-launch walkthrough covering Act mode safety and provider setup - **Side Panel UI** — Clean chat interface that lives alongside your browsing - **Reading-first long replies** — New questions stay in view while answers grow, with floating controls to follow the response, jump to the latest content, or return to the question - **Per-Tab Conversations** — Each tab has its own chat history - **User Memory** — Optional local memory for user-stated preferences, with explicit `/memory --add` commands and opt-in background auto-learning -- **Ask streaming** — Interactive Ask chats show text as it arrives for supported OpenAI, Anthropic, Azure OpenAI, Gemini, DeepSeek, xAI, Mistral, Nvidia NIM, Groq, Together AI, Fireworks, z.ai, OpenRouter, WebBrain Cloud, llama.cpp, Ollama, LM Studio, Jan, vLLM, SGLang, and LocalAI requests; tools and history wait for the provider's terminal event, with an Advanced kill switch and one silent non-streaming fallback for interrupted streams +- **Ask streaming** — Interactive Ask chats stream capable provider responses as they arrive; tools and history wait for a terminal stream event, with an Advanced kill switch and automatic non-streaming fallback for interrupted streams - **Smart Context** — Token-aware auto-compaction (summarizes older turns once the conversation nears the model's context window, with a visible "Context automatically compacted" notice), tool result limits, and emergency overflow recovery - **Browser History Control** — Act mode can use native `go_back` / `go_forward` history tools instead of CSP-sensitive page JavaScript - **API Shortcut Hints** — Repeated clicks that fire the same XHR/fetch request can surface a matching `fetch_url` suggestion while preserving the UI-first and `/allow-api` mutation policy @@ -155,7 +156,10 @@ Click the gear icon or go to the extension's Options page to configure: **Providers:** -Base URLs are pre-filled in Settings when you select a provider. Local servers use the default port shown below. +Base URLs are pre-filled in Settings when you select a provider. Local servers +use the default port shown below. This table highlights the original providers; +the [full catalog](docs/providers-and-models.md#extended-provider-catalog) +contains 103 built-in cards. | Provider | API Key | Default Model | |----------|---------|---------------| @@ -172,7 +176,7 @@ Base URLs are pre-filled in Settings when you select a provider. Local servers u | OpenAI | Required | gpt-5.6-terra | | Anthropic Claude | Required | claude-sonnet-4-6 | | Google Gemini | Required | gemini-3.1-flash | -| Cloudflare Workers AI | Required (+ Account ID) | @cf/zai-org/glm-5.2 | +| Cloudflare AI Gateway / Workers AI | Required (+ Account ID) | @cf/zai-org/glm-5.2 | | Mistral AI | Required | mistral-large-latest | | DeepSeek | Required | deepseek-v4-flash | | xAI Grok | Required | grok-4.3 | diff --git a/README.zh-CN.md b/README.zh-CN.md index e7ab57035..386b45046 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -41,11 +41,12 @@ - **MiniMax**、**Kimi**、**阿里云(通义千问 Qwen)**、**z.ai GLM** - **Cloudflare Workers AI**、**Nvidia NIM**、**Groq**、**Together AI**、**Hugging Face Inference**、**Fireworks** - **OpenRouter**(默认模型:`openrouter/free`;可访问 100+ 模型) + - **另外 76 个直连 API 与路由器** — 共 103 张内置提供商卡片;请参阅[提供商目录](docs/zh-CN/providers-and-models.md#扩展提供商目录) - **引导向导** — 首次启动的演练,涵盖 Act 模式安全性与提供商配置 - **侧边栏 UI** — 与浏览并存的简洁聊天界面 - **以阅读为先的长回复** — 回复增长时新问题会保持在视野中,并提供浮动控件来跟随回复、跳到最新内容或返回问题 - **按标签页对话** — 每个标签页拥有独立的聊天历史 -- **Ask 流式输出** — 交互式 Ask 对话会在 OpenAI 官方 Responses 文本到达时实时显示;工具与历史记录会等待 `response.completed`,并提供高级关闭开关和中断后的自动非流式回退 +- **Ask 流式输出** — 交互式 Ask 对话会在支持的提供商回复到达时实时显示;工具与历史记录会等待流的终止事件,并提供高级关闭开关和中断后的自动非流式回退 - **智能上下文** — 令牌感知的自动压缩(当对话接近模型上下文窗口时汇总较早的轮次,并显示「上下文已自动压缩」提示)、工具结果限制以及紧急溢出恢复 - **浏览器历史控制** — Act 模式可以使用原生 `go_back` / `go_forward` 历史工具,而不是受 CSP 影响的页面 JavaScript - **API 快捷提示** — 重复点击触发相同 XHR/fetch 请求时,可显示匹配的 `fetch_url` 建议,同时保留 UI 优先和 `/allow-api` 变更策略 @@ -119,7 +120,9 @@ python -m sglang.launch_server --model-path your-model --port 30000 **提供商:** -在设置中选择提供商时会预填 Base URL。本地服务使用下方默认端口。 +在设置中选择提供商时会预填 Base URL。本地服务使用下方默认端口。下表重点列出 +原有提供商;[完整目录](docs/zh-CN/providers-and-models.md#扩展提供商目录) +包含 103 张内置卡片。 | 提供商 | API 密钥 | 默认模型 | |--------|----------|----------| @@ -136,7 +139,7 @@ python -m sglang.launch_server --model-path your-model --port 30000 | OpenAI | 必需 | gpt-5.6-terra | | Anthropic Claude | 必需 | claude-sonnet-4-6 | | Google Gemini | 必需 | gemini-3.1-flash | -| Cloudflare Workers AI | 必需(+ Account ID) | @cf/zai-org/glm-5.2 | +| Cloudflare AI Gateway / Workers AI | 必需(+ Account ID) | @cf/zai-org/glm-5.2 | | Mistral AI | 必需 | mistral-large-latest | | DeepSeek | 必需 | deepseek-v4-flash | | xAI Grok | 必需 | grok-4.3 | diff --git a/docs/fr/providers-and-models.md b/docs/fr/providers-and-models.md index 7fa3adb7a..be3f54b96 100644 --- a/docs/fr/providers-and-models.md +++ b/docs/fr/providers-and-models.md @@ -11,6 +11,7 @@ class BaseLLMProvider { async chat(messages, options) // → { content, toolCalls, usage } async *chatStream(messages, options) // → générateur async produisant { type, content } get supportsTools() // → booléen + get supportsAskStreaming() // → booléen get supportsVision() // → booléen get promptTier() // → 'compact' | 'mid' | 'full' async testConnection() // → { ok, error?, model? } @@ -63,6 +64,53 @@ class BaseLLMProvider { | `fireworks` | `openai` | routeur | `accounts/fireworks/models/llama-v3p3-70b-instruct` | Regex nom de modèle | | `z_ai` | `openai` | cloud | `glm-5.2` | Regex nom de modèle | +### Catalogue étendu de fournisseurs + +WebBrain ajoute 76 cartes désactivées par défaut depuis l’instantané du +catalogue OpenCode au commit +`62e4641235d7847dadc60da37cca8a023dd54fc1`. Avec les 27 cartes existantes, +les Paramètres proposent **103 fournisseurs intégrés**. La liste exacte des +identifiants est : + +`302ai`, `abacus`, `aihubmix`, `alibaba-coding-plan`, +`alibaba-coding-plan-cn`, `azure-cognitive-services`, `bailing`, `baseten`, +`berget`, `cerebras`, `chutes`, `clarifai`, `cloudferro-sherlock`, `cohere`, +`cortecs`, `deepinfra`, `digitalocean`, `dinference`, `drun`, `evroc`, +`fastrouter`, `friendli`, `google-vertex`, `google-vertex-anthropic`, +`helicone`, `iflowcn`, `inception`, `inference`, `io-net`, `jiekou`, `kilo`, +`kimi-for-coding`, `kuae-cloud-coding-plan`, `llama`, `lucidquery`, +`meganova`, `minimax-cn-coding-plan`, `minimax-coding-plan`, `moark`, +`modelscope`, `morph`, `nano-gpt`, `nebius`, `nova`, `novita-ai`, +`ollama-cloud`, `opencode`, `opencode-go`, `ovhcloud`, `perplexity`, +`perplexity-agent`, `poe`, `privatemode-ai`, `qihang-ai`, `qiniu-ai`, +`requesty`, `scaleway`, `siliconflow`, `siliconflow-cn`, `stackit`, +`stepfun`, `submodel`, `synthetic`, `tencent-coding-plan`, `upstage`, `v0`, +`venice`, `vercel`, `vivgrid`, `vultr`, `wandb`, `xiaomi`, +`zai-coding-plan`, `zenmux`, `zhipuai`, `zhipuai-coding-plan`. + +La plupart utilisent Chat Completions compatible OpenAI avec une clé Bearer. +Azure AI Foundry utilise un nom de ressource et `api-key`. Google Vertex AI +utilise projet, région et clé d’autorisation Google via `x-goog-api-key`; +la région `global` utilise `aiplatform.googleapis.com`, et Vertex Anthropic +utilise `rawPredict` / `streamRawPredict` avec les hôtes multirégion `us` et +`eu`. Perplexity Agent +utilise l’API Responses. La carte Cloudflare existante prend désormais en +charge un identifiant AI Gateway facultatif ; pour les modèles `@cf/`, un +champ vide utilise automatiquement la passerelle `default`. + +Les réponses sont diffusées pendant les tours Ask interactifs lorsque +`supportsAskStreaming` est actif. Un flux interrompu efface le texte partiel, +réessaie une seule fois sans diffusion et désactive la diffusion pour le reste +de l’exécution. Act, Dev, les tâches planifiées, cloud et Continue restent sans +diffusion. L’utilisation de jetons fournie par le service est enregistrée +directement ; si elle est absente, WebBrain enregistre une estimation prudente +fondée sur le nombre de caractères afin que la diffusion ne contourne pas la +limite de coût configurée. + +Entrées volontairement exclues : `github-models` (retrait de GitHub Models le +30 juillet 2026), `github-copilot` (abonnement/OAuth), `gitlab` et +`sap-ai-core` (authentification, découverte et protocoles spécifiques). + ### Fournisseurs Locaux Sept fournisseurs locaux sont activés par défaut sans clé API requise sauf si le diff --git a/docs/providers-and-models.md b/docs/providers-and-models.md index 9e559fcef..9dedcaeeb 100644 --- a/docs/providers-and-models.md +++ b/docs/providers-and-models.md @@ -11,6 +11,7 @@ class BaseLLMProvider { async chat(messages, options) // → { content, toolCalls, usage } async *chatStream(messages, options) // → async generator yielding { type, content } get supportsTools() // → boolean + get supportsAskStreaming() // → boolean get supportsVision() // → boolean get promptTier() // → 'compact' | 'mid' | 'full' async testConnection() // → { ok, error?, model? } @@ -63,32 +64,82 @@ class BaseLLMProvider { | `fireworks` | `openai` | router | `accounts/fireworks/models/llama-v3p3-70b-instruct` | Model-name regex | | `z_ai` | `openai` | cloud | `glm-5.2` | Model-name regex | -### Interactive Ask streaming +### Extended provider catalog + +WebBrain also ships 76 disabled-by-default provider cards sourced from the +OpenCode provider catalog snapshot at commit +`62e4641235d7847dadc60da37cca8a023dd54fc1`. Together with the 27 original +cards, Settings contains **103 built-in providers**. + +| IDs | +|---| +| `302ai`, `abacus`, `aihubmix`, `alibaba-coding-plan`, `alibaba-coding-plan-cn`, `azure-cognitive-services`, `bailing`, `baseten`, `berget`, `cerebras`, `chutes`, `clarifai`, `cloudferro-sherlock`, `cohere`, `cortecs`, `deepinfra`, `digitalocean`, `dinference`, `drun`, `evroc`, `fastrouter`, `friendli` | +| `google-vertex`, `google-vertex-anthropic`, `helicone`, `iflowcn`, `inception`, `inference`, `io-net`, `jiekou`, `kilo`, `kimi-for-coding`, `kuae-cloud-coding-plan`, `llama`, `lucidquery`, `meganova`, `minimax-cn-coding-plan`, `minimax-coding-plan`, `moark`, `modelscope`, `morph` | +| `nano-gpt`, `nebius`, `nova`, `novita-ai`, `ollama-cloud`, `opencode`, `opencode-go`, `ovhcloud`, `perplexity`, `perplexity-agent`, `poe`, `privatemode-ai`, `qihang-ai`, `qiniu-ai`, `requesty`, `scaleway`, `siliconflow`, `siliconflow-cn`, `stackit` | +| `stepfun`, `submodel`, `synthetic`, `tencent-coding-plan`, `upstage`, `v0`, `venice`, `vercel`, `vivgrid`, `vultr`, `wandb`, `xiaomi`, `zai-coding-plan`, `zenmux`, `zhipuai`, `zhipuai-coding-plan` | + +Most use the OpenAI-compatible Chat Completions contract and bearer API keys. +The exceptions are: + +| Provider | Authentication / protocol | +|---|---| +| Azure AI Foundry | Resource name plus `api-key`; model is the deployed model name | +| Google Vertex AI | Project, location, and a Google authorization key sent as `x-goog-api-key`; `global` uses `aiplatform.googleapis.com` | +| Google Vertex AI (Anthropic) | Vertex `rawPredict` / `streamRawPredict` with the same authorization-key fields; `us` and `eu` use their multi-region hosts | +| Perplexity Agent | OpenAI Responses-compatible `/v1/responses` | +| Cloudflare | Existing card supports Workers AI plus an optional AI Gateway ID; blank IDs use Cloudflare's `default` gateway for `@cf/` models | + +Morph and standard Perplexity Sonar are text-only integrations in the agent +and advertise `supportsTools: false`. New provider cards remain inactive until +the user saves their credentials and selects the provider. + +### Ask response streaming + +Providers with `supportsAskStreaming` stream visible text during interactive +Ask turns. Act, Dev, scheduled, managed-cloud, and Continue turns remain +non-streaming. Tool calls are withheld until a terminal protocol event arrives +(`[DONE]`, a terminal `finish_reason`, `message_stop`, or +`response.completed`). A network failure, HTTP failure before completion, or +premature EOF clears partial UI text and retries that turn once without +streaming; the rest of that run then stays non-streaming. + +When a streaming provider returns token usage, WebBrain records it directly. +If the provider omits usage, WebBrain records a conservative character-based +estimate so streaming cannot bypass the configured cost allowance. + +The setting still uses the stored key `openaiAskStreamingEnabled` for backward +compatibility, but it now controls all capable providers. -Interactive Ask chats stream for the built-in OpenAI, Anthropic, Azure OpenAI, -Gemini, Mistral, DeepSeek, xAI, Nvidia NIM, Groq, Together AI, Fireworks, z.ai, -OpenRouter, WebBrain Cloud, llama.cpp, Ollama, LM Studio, Jan, vLLM, SGLang, -and LocalAI providers. Official OpenAI GPT-5.6 and streaming-capable Responses-only GPT-5 Pro variants use Responses streaming. Supported GPT-5.x, GPT-4.1, GPT-4o, GPT-4 Turbo, and o-series variants retain Chat Completions streaming. GPT-5.5 Pro and other official OpenAI models without documented streaming or function-calling -support stay non-streaming. Compatible built-ins opt in with -`supportsAskStreaming: true`; custom endpoints are not inferred from their -model names. +support stay non-streaming. Compatible built-ins opt in explicitly; custom +endpoints are not inferred from their model names. -Alibaba Cloud remains non-streaming for interactive Ask because +Alibaba Cloud and both Alibaba Coding Plan cards remain non-streaming for +interactive Ask because [DashScope does not allow `tools` with `stream=True`](https://www.alibabacloud.com/help/en/model-studio/compatibility-of-openai-with-dashscope), and Ask always sends its read-only tool catalog. Every parser waits for its protocol's terminal event (`response.completed`, Anthropic `message_stop`, or SSE `[DONE]`). A network/read error, malformed -frame, or premature EOF silently retries the current generation once through -`chat()` and disables streaming for the rest of that run. HTTP failures, -explicit in-stream provider/API errors, and `content_filter` finish reasons are -terminal and never trigger the duplicate request. Mistral streams explicitly -request `stream_options.include_usage` so token costs continue advancing the -cloud-provider allowance. +frame, or premature EOF clears partial output, displays a localized notice, +retries the current generation once through `chat()`, and disables streaming +for the rest of that run. HTTP failures, explicit in-stream provider/API +errors, and `content_filter` finish reasons are terminal and never trigger the +duplicate request. + +### Deliberately unsupported provider entries + +- `github-models`: GitHub is not being retired, but + [GitHub Models will retire on July 30, 2026](https://github.blog/changelog/2026-07-01-github-models-is-being-fully-retired-on-july-30-2026/). +- `github-copilot`: requires GitHub subscription/OAuth and does not expose a + suitable stable general provider API for this extension. +- `gitlab`: GitLab Duo uses custom authentication, discovery, and protocol + behavior rather than a direct Chat Completions endpoint. +- `sap-ai-core`: requires service-key OAuth, deployment discovery, and custom + service integration. ### Local Providers @@ -225,12 +276,13 @@ Used by Tab Recorder for Whisper transcription. Falls back through configured pr ## Adding a Provider -1. **Create the provider class** in `src/chrome/src/providers/.js` implementing `BaseLLMProvider` -2. **Add the default config** to `_defaultConfigs()` in `manager.js` -3. **Add the factory case** in `_createProvider()` -4. **Register the import** in `manager.js` -5. **Add provider-specific handling** in the agent if needed (e.g., Anthropic's message format conversion) -6. **Mirror to Firefox** (`src/firefox/src/providers/`) +1. Add OpenAI-compatible metadata to `providers/provider-catalog.js`, including + endpoint, model, auth mode, capabilities, and UI suggestions. +2. Create a provider class only when the wire protocol differs from the + existing OpenAI, Anthropic, Azure, Bedrock, or Vertex adapters. +3. Add a factory case and import when a new class is required. +4. Add and attribute an SVG under `icons/providers/`. +5. Mirror code, icon, UI, and tests to Firefox. ### For OpenAI-compatible providers @@ -244,6 +296,7 @@ myprovider: { providerName: 'myprovider', baseUrl: 'https://api.myprovider.com/v1', model: 'my-model', + supportsAskStreaming: true, supportsStreamUsageOptions: false, apiKey: '', enabled: false, diff --git a/docs/zh-CN/providers-and-models.md b/docs/zh-CN/providers-and-models.md index 1806d6d06..b1db86fa4 100644 --- a/docs/zh-CN/providers-and-models.md +++ b/docs/zh-CN/providers-and-models.md @@ -11,6 +11,7 @@ class BaseLLMProvider { async chat(messages, options) // → { content, toolCalls, usage } async *chatStream(messages, options) // → async generator yielding { type, content } get supportsTools() // → boolean + get supportsAskStreaming() // → boolean get supportsVision() // → boolean get promptTier() // → 'compact' | 'mid' | 'full' async testConnection() // → { ok, error?, model? } @@ -63,6 +64,47 @@ class BaseLLMProvider { | `fireworks` | `openai` | 路由器 | `accounts/fireworks/models/llama-v3p3-70b-instruct` | 模型名正则 | | `z_ai` | `openai` | 云端 | `glm-5.2` | 模型名正则 | +### 扩展提供商目录 + +WebBrain 从 OpenCode 提供商目录提交 +`62e4641235d7847dadc60da37cca8a023dd54fc1` 的快照中新增了 76 张默认禁用的 +提供商卡片。加上原有 27 张,设置中共有 **103 个内置提供商**。完整 ID +列表如下: + +`302ai`、`abacus`、`aihubmix`、`alibaba-coding-plan`、 +`alibaba-coding-plan-cn`、`azure-cognitive-services`、`bailing`、`baseten`、 +`berget`、`cerebras`、`chutes`、`clarifai`、`cloudferro-sherlock`、`cohere`、 +`cortecs`、`deepinfra`、`digitalocean`、`dinference`、`drun`、`evroc`、 +`fastrouter`、`friendli`、`google-vertex`、`google-vertex-anthropic`、 +`helicone`、`iflowcn`、`inception`、`inference`、`io-net`、`jiekou`、`kilo`、 +`kimi-for-coding`、`kuae-cloud-coding-plan`、`llama`、`lucidquery`、 +`meganova`、`minimax-cn-coding-plan`、`minimax-coding-plan`、`moark`、 +`modelscope`、`morph`、`nano-gpt`、`nebius`、`nova`、`novita-ai`、 +`ollama-cloud`、`opencode`、`opencode-go`、`ovhcloud`、`perplexity`、 +`perplexity-agent`、`poe`、`privatemode-ai`、`qihang-ai`、`qiniu-ai`、 +`requesty`、`scaleway`、`siliconflow`、`siliconflow-cn`、`stackit`、 +`stepfun`、`submodel`、`synthetic`、`tencent-coding-plan`、`upstage`、`v0`、 +`venice`、`vercel`、`vivgrid`、`vultr`、`wandb`、`xiaomi`、 +`zai-coding-plan`、`zenmux`、`zhipuai`、`zhipuai-coding-plan`。 + +大多数提供商使用兼容 OpenAI 的 Chat Completions 协议和 Bearer API 密钥。 +Azure AI Foundry 使用资源名称与 `api-key`;Google Vertex AI 使用项目、区域和 +通过 `x-goog-api-key` 发送的 Google 授权密钥;`global` 区域使用 +`aiplatform.googleapis.com`。Vertex Anthropic 使用 `rawPredict` / +`streamRawPredict`,并为 `us` 和 `eu` 使用对应的多区域主机;Perplexity +Agent 使用 Responses API。现有 Cloudflare 卡片还支持可选的 AI Gateway +ID;对于 `@cf/` 模型,留空时会自动使用 `default` 网关。 + +当 `supportsAskStreaming` 启用时,交互式 Ask 回合会流式显示回复。中断的流会 +清除部分文本、仅以非流式方式重试一次,并在本次运行剩余阶段关闭流式传输。 +Act、Dev、计划任务、云端运行和 Continue 仍使用非流式请求。服务返回令牌用量时, +WebBrain 会直接记录;若服务省略用量,则记录基于字符数的保守估算,避免流式请求绕过 +已配置的成本限额。 + +明确不支持的条目:`github-models`(GitHub Models 于 2026 年 7 月 30 日退役)、 +`github-copilot`(订阅/OAuth)、`gitlab` 和 `sap-ai-core`(需要专用认证、 +部署发现或协议)。 + ### 本地提供商 七个本地提供商默认启用,无需 API 密钥(除非本地服务器启动时启用了认证): diff --git a/src/chrome/icons/providers/302ai.svg b/src/chrome/icons/providers/302ai.svg new file mode 100644 index 000000000..46f2e4315 --- /dev/null +++ b/src/chrome/icons/providers/302ai.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/chrome/icons/providers/SOURCES.md b/src/chrome/icons/providers/SOURCES.md index 3495050a5..7c8855c3e 100644 --- a/src/chrome/icons/providers/SOURCES.md +++ b/src/chrome/icons/providers/SOURCES.md @@ -11,5 +11,6 @@ Most brand marks come from [Lobe Icons](https://github.com/lobehub/lobe-icons) | localai | LocalAI official logo (`mudler/LocalAI`) | | sglang | SGLang official `logo_square` (`sgl-project/sglang`) | | webbrain_cloud | WebBrain extension icon | +| 302ai, abacus, aihubmix, alibaba-coding-plan, alibaba-coding-plan-cn, azure-cognitive-services, bailing, baseten, berget, cerebras, chutes, clarifai, cloudferro-sherlock, cohere, cortecs, deepinfra, digitalocean, dinference, drun, evroc, fastrouter, friendli, google-vertex, google-vertex-anthropic, helicone, iflowcn, inception, inference, io-net, jiekou, kilo, kimi-for-coding, kuae-cloud-coding-plan, llama, lucidquery, meganova, minimax-cn-coding-plan, minimax-coding-plan, moark, modelscope, morph, nano-gpt, nebius, nova, novita-ai, ollama-cloud, opencode, opencode-go, ovhcloud, perplexity, perplexity-agent, poe, privatemode-ai, qihang-ai, qiniu-ai, requesty, scaleway, siliconflow, siliconflow-cn, stackit, stepfun, submodel, synthetic, tencent-coding-plan, upstage, v0, venice, vercel, vivgrid, vultr, wandb, xiaomi, zai-coding-plan, zenmux, zhipuai, zhipuai-coding-plan | OpenCode provider icon set at commit `62e4641235d7847dadc60da37cca8a023dd54fc1` (MIT); DInference SVG normalized with a `viewBox` | Brand trademarks remain property of their owners; used only for provider identification in the settings UI. diff --git a/src/chrome/icons/providers/abacus.svg b/src/chrome/icons/providers/abacus.svg new file mode 100644 index 000000000..121a91d98 --- /dev/null +++ b/src/chrome/icons/providers/abacus.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/chrome/icons/providers/aihubmix.svg b/src/chrome/icons/providers/aihubmix.svg new file mode 100644 index 000000000..33164b78b --- /dev/null +++ b/src/chrome/icons/providers/aihubmix.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/alibaba-coding-plan-cn.svg b/src/chrome/icons/providers/alibaba-coding-plan-cn.svg new file mode 100644 index 000000000..b3a2edc3c --- /dev/null +++ b/src/chrome/icons/providers/alibaba-coding-plan-cn.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/alibaba-coding-plan.svg b/src/chrome/icons/providers/alibaba-coding-plan.svg new file mode 100644 index 000000000..b3a2edc3c --- /dev/null +++ b/src/chrome/icons/providers/alibaba-coding-plan.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/azure-cognitive-services.svg b/src/chrome/icons/providers/azure-cognitive-services.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/chrome/icons/providers/azure-cognitive-services.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/chrome/icons/providers/bailing.svg b/src/chrome/icons/providers/bailing.svg new file mode 100644 index 000000000..b8ed486a8 --- /dev/null +++ b/src/chrome/icons/providers/bailing.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/baseten.svg b/src/chrome/icons/providers/baseten.svg new file mode 100644 index 000000000..ffd4fbd8b --- /dev/null +++ b/src/chrome/icons/providers/baseten.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/berget.svg b/src/chrome/icons/providers/berget.svg new file mode 100644 index 000000000..831547a59 --- /dev/null +++ b/src/chrome/icons/providers/berget.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/chrome/icons/providers/cerebras.svg b/src/chrome/icons/providers/cerebras.svg new file mode 100644 index 000000000..b16759672 --- /dev/null +++ b/src/chrome/icons/providers/cerebras.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/chrome/icons/providers/chutes.svg b/src/chrome/icons/providers/chutes.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/chrome/icons/providers/chutes.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/chrome/icons/providers/clarifai.svg b/src/chrome/icons/providers/clarifai.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/chrome/icons/providers/clarifai.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/chrome/icons/providers/cloudferro-sherlock.svg b/src/chrome/icons/providers/cloudferro-sherlock.svg new file mode 100644 index 000000000..6f09a794e --- /dev/null +++ b/src/chrome/icons/providers/cloudferro-sherlock.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/chrome/icons/providers/cohere.svg b/src/chrome/icons/providers/cohere.svg new file mode 100644 index 000000000..cfeaa6002 --- /dev/null +++ b/src/chrome/icons/providers/cohere.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/chrome/icons/providers/cortecs.svg b/src/chrome/icons/providers/cortecs.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/chrome/icons/providers/cortecs.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/chrome/icons/providers/deepinfra.svg b/src/chrome/icons/providers/deepinfra.svg new file mode 100644 index 000000000..c35ab7183 --- /dev/null +++ b/src/chrome/icons/providers/deepinfra.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/chrome/icons/providers/digitalocean.svg b/src/chrome/icons/providers/digitalocean.svg new file mode 100644 index 000000000..5be390b9d --- /dev/null +++ b/src/chrome/icons/providers/digitalocean.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/chrome/icons/providers/dinference.svg b/src/chrome/icons/providers/dinference.svg new file mode 100644 index 000000000..e161327d4 --- /dev/null +++ b/src/chrome/icons/providers/dinference.svg @@ -0,0 +1 @@ + diff --git a/src/chrome/icons/providers/drun.svg b/src/chrome/icons/providers/drun.svg new file mode 100644 index 000000000..472dee912 --- /dev/null +++ b/src/chrome/icons/providers/drun.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/chrome/icons/providers/evroc.svg b/src/chrome/icons/providers/evroc.svg new file mode 100644 index 000000000..7597820a1 --- /dev/null +++ b/src/chrome/icons/providers/evroc.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/chrome/icons/providers/fastrouter.svg b/src/chrome/icons/providers/fastrouter.svg new file mode 100644 index 000000000..ec73dc49c --- /dev/null +++ b/src/chrome/icons/providers/fastrouter.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/friendli.svg b/src/chrome/icons/providers/friendli.svg new file mode 100644 index 000000000..8acb7632d --- /dev/null +++ b/src/chrome/icons/providers/friendli.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/google-vertex-anthropic.svg b/src/chrome/icons/providers/google-vertex-anthropic.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/chrome/icons/providers/google-vertex-anthropic.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/chrome/icons/providers/google-vertex.svg b/src/chrome/icons/providers/google-vertex.svg new file mode 100644 index 000000000..fda56b447 --- /dev/null +++ b/src/chrome/icons/providers/google-vertex.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/chrome/icons/providers/helicone.svg b/src/chrome/icons/providers/helicone.svg new file mode 100644 index 000000000..8a4bd43ad --- /dev/null +++ b/src/chrome/icons/providers/helicone.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/chrome/icons/providers/iflowcn.svg b/src/chrome/icons/providers/iflowcn.svg new file mode 100644 index 000000000..6f35a7d59 --- /dev/null +++ b/src/chrome/icons/providers/iflowcn.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/inception.svg b/src/chrome/icons/providers/inception.svg new file mode 100644 index 000000000..f70ffbc78 --- /dev/null +++ b/src/chrome/icons/providers/inception.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/chrome/icons/providers/inference.svg b/src/chrome/icons/providers/inference.svg new file mode 100644 index 000000000..c17f66574 --- /dev/null +++ b/src/chrome/icons/providers/inference.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/io-net.svg b/src/chrome/icons/providers/io-net.svg new file mode 100644 index 000000000..651e57df8 --- /dev/null +++ b/src/chrome/icons/providers/io-net.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/chrome/icons/providers/jiekou.svg b/src/chrome/icons/providers/jiekou.svg new file mode 100644 index 000000000..7fe6378e5 --- /dev/null +++ b/src/chrome/icons/providers/jiekou.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/chrome/icons/providers/kilo.svg b/src/chrome/icons/providers/kilo.svg new file mode 100644 index 000000000..0a761347a --- /dev/null +++ b/src/chrome/icons/providers/kilo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/chrome/icons/providers/kimi-for-coding.svg b/src/chrome/icons/providers/kimi-for-coding.svg new file mode 100644 index 000000000..8f2af02e6 --- /dev/null +++ b/src/chrome/icons/providers/kimi-for-coding.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/kuae-cloud-coding-plan.svg b/src/chrome/icons/providers/kuae-cloud-coding-plan.svg new file mode 100644 index 000000000..3d0d0c455 --- /dev/null +++ b/src/chrome/icons/providers/kuae-cloud-coding-plan.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/llama.svg b/src/chrome/icons/providers/llama.svg new file mode 100644 index 000000000..3053b251f --- /dev/null +++ b/src/chrome/icons/providers/llama.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/lucidquery.svg b/src/chrome/icons/providers/lucidquery.svg new file mode 100644 index 000000000..6420a042e --- /dev/null +++ b/src/chrome/icons/providers/lucidquery.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/meganova.svg b/src/chrome/icons/providers/meganova.svg new file mode 100644 index 000000000..59e8b3a1f --- /dev/null +++ b/src/chrome/icons/providers/meganova.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/minimax-cn-coding-plan.svg b/src/chrome/icons/providers/minimax-cn-coding-plan.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/chrome/icons/providers/minimax-cn-coding-plan.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/chrome/icons/providers/minimax-coding-plan.svg b/src/chrome/icons/providers/minimax-coding-plan.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/chrome/icons/providers/minimax-coding-plan.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/chrome/icons/providers/moark.svg b/src/chrome/icons/providers/moark.svg new file mode 100644 index 000000000..dc84a9191 --- /dev/null +++ b/src/chrome/icons/providers/moark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/modelscope.svg b/src/chrome/icons/providers/modelscope.svg new file mode 100644 index 000000000..94a894a55 --- /dev/null +++ b/src/chrome/icons/providers/modelscope.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/chrome/icons/providers/morph.svg b/src/chrome/icons/providers/morph.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/chrome/icons/providers/morph.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/chrome/icons/providers/nano-gpt.svg b/src/chrome/icons/providers/nano-gpt.svg new file mode 100644 index 000000000..f7fbb4cdc --- /dev/null +++ b/src/chrome/icons/providers/nano-gpt.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/chrome/icons/providers/nebius.svg b/src/chrome/icons/providers/nebius.svg new file mode 100644 index 000000000..aeba5890d --- /dev/null +++ b/src/chrome/icons/providers/nebius.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/chrome/icons/providers/nova.svg b/src/chrome/icons/providers/nova.svg new file mode 100644 index 000000000..9fcae228c --- /dev/null +++ b/src/chrome/icons/providers/nova.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/novita-ai.svg b/src/chrome/icons/providers/novita-ai.svg new file mode 100644 index 000000000..ac537b8dd --- /dev/null +++ b/src/chrome/icons/providers/novita-ai.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/chrome/icons/providers/ollama-cloud.svg b/src/chrome/icons/providers/ollama-cloud.svg new file mode 100644 index 000000000..08c05cf28 --- /dev/null +++ b/src/chrome/icons/providers/ollama-cloud.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/chrome/icons/providers/opencode-go.svg b/src/chrome/icons/providers/opencode-go.svg new file mode 100644 index 000000000..e0833b923 --- /dev/null +++ b/src/chrome/icons/providers/opencode-go.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/opencode.svg b/src/chrome/icons/providers/opencode.svg new file mode 100644 index 000000000..950846582 --- /dev/null +++ b/src/chrome/icons/providers/opencode.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/ovhcloud.svg b/src/chrome/icons/providers/ovhcloud.svg new file mode 100644 index 000000000..064b0835b --- /dev/null +++ b/src/chrome/icons/providers/ovhcloud.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/perplexity-agent.svg b/src/chrome/icons/providers/perplexity-agent.svg new file mode 100644 index 000000000..a0f38862a --- /dev/null +++ b/src/chrome/icons/providers/perplexity-agent.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/perplexity.svg b/src/chrome/icons/providers/perplexity.svg new file mode 100644 index 000000000..a0f38862a --- /dev/null +++ b/src/chrome/icons/providers/perplexity.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/poe.svg b/src/chrome/icons/providers/poe.svg new file mode 100644 index 000000000..a5ab62d72 --- /dev/null +++ b/src/chrome/icons/providers/poe.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/chrome/icons/providers/privatemode-ai.svg b/src/chrome/icons/providers/privatemode-ai.svg new file mode 100644 index 000000000..edb5a6d76 --- /dev/null +++ b/src/chrome/icons/providers/privatemode-ai.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/chrome/icons/providers/qihang-ai.svg b/src/chrome/icons/providers/qihang-ai.svg new file mode 100644 index 000000000..9e58c7440 --- /dev/null +++ b/src/chrome/icons/providers/qihang-ai.svg @@ -0,0 +1,9 @@ + + + diff --git a/src/chrome/icons/providers/qiniu-ai.svg b/src/chrome/icons/providers/qiniu-ai.svg new file mode 100644 index 000000000..858560f9f --- /dev/null +++ b/src/chrome/icons/providers/qiniu-ai.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/chrome/icons/providers/requesty.svg b/src/chrome/icons/providers/requesty.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/chrome/icons/providers/requesty.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/chrome/icons/providers/scaleway.svg b/src/chrome/icons/providers/scaleway.svg new file mode 100644 index 000000000..7574f72f3 --- /dev/null +++ b/src/chrome/icons/providers/scaleway.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/chrome/icons/providers/siliconflow-cn.svg b/src/chrome/icons/providers/siliconflow-cn.svg new file mode 100644 index 000000000..13cac22b9 --- /dev/null +++ b/src/chrome/icons/providers/siliconflow-cn.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/siliconflow.svg b/src/chrome/icons/providers/siliconflow.svg new file mode 100644 index 000000000..13cac22b9 --- /dev/null +++ b/src/chrome/icons/providers/siliconflow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/stackit.svg b/src/chrome/icons/providers/stackit.svg new file mode 100644 index 000000000..0d78b781a --- /dev/null +++ b/src/chrome/icons/providers/stackit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/chrome/icons/providers/stepfun.svg b/src/chrome/icons/providers/stepfun.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/chrome/icons/providers/stepfun.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/chrome/icons/providers/submodel.svg b/src/chrome/icons/providers/submodel.svg new file mode 100644 index 000000000..5bef03c64 --- /dev/null +++ b/src/chrome/icons/providers/submodel.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/synthetic.svg b/src/chrome/icons/providers/synthetic.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/chrome/icons/providers/synthetic.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/chrome/icons/providers/tencent-coding-plan.svg b/src/chrome/icons/providers/tencent-coding-plan.svg new file mode 100644 index 000000000..502e51a5b --- /dev/null +++ b/src/chrome/icons/providers/tencent-coding-plan.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/chrome/icons/providers/upstage.svg b/src/chrome/icons/providers/upstage.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/chrome/icons/providers/upstage.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/chrome/icons/providers/v0.svg b/src/chrome/icons/providers/v0.svg new file mode 100644 index 000000000..09f3b411e --- /dev/null +++ b/src/chrome/icons/providers/v0.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/venice.svg b/src/chrome/icons/providers/venice.svg new file mode 100644 index 000000000..3d5809e3b --- /dev/null +++ b/src/chrome/icons/providers/venice.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/chrome/icons/providers/vercel.svg b/src/chrome/icons/providers/vercel.svg new file mode 100644 index 000000000..a99425f2a --- /dev/null +++ b/src/chrome/icons/providers/vercel.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/vivgrid.svg b/src/chrome/icons/providers/vivgrid.svg new file mode 100644 index 000000000..928fa3ff1 --- /dev/null +++ b/src/chrome/icons/providers/vivgrid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/chrome/icons/providers/vultr.svg b/src/chrome/icons/providers/vultr.svg new file mode 100644 index 000000000..9205d4484 --- /dev/null +++ b/src/chrome/icons/providers/vultr.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/chrome/icons/providers/wandb.svg b/src/chrome/icons/providers/wandb.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/chrome/icons/providers/wandb.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/chrome/icons/providers/xiaomi.svg b/src/chrome/icons/providers/xiaomi.svg new file mode 100644 index 000000000..4a893919e --- /dev/null +++ b/src/chrome/icons/providers/xiaomi.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/zai-coding-plan.svg b/src/chrome/icons/providers/zai-coding-plan.svg new file mode 100644 index 000000000..d7da9b7c5 --- /dev/null +++ b/src/chrome/icons/providers/zai-coding-plan.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/zenmux.svg b/src/chrome/icons/providers/zenmux.svg new file mode 100644 index 000000000..9eb8045e4 --- /dev/null +++ b/src/chrome/icons/providers/zenmux.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/chrome/icons/providers/zhipuai-coding-plan.svg b/src/chrome/icons/providers/zhipuai-coding-plan.svg new file mode 100644 index 000000000..3d0d0c455 --- /dev/null +++ b/src/chrome/icons/providers/zhipuai-coding-plan.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/icons/providers/zhipuai.svg b/src/chrome/icons/providers/zhipuai.svg new file mode 100644 index 000000000..d7da9b7c5 --- /dev/null +++ b/src/chrome/icons/providers/zhipuai.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/chrome/src/agent/agent.js b/src/chrome/src/agent/agent.js index db003594a..69f273fd1 100644 --- a/src/chrome/src/agent/agent.js +++ b/src/chrome/src/agent/agent.js @@ -1114,6 +1114,27 @@ export class Agent { return result; } + _estimateAskStreamUsage(messages, options, content, reasoningContent, toolCalls) { + let toolSchemaChars = 0; + let toolCallChars = 0; + try { toolSchemaChars = JSON.stringify(options?.tools || []).length; } catch {} + try { toolCallChars = JSON.stringify(toolCalls || []).length; } catch {} + const promptTokens = Math.max( + 1, + Math.ceil((this._estimateContextChars(Array.isArray(messages) ? messages : []) + toolSchemaChars) / 4), + ); + const completionChars = String(content || '').length + + String(reasoningContent || '').length + + toolCallChars; + const completionTokens = completionChars > 0 ? Math.max(1, Math.ceil(completionChars / 4)) : 0; + return { + prompt_tokens: promptTokens, + completion_tokens: completionTokens, + total_tokens: promptTokens + completionTokens, + estimated: true, + }; + } + _shouldStreamInteractiveAsk(provider, mode, runOptions = {}, disabledForRun = false) { const streamingEnabled = runOptions?.askStreamingEnabled ?? runOptions?.openaiAskStreamingEnabled; @@ -1163,6 +1184,18 @@ export class Agent { usageRecorded = true; return this._recordCostUsage(provider, usage, costState); }; + const estimateUsageIfMissing = (completed = false) => { + if (usage) return; + const partialToolCalls = [...toolCalls.values()]; + if (!completed && !content && !reasoningContent && partialToolCalls.length === 0) return; + usage = this._estimateAskStreamUsage( + messages, + streamOptions, + content, + reasoningContent, + partialToolCalls, + ); + }; const mergeToolCall = (toolCall, fallbackIndex = 0) => { if (!toolCall || typeof toolCall !== 'object') return; const index = Number.isInteger(toolCall.index) ? toolCall.index : fallbackIndex; @@ -1222,10 +1255,12 @@ export class Agent { } catch (error) { // Incomplete Responses streams can still report billable usage. Record // that once before the caller either propagates or retries the failure. + estimateUsageIfMissing(false); try { await recordUsage(); } catch {} throw error; } + estimateUsageIfMissing(true); content = Agent._stripReasoningTags(content); const result = { content, @@ -18495,6 +18530,10 @@ Rules: no prose intro, no conclusion, no "this screenshot shows...", no layout d if (emittedText) onUpdate('text', { content: '', replace: true }); if (!this._shouldFallbackAskStream(error)) throw error; askStreamingDisabledForRun = true; + onUpdate('warning', { + code: 'ask_stream_fallback', + message: 'Response streaming was interrupted; retrying this Ask turn without streaming.', + }); this._logDebug({ type: 'llm_stream_fallback', provider: provider.constructor?.name || provider.name, diff --git a/src/chrome/src/providers/anthropic.js b/src/chrome/src/providers/anthropic.js index 7879203d8..80ccdcda5 100644 --- a/src/chrome/src/providers/anthropic.js +++ b/src/chrome/src/providers/anthropic.js @@ -36,6 +36,14 @@ export class AnthropicProvider extends BaseLLMProvider { return true; } + _messagesUrl(_stream = false) { + return `${String(this.baseUrl).replace(/\/+$/, '')}/v1/messages`; + } + + _prepareRequestBody(body, _options = {}, _stream = false) { + return body; + } + _headers() { return { 'Content-Type': 'application/json', @@ -188,7 +196,7 @@ export class AnthropicProvider extends BaseLLMProvider { async chat(messages, options = {}) { const { system, messages: anthropicMessages } = this._convertMessages(messages); - const body = { + let body = { model: this.model, max_tokens: options.maxTokens ?? 4096, messages: anthropicMessages, @@ -199,8 +207,9 @@ export class AnthropicProvider extends BaseLLMProvider { if (options.tools && options.tools.length > 0) { body.tools = this._convertTools(options.tools); } + body = this._prepareRequestBody(body, options, false); - const res = await fetchWithFallback(`${this.baseUrl}/v1/messages`, { + const res = await fetchWithFallback(this._messagesUrl(false), { method: 'POST', headers: this._headers(), body: JSON.stringify(body), @@ -248,7 +257,7 @@ export class AnthropicProvider extends BaseLLMProvider { async *chatStream(messages, options = {}) { const { system, messages: anthropicMessages } = this._convertMessages(messages); - const body = { + let body = { model: this.model, max_tokens: options.maxTokens ?? 4096, messages: anthropicMessages, @@ -260,8 +269,9 @@ export class AnthropicProvider extends BaseLLMProvider { if (options.tools && options.tools.length > 0) { body.tools = this._convertTools(options.tools); } + body = this._prepareRequestBody(body, options, true); - const url = `${this.baseUrl}/v1/messages`; + const url = this._messagesUrl(true); let res; try { res = await fetchWithFallback(url, { diff --git a/src/chrome/src/providers/base.js b/src/chrome/src/providers/base.js index 6452a6347..35169b7ff 100644 --- a/src/chrome/src/providers/base.js +++ b/src/chrome/src/providers/base.js @@ -67,6 +67,15 @@ export class BaseLLMProvider { return false; } + /** + * Whether interactive Ask turns may use this provider's streaming method. + * Providers must opt in explicitly; merely implementing chatStream() is not + * enough because some adapters retain a non-streaming compatibility shim. + */ + get supportsAskStreaming() { + return this.config.supportsAskStreaming === true; + } + /** * Check if this provider supports image inputs (vision). */ diff --git a/src/chrome/src/providers/manager.js b/src/chrome/src/providers/manager.js index 82f179064..b8a7bb760 100644 --- a/src/chrome/src/providers/manager.js +++ b/src/chrome/src/providers/manager.js @@ -2,8 +2,10 @@ import { LlamaCppProvider } from './llamacpp.js'; import { OpenAICompatibleProvider } from './openai.js'; import { AzureOpenAIProvider } from './azure-openai.js'; import { AnthropicProvider, AnthropicOAuthProvider } from './anthropic.js'; +import { VertexAnthropicProvider } from './vertex-anthropic.js'; import { signOutClaude } from './oauth-claude.js'; import { AwsBedrockProvider } from './aws-bedrock.js'; +import { ADDITIONAL_PROVIDER_DEFAULTS } from './provider-catalog.js'; // Static, NOT dynamic: this module runs in the MV3 service worker, where // `await import()` throws "import() is disallowed on ServiceWorkerGlobalScope". // The provider modules above already import this statically, so it's in the SW @@ -32,7 +34,7 @@ const OPENROUTER_DEFAULT_MODEL = 'openrouter/free'; const OPENROUTER_LEGACY_DEFAULT_MODEL = 'stepfun/step-3.7-flash'; const OPENAI_DEFAULT_MODEL = 'gpt-5.6-terra'; const OPENAI_LEGACY_DEFAULT_MODEL = 'gpt-5.5'; -const SUPPORTED_PROVIDER_TYPES = new Set(['llamacpp', 'openai', 'azure_openai', 'aws_bedrock', 'anthropic', 'anthropic_oauth']); +const SUPPORTED_PROVIDER_TYPES = new Set(['llamacpp', 'openai', 'azure_openai', 'aws_bedrock', 'anthropic', 'anthropic_oauth', 'vertex_anthropic']); const SAFE_PROVIDER_ID_RE = /^[A-Za-z0-9_-]+$/; const ROUTER_PROVIDER_IDS = ['openrouter', 'cloudflare', 'nvidia', 'groq', 'huggingface', 'fireworks', 'together']; const PROVIDER_CREDENTIAL_KEYS = ['apiKey', 'accessKeyId', 'secretAccessKey', 'sessionToken']; @@ -349,13 +351,14 @@ export class ProviderManager { cloudflare: { type: 'openai', category: 'router', - label: 'Cloudflare Workers AI', + label: 'Cloudflare AI Gateway / Workers AI', providerName: 'cloudflare', baseUrl: 'https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/v1', model: '@cf/zai-org/glm-5.2', contextWindow: 262144, supportsStreamUsageOptions: false, accountId: '', + gatewayId: '', apiKey: '', apiKeyUrl: 'https://dash.cloudflare.com/profile/api-tokens', enabled: false, @@ -539,6 +542,7 @@ export class ProviderManager { apiKeyUrl: 'https://docs.z.ai/guides/overview/quick-start', enabled: false, }, + ...ADDITIONAL_PROVIDER_DEFAULTS, }; } @@ -646,6 +650,14 @@ export class ProviderManager { const normalizedConfig = { ...config, category: ProviderManager.categoryFor(id, config), + supportsAskStreaming: config.supportsAskStreaming ?? [ + 'llamacpp', + 'openai', + 'azure_openai', + 'anthropic', + 'anthropic_oauth', + 'vertex_anthropic', + ].includes(config.type), }; switch (normalizedConfig.type) { case 'llamacpp': @@ -660,6 +672,8 @@ export class ProviderManager { return new AnthropicProvider(normalizedConfig); case 'anthropic_oauth': return new AnthropicOAuthProvider(normalizedConfig); + case 'vertex_anthropic': + return new VertexAnthropicProvider(normalizedConfig); default: throw new Error(`Unknown provider type: ${normalizedConfig.type}`); } diff --git a/src/chrome/src/providers/openai.js b/src/chrome/src/providers/openai.js index 26693a9c5..6167c8334 100644 --- a/src/chrome/src/providers/openai.js +++ b/src/chrome/src/providers/openai.js @@ -34,18 +34,48 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { } get baseUrl() { - const baseUrl = this.config.baseUrl || 'https://api.openai.com/v1'; - if ((this.config.providerName || '').toLowerCase() !== 'cloudflare') return baseUrl; - if (!baseUrl.includes('{account_id}')) return baseUrl; - const accountId = String(this.config.accountId || '').trim(); - if (!/^[0-9a-f]{32}$/i.test(accountId)) { - throw new Error('Cloudflare Account ID is required and must be a 32-character hex string.'); + let baseUrl = String(this.config.baseUrl || 'https://api.openai.com/v1').trim(); + const vertexLocation = String(this.config.location || '').trim(); + const replacements = { + account_id: { + value: String(this.config.accountId || '').trim(), + valid: (value) => /^[0-9a-f]{32}$/i.test(value), + message: 'Cloudflare Account ID is required and must be a 32-character hex string.', + }, + project: { + value: String(this.config.project || '').trim(), + valid: (value) => /^[a-z][a-z0-9:._-]{4,127}$/i.test(value), + message: 'Google Cloud project ID is required.', + }, + location: { + value: vertexLocation, + valid: (value) => /^[a-z0-9-]+$/i.test(value), + message: 'Google Cloud location is required.', + }, + resource: { + value: String(this.config.resource || '').trim(), + valid: (value) => /^[a-z0-9-]{2,64}$/i.test(value), + message: 'Azure resource name is required.', + }, + vertex_endpoint: { + value: vertexLocation.toLowerCase() === 'global' + ? 'aiplatform.googleapis.com' + : `${vertexLocation}-aiplatform.googleapis.com`, + valid: (value) => /^(?:[a-z0-9-]+-)?aiplatform\.googleapis\.com$/i.test(value), + message: 'Google Cloud location is required.', + }, + }; + for (const [placeholder, replacement] of Object.entries(replacements)) { + if (!baseUrl.includes(`{${placeholder}}`)) continue; + if (!replacement.valid(replacement.value)) throw new Error(replacement.message); + baseUrl = baseUrl.replaceAll(`{${placeholder}}`, replacement.value); } - return baseUrl.replace('{account_id}', accountId); + return baseUrl.replace(/\/+$/, ''); } get model() { if (this.config.model) return this.config.model; + if (this.config.requiresModel) throw new Error(`${this.config.label || this.name} model is required.`); return String(this.config.providerName || '').toLowerCase() === 'openai' && this._isOfficialOpenAIBaseUrl() ? 'gpt-5.6-terra' @@ -53,7 +83,7 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { } get supportsTools() { - return true; + return this.config.supportsTools !== false; } get supportsVision() { @@ -76,7 +106,13 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { const headers = { 'Content-Type': 'application/json' }; const providerName = (this.config.providerName || '').toLowerCase(); if (this.config.apiKey) { - headers['Authorization'] = `Bearer ${this.config.apiKey}`; + if (this.config.apiKeyHeader === 'x-goog-api-key') { + headers['x-goog-api-key'] = String(this.config.apiKey); + } else if (this.config.apiKeyHeader === 'api-key') { + headers['api-key'] = String(this.config.apiKey); + } else { + headers['Authorization'] = `Bearer ${this.config.apiKey}`; + } } if (providerName === 'webbrain-cloud') { if (this.config.deviceGuid) headers['X-WebBrain-Device-Id'] = this.config.deviceGuid; @@ -88,6 +124,12 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { headers['HTTP-Referer'] = this.config.siteUrl || 'https://github.com/webbrain-one/webbrain'; headers['X-Title'] = 'WebBrain'; } + if (providerName === 'cloudflare') { + const configuredGatewayId = String(this.config.gatewayId || '').trim(); + const gatewayId = configuredGatewayId + || (String(this.model || '').trim().startsWith('@cf/') ? 'default' : ''); + if (gatewayId) headers['cf-aig-gateway-id'] = gatewayId; + } return headers; } @@ -232,7 +274,11 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { // DashScope rejects `tools` together with `stream: true`, while Ask always // supplies its read-only tool catalog. Keep even stale/imported opt-ins on // the safe non-streaming path. - if (String(resolved.providerName || '').trim().toLowerCase() === 'alibaba') { + if ([ + 'alibaba', + 'alibaba-coding-plan', + 'alibaba-coding-plan-cn', + ].includes(String(resolved.providerName || '').trim().toLowerCase())) { return false; } if (isOfficialOpenAIConfig(resolved)) { @@ -878,6 +924,7 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { const decoder = new TextDecoder(); let buffer = ''; let finalUsage = null; + let sawTerminalFinish = false; while (true) { let chunk; @@ -939,6 +986,9 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { `${this.name} Chat Completions stream failed with terminal finish reason "${finishReason}".`, ); } + if (finishReason != null) { + sawTerminalFinish = true; + } const delta = choice?.delta; const reasoningDelta = delta?.reasoning_content || delta?.reasoning; if (typeof reasoningDelta === 'string' && reasoningDelta) { @@ -953,6 +1003,10 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { } } if (finalUsage) yield { type: 'usage', usage: finalUsage }; + if (sawTerminalFinish) { + yield { type: 'done', content: '' }; + return; + } if (this._supportsInteractiveAskStreaming()) { throw this._chatCompletionsStreamTransportError( `${this.name} Chat Completions stream ended before the [DONE] sentinel.`, diff --git a/src/chrome/src/providers/provider-catalog.js b/src/chrome/src/providers/provider-catalog.js new file mode 100644 index 000000000..a607bf805 --- /dev/null +++ b/src/chrome/src/providers/provider-catalog.js @@ -0,0 +1,148 @@ +/** + * Additional built-in providers. + * + * The catalog is a curated, checked-in snapshot of OpenCode's provider data at + * commit 62e4641235d7847dadc60da37cca8a023dd54fc1. Keeping it local makes the + * extension deterministic and avoids loading provider metadata at runtime. + */ + +const DEFAULT_API_KEY_PLACEHOLDER = 'API key'; + +function provider(id, label, baseUrl, model, contextWindow, options = {}) { + const { + category = 'router', + type = 'openai', + apiKeyUrl = '', + supportsVision = false, + supportsTools = true, + supportsAskStreaming = true, + suggestions = model ? [model] : [], + inputCostPerMillionUsd, + cacheReadCostPerMillionUsd, + cacheWriteCostPerMillionUsd, + outputCostPerMillionUsd, + apiKeyPlaceholder = DEFAULT_API_KEY_PLACEHOLDER, + ...config + } = options; + + return { + id, + config: { + type, + category, + label, + providerName: id, + baseUrl, + model, + contextWindow, + supportsVision, + supportsTools, + supportsAskStreaming, + // Chat Completions streaming is broadly supported, but the optional + // stream_options.include_usage extension is not. Individual providers + // can opt in later when their wire contract guarantees it. + supportsStreamUsageOptions: false, + apiKey: '', + apiKeyUrl, + enabled: false, + ...(inputCostPerMillionUsd == null ? {} : { inputCostPerMillionUsd }), + ...(cacheReadCostPerMillionUsd == null ? {} : { cacheReadCostPerMillionUsd }), + ...(cacheWriteCostPerMillionUsd == null ? {} : { cacheWriteCostPerMillionUsd }), + ...(outputCostPerMillionUsd == null ? {} : { outputCostPerMillionUsd }), + ...config, + }, + ui: { + suggestions, + apiKeyPlaceholder, + }, + }; +} + +const PROVIDERS = [ + provider('302ai', '302.AI', 'https://api.302.ai/v1', 'gpt-5.4-mini-2026-03-17', 400000, { apiKeyUrl: 'https://doc.302.ai', supportsVision: true, inputCostPerMillionUsd: 0.75, outputCostPerMillionUsd: 4.5 }), + provider('abacus', 'Abacus', 'https://routellm.abacus.ai/v1', 'o3', 200000, { apiKeyUrl: 'https://abacus.ai/help/api', supportsVision: true, inputCostPerMillionUsd: 2, cacheReadCostPerMillionUsd: 0.5, outputCostPerMillionUsd: 8 }), + provider('aihubmix', 'AIHubMix', 'https://aihubmix.com/v1', 'coding-minimax-m2.7', 204800, { apiKeyUrl: 'https://docs.aihubmix.com', inputCostPerMillionUsd: 0.2, outputCostPerMillionUsd: 0.2 }), + provider('alibaba-coding-plan', 'Alibaba Coding Plan', 'https://coding-intl.dashscope.aliyuncs.com/v1', 'qwen3-coder-plus', 1000000, { category: 'cloud', apiKeyUrl: 'https://www.alibabacloud.com/help/en/model-studio/coding-plan', supportsAskStreaming: false }), + provider('alibaba-coding-plan-cn', 'Alibaba Coding Plan (China)', 'https://coding.dashscope.aliyuncs.com/v1', 'qwen3-coder-plus', 1000000, { category: 'cloud', apiKeyUrl: 'https://help.aliyun.com/zh/model-studio/coding-plan', supportsAskStreaming: false }), + provider('azure-cognitive-services', 'Azure AI Foundry', 'https://{resource}.openai.azure.com/openai/v1', '', 200000, { category: 'cloud', apiKeyUrl: 'https://ai.azure.com/', apiKeyHeader: 'api-key', resource: '', requiresModel: true, supportsVision: true, apiKeyPlaceholder: 'Azure API key' }), + provider('bailing', 'Bailing', 'https://api.tbox.cn/api/llm/v1', 'Ling-1T', 128000, { category: 'cloud', apiKeyUrl: 'https://alipaytbox.yuque.com/sxs0ba/ling/intro', inputCostPerMillionUsd: 0.57, outputCostPerMillionUsd: 2.29 }), + provider('baseten', 'Baseten', 'https://inference.baseten.co/v1', 'moonshotai/Kimi-K2.6', 262000, { apiKeyUrl: 'https://docs.baseten.co/inference/model-apis/overview', supportsVision: true, inputCostPerMillionUsd: 0.95, cacheReadCostPerMillionUsd: 0.16, outputCostPerMillionUsd: 4 }), + provider('berget', 'Berget.AI', 'https://api.berget.ai/v1', 'meta-llama/Llama-3.3-70B-Instruct', 128000, { apiKeyUrl: 'https://api.berget.ai', inputCostPerMillionUsd: 0.99, outputCostPerMillionUsd: 0.99 }), + provider('cerebras', 'Cerebras', 'https://api.cerebras.ai/v1', 'gemma-4-31b', 131072, { category: 'cloud', apiKeyUrl: 'https://cloud.cerebras.ai/', supportsVision: true, inputCostPerMillionUsd: 0.99, outputCostPerMillionUsd: 1.49 }), + provider('chutes', 'Chutes', 'https://llm.chutes.ai/v1', 'moonshotai/Kimi-K2.6-TEE', 262144, { apiKeyUrl: 'https://chutes.ai/', supportsVision: true, inputCostPerMillionUsd: 0.66, cacheReadCostPerMillionUsd: 0.33, outputCostPerMillionUsd: 3.5 }), + provider('clarifai', 'Clarifai', 'https://api.clarifai.com/v2/ext/openai/v1', 'moonshotai/chat-completion/models/Kimi-K2_6', 262144, { apiKeyUrl: 'https://clarifai.com/settings/security', supportsVision: true, inputCostPerMillionUsd: 0.95, outputCostPerMillionUsd: 4, apiKeyPlaceholder: 'Personal access token' }), + provider('cloudferro-sherlock', 'CloudFerro Sherlock', 'https://api-sherlock.cloudferro.com/openai/v1', 'meta-llama/Llama-3.3-70B-Instruct', 70000, { apiKeyUrl: 'https://docs.sherlock.cloudferro.com/', inputCostPerMillionUsd: 2.92, outputCostPerMillionUsd: 2.92 }), + provider('cohere', 'Cohere', 'https://api.cohere.ai/compatibility/v1', 'command-a-03-2025', 256000, { category: 'cloud', apiKeyUrl: 'https://dashboard.cohere.com/api-keys', inputCostPerMillionUsd: 2.5, outputCostPerMillionUsd: 10 }), + provider('cortecs', 'Cortecs', 'https://api.cortecs.ai/v1', 'deepseek-r1-0528', 164000, { apiKeyUrl: 'https://api.cortecs.ai/v1/models', inputCostPerMillionUsd: 0.585, outputCostPerMillionUsd: 2.307 }), + provider('deepinfra', 'DeepInfra', 'https://api.deepinfra.com/v1/openai', 'meta-llama/Llama-4-Scout-17B-16E-Instruct', 327680, { apiKeyUrl: 'https://deepinfra.com/dash/api_keys', supportsVision: true, inputCostPerMillionUsd: 0.1, outputCostPerMillionUsd: 0.3 }), + provider('digitalocean', 'DigitalOcean Gradient AI', 'https://inference.do-ai.run/v1', 'anthropic-claude-haiku-4.5', 200000, { apiKeyUrl: 'https://cloud.digitalocean.com/account/api/tokens', supportsVision: true, inputCostPerMillionUsd: 1, cacheReadCostPerMillionUsd: 1, cacheWriteCostPerMillionUsd: 1.25, outputCostPerMillionUsd: 5, apiKeyPlaceholder: 'Access token' }), + provider('dinference', 'DInference', 'https://api.dinference.com/v1', 'minimax-m2.5', 200000, { apiKeyUrl: 'https://dinference.com', inputCostPerMillionUsd: 0.22, outputCostPerMillionUsd: 0.88 }), + provider('drun', 'D.Run (China)', 'https://chat.d.run/v1', 'public/deepseek-v3', 131072, { apiKeyUrl: 'https://www.d.run', inputCostPerMillionUsd: 0.28, outputCostPerMillionUsd: 1.1 }), + provider('evroc', 'evroc', 'https://models.think.evroc.com/v1', 'moonshotai/Kimi-K2.6', 262144, { apiKeyUrl: 'https://docs.evroc.com/products/think/overview.html', supportsVision: true, inputCostPerMillionUsd: 1.4375, outputCostPerMillionUsd: 5.75 }), + provider('fastrouter', 'FastRouter', 'https://go.fastrouter.ai/api/v1', 'moonshotai/kimi-k2', 131072, { apiKeyUrl: 'https://fastrouter.ai/models', inputCostPerMillionUsd: 0.55, outputCostPerMillionUsd: 2.2 }), + provider('friendli', 'Friendli', 'https://api.friendli.ai/serverless/v1', 'google/gemma-4-31B-it', 262144, { apiKeyUrl: 'https://friendli.ai/docs/guides/serverless_endpoints/introduction', supportsVision: true, inputCostPerMillionUsd: 0.14, outputCostPerMillionUsd: 0.4 }), + provider('google-vertex', 'Google Vertex AI', 'https://{vertex_endpoint}/v1/projects/{project}/locations/{location}/endpoints/openapi', 'gemini-2.5-flash', 1048576, { category: 'cloud', apiKeyUrl: 'https://console.cloud.google.com/apis/credentials', apiKeyHeader: 'x-goog-api-key', project: '', location: 'us-central1', supportsVision: true, apiKeyPlaceholder: 'Google authorization key' }), + provider('google-vertex-anthropic', 'Google Vertex AI (Anthropic)', 'https://{vertex_endpoint}', 'claude-haiku-4-5@20251001', 200000, { category: 'cloud', type: 'vertex_anthropic', apiKeyUrl: 'https://console.cloud.google.com/apis/credentials', project: '', location: 'us-east5', supportsVision: true, inputCostPerMillionUsd: 1, cacheReadCostPerMillionUsd: 0.1, cacheWriteCostPerMillionUsd: 1.25, outputCostPerMillionUsd: 5, apiKeyPlaceholder: 'Google authorization key' }), + provider('helicone', 'Helicone', 'https://ai-gateway.helicone.ai/v1', 'chatgpt-4o-latest', 128000, { apiKeyUrl: 'https://helicone.ai/', inputCostPerMillionUsd: 5, cacheReadCostPerMillionUsd: 2.5, outputCostPerMillionUsd: 20 }), + provider('iflowcn', 'iFlow', 'https://apis.iflow.cn/v1', 'qwen3-coder-plus', 256000, { apiKeyUrl: 'https://platform.iflow.cn/en/docs' }), + provider('inception', 'Inception', 'https://api.inceptionlabs.ai/v1', 'mercury-2', 128000, { category: 'cloud', apiKeyUrl: 'https://platform.inceptionlabs.ai/docs', inputCostPerMillionUsd: 0.25, cacheReadCostPerMillionUsd: 0.025, outputCostPerMillionUsd: 0.75 }), + provider('inference', 'Inference.net', 'https://inference.net/v1', 'mistral/mistral-nemo-12b-instruct', 16000, { apiKeyUrl: 'https://inference.net/models', inputCostPerMillionUsd: 0.038, outputCostPerMillionUsd: 0.1 }), + provider('io-net', 'IO.NET', 'https://api.intelligence.io.solutions/api/v1', 'meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8', 430000, { apiKeyUrl: 'https://io.net/docs/guides/intelligence/io-intelligence', inputCostPerMillionUsd: 0.15, cacheReadCostPerMillionUsd: 0.075, cacheWriteCostPerMillionUsd: 0.3, outputCostPerMillionUsd: 0.6 }), + provider('jiekou', 'Jiekou.AI', 'https://api.jiekou.ai/openai', 'o3', 131072, { apiKeyUrl: 'https://docs.jiekou.ai/docs/support/quickstart', supportsVision: true, inputCostPerMillionUsd: 10, outputCostPerMillionUsd: 40 }), + provider('kilo', 'Kilo Gateway', 'https://api.kilo.ai/api/gateway', 'inclusionai/ling-2.6-1t', 262144, { apiKeyUrl: 'https://kilo.ai', inputCostPerMillionUsd: 0.3, cacheReadCostPerMillionUsd: 0.06, outputCostPerMillionUsd: 2.5 }), + provider('kimi-for-coding', 'Kimi For Coding', 'https://api.kimi.com/coding/v1', 'kimi-for-coding', 262144, { category: 'cloud', apiKeyUrl: 'https://www.kimi.com/code/docs/en/', supportsVision: true, suggestions: ['kimi-for-coding', 'kimi-for-coding-highspeed', 'k3'] }), + provider('kuae-cloud-coding-plan', 'KUAE Cloud Coding Plan', 'https://coding-plan-endpoint.kuaecloud.net/v1', 'GLM-4.7', 204800, { category: 'cloud', apiKeyUrl: 'https://docs.mthreads.com/kuaecloud/kuaecloud-doc-online/coding_plan/' }), + provider('llama', 'Meta Llama API', 'https://api.llama.com/compat/v1', 'llama-4-scout-17b-16e-instruct-fp8', 128000, { category: 'cloud', apiKeyUrl: 'https://llama.developer.meta.com/', supportsVision: true }), + provider('lucidquery', 'LucidQuery', 'https://api.lucidquery.com/v1', 'lucidnova-rf1-100b', 120000, { apiKeyUrl: 'https://lucidquery.com/docs', supportsVision: true, inputCostPerMillionUsd: 2, outputCostPerMillionUsd: 5 }), + provider('meganova', 'Meganova', 'https://api.meganova.ai/v1', 'meta-llama/Llama-3.3-70B-Instruct', 131072, { apiKeyUrl: 'https://docs.meganova.ai', inputCostPerMillionUsd: 0.1, outputCostPerMillionUsd: 0.3 }), + provider('minimax-cn-coding-plan', 'MiniMax Token Plan (China)', 'https://api.minimaxi.com/v1', 'MiniMax-M2.1', 204800, { category: 'cloud', apiKeyUrl: 'https://platform.minimaxi.com/docs/token-plan/intro' }), + provider('minimax-coding-plan', 'MiniMax Token Plan', 'https://api.minimax.io/v1', 'MiniMax-M2.1', 204800, { category: 'cloud', apiKeyUrl: 'https://platform.minimax.io/docs/token-plan/intro' }), + provider('moark', 'Moark', 'https://moark.com/v1', 'MiniMax-M2.1', 204800, { apiKeyUrl: 'https://moark.com/docs/openapi/v1', inputCostPerMillionUsd: 2.1, outputCostPerMillionUsd: 8.4 }), + provider('modelscope', 'ModelScope', 'https://api-inference.modelscope.cn/v1', 'Qwen/Qwen3-30B-A3B-Thinking-2507', 262144, { apiKeyUrl: 'https://modelscope.cn/docs/model-service/API-Inference/intro' }), + provider('morph', 'Morph', 'https://api.morphllm.com/v1', 'morph-v3-fast', 16000, { category: 'cloud', apiKeyUrl: 'https://docs.morphllm.com/api-reference/introduction', supportsTools: false, inputCostPerMillionUsd: 0.8, outputCostPerMillionUsd: 1.2 }), + provider('nano-gpt', 'NanoGPT', 'https://nano-gpt.com/api/v1', 'claude-opus-4-thinking:8192', 200000, { apiKeyUrl: 'https://docs.nano-gpt.com', supportsVision: true, inputCostPerMillionUsd: 14.994, outputCostPerMillionUsd: 75.004 }), + provider('nebius', 'Nebius Token Factory', 'https://api.tokenfactory.nebius.com/v1', 'meta-llama/Llama-3.3-70B-Instruct', 128000, { apiKeyUrl: 'https://docs.tokenfactory.nebius.com/', inputCostPerMillionUsd: 0.13, cacheReadCostPerMillionUsd: 0.013, cacheWriteCostPerMillionUsd: 0.16, outputCostPerMillionUsd: 0.4 }), + provider('nova', 'Amazon Nova', 'https://api.nova.amazon.com/v1', 'nova-2-pro-v1', 1000000, { category: 'cloud', apiKeyUrl: 'https://nova.amazon.com/dev/documentation', supportsVision: true }), + provider('novita-ai', 'NovitaAI', 'https://api.novita.ai/openai', 'inclusionai/ling-2.6-1t', 262144, { apiKeyUrl: 'https://novita.ai/docs/guides/introduction', inputCostPerMillionUsd: 0.3, cacheReadCostPerMillionUsd: 0.06, outputCostPerMillionUsd: 2.5 }), + provider('ollama-cloud', 'Ollama Cloud', 'https://ollama.com/v1', 'deepseek-v4-flash', 1048576, { category: 'cloud', apiKeyUrl: 'https://docs.ollama.com/cloud' }), + provider('opencode', 'OpenCode Zen', 'https://opencode.ai/zen/v1', 'ring-2.6-1t-free', 262000, { apiKeyUrl: 'https://opencode.ai/docs/zen' }), + provider('opencode-go', 'OpenCode Go', 'https://opencode.ai/zen/go/v1', 'deepseek-v4-flash', 1000000, { apiKeyUrl: 'https://opencode.ai/docs/zen', inputCostPerMillionUsd: 0.14, cacheReadCostPerMillionUsd: 0.0028, outputCostPerMillionUsd: 0.28 }), + provider('ovhcloud', 'OVHcloud AI Endpoints', 'https://oai.endpoints.kepler.ai.cloud.ovh.net/v1', 'qwen3-coder-30b-a3b-instruct', 262144, { apiKeyUrl: 'https://www.ovhcloud.com/en/public-cloud/ai-endpoints/catalog/', inputCostPerMillionUsd: 0.07, outputCostPerMillionUsd: 0.26 }), + provider('perplexity', 'Perplexity Sonar', 'https://api.perplexity.ai', 'sonar-reasoning-pro', 128000, { category: 'cloud', apiKeyUrl: 'https://www.perplexity.ai/settings/api', supportsVision: true, supportsTools: false, inputCostPerMillionUsd: 2, outputCostPerMillionUsd: 8 }), + provider('perplexity-agent', 'Perplexity Agent', 'https://api.perplexity.ai/v1', 'xai/grok-4-1-fast-non-reasoning', 2000000, { category: 'cloud', apiKeyUrl: 'https://www.perplexity.ai/settings/api', supportsVision: true, apiFormat: 'responses', inputCostPerMillionUsd: 0.2, cacheReadCostPerMillionUsd: 0.05, outputCostPerMillionUsd: 0.5 }), + provider('poe', 'Poe', 'https://api.poe.com/v1', 'trytako/tako', 2048, { apiKeyUrl: 'https://poe.com/api_key', supportsVision: true }), + provider('privatemode-ai', 'Privatemode AI', 'http://localhost:8080/v1', 'gemma-3-27b', 128000, { category: 'local', apiKeyUrl: 'https://docs.privatemode.ai/api/overview', supportsVision: true }), + provider('qihang-ai', 'QiHang', 'https://api.qhaigc.net/v1', 'claude-haiku-4-5-20251001', 200000, { apiKeyUrl: 'https://www.qhaigc.net/docs', supportsVision: true, inputCostPerMillionUsd: 0.14, outputCostPerMillionUsd: 0.71 }), + provider('qiniu-ai', 'Qiniu', 'https://api.qnaigc.com/v1', 'deepseek-r1-0528', 128000, { apiKeyUrl: 'https://developer.qiniu.com/aitokenapi' }), + provider('requesty', 'Requesty', 'https://router.requesty.ai/v1', 'xai/grok-4', 256000, { apiKeyUrl: 'https://requesty.ai/solution/llm-routing/models', supportsVision: true, inputCostPerMillionUsd: 3, cacheReadCostPerMillionUsd: 0.75, cacheWriteCostPerMillionUsd: 3, outputCostPerMillionUsd: 15 }), + provider('scaleway', 'Scaleway', 'https://api.scaleway.ai/v1', 'qwen3-235b-a22b-instruct-2507', 260000, { apiKeyUrl: 'https://www.scaleway.com/en/docs/generative-apis/', inputCostPerMillionUsd: 0.75, outputCostPerMillionUsd: 2.25 }), + provider('siliconflow', 'SiliconFlow', 'https://api.siliconflow.com/v1', 'moonshotai/Kimi-K2.6', 262000, { apiKeyUrl: 'https://cloud.siliconflow.com/account/ak', inputCostPerMillionUsd: 0.77, cacheReadCostPerMillionUsd: 0.2, outputCostPerMillionUsd: 4 }), + provider('siliconflow-cn', 'SiliconFlow (China)', 'https://api.siliconflow.cn/v1', 'baidu/ERNIE-4.5-300B-A47B', 131000, { apiKeyUrl: 'https://cloud.siliconflow.cn/account/ak', inputCostPerMillionUsd: 0.28, outputCostPerMillionUsd: 1.1 }), + provider('stackit', 'STACKIT', 'https://api.openai-compat.model-serving.eu01.onstackit.cloud/v1', 'cortecs/Llama-3.3-70B-Instruct-FP8-Dynamic', 128000, { apiKeyUrl: 'https://docs.stackit.cloud/products/data-and-ai/ai-model-serving/', inputCostPerMillionUsd: 0.53, outputCostPerMillionUsd: 0.76 }), + provider('stepfun', 'StepFun', 'https://api.stepfun.com/v1', 'step-1-32k', 32768, { category: 'cloud', apiKeyUrl: 'https://platform.stepfun.com/docs/zh/overview/concept', inputCostPerMillionUsd: 2.05, cacheReadCostPerMillionUsd: 0.41, outputCostPerMillionUsd: 9.59 }), + provider('submodel', 'submodel', 'https://llm.submodel.ai/v1', 'Qwen/Qwen3-235B-A22B-Thinking-2507', 262144, { apiKeyUrl: 'https://submodel.gitbook.io', inputCostPerMillionUsd: 0.2, outputCostPerMillionUsd: 0.6 }), + provider('synthetic', 'Synthetic', 'https://api.synthetic.new/openai/v1', 'hf:moonshotai/Kimi-K2.7-Code', 262144, { apiKeyUrl: 'https://synthetic.new/', supportsVision: true, inputCostPerMillionUsd: 0.95, cacheReadCostPerMillionUsd: 0.95, outputCostPerMillionUsd: 4 }), + provider('tencent-coding-plan', 'Tencent Coding Plan (China)', 'https://api.lkeap.cloud.tencent.com/coding/v3', 'minimax-m2.5', 204800, { category: 'cloud', apiKeyUrl: 'https://cloud.tencent.com/document/product/1772/128947' }), + provider('upstage', 'Upstage', 'https://api.upstage.ai/v1/solar', 'solar-pro2', 65536, { category: 'cloud', apiKeyUrl: 'https://console.upstage.ai/api-keys', inputCostPerMillionUsd: 0.25, outputCostPerMillionUsd: 0.25 }), + provider('v0', 'v0', 'https://api.v0.dev/v1', 'v0-1.0-md', 128000, { category: 'cloud', apiKeyUrl: 'https://v0.dev/chat/settings/keys', supportsVision: true, inputCostPerMillionUsd: 3, outputCostPerMillionUsd: 15 }), + provider('venice', 'Venice AI', 'https://api.venice.ai/api/v1', 'z-ai-glm-5-turbo', 200000, { apiKeyUrl: 'https://venice.ai/settings/api', inputCostPerMillionUsd: 1.2, cacheReadCostPerMillionUsd: 0.24, outputCostPerMillionUsd: 4 }), + provider('vercel', 'Vercel AI Gateway', 'https://ai-gateway.vercel.sh/v1', 'xai/grok-4.1-fast-reasoning', 1000000, { apiKeyUrl: 'https://vercel.com/ai-gateway', inputCostPerMillionUsd: 0.2, cacheReadCostPerMillionUsd: 0.05, outputCostPerMillionUsd: 0.5 }), + provider('vivgrid', 'Vivgrid', 'https://api.vivgrid.com/v1', 'deepseek-v4-pro', 1000000, { apiKeyUrl: 'https://docs.vivgrid.com/models', inputCostPerMillionUsd: 0.435, cacheReadCostPerMillionUsd: 0.003625, outputCostPerMillionUsd: 0.87 }), + provider('vultr', 'Vultr', 'https://api.vultrinference.com/v1', 'moonshotai/Kimi-K2.6', 262144, { apiKeyUrl: 'https://my.vultr.com/', supportsVision: true, inputCostPerMillionUsd: 0.3, outputCostPerMillionUsd: 1.2 }), + provider('wandb', 'Weights & Biases', 'https://api.inference.wandb.ai/v1', 'ibm-granite/granite-4.1-8b', 131072, { apiKeyUrl: 'https://wandb.ai/authorize', inputCostPerMillionUsd: 0.05, cacheReadCostPerMillionUsd: 0.05, outputCostPerMillionUsd: 0.1 }), + provider('xiaomi', 'Xiaomi MiMo', 'https://api.xiaomimimo.com/v1', 'mimo-v2.5-pro-ultraspeed', 1048576, { category: 'cloud', apiKeyUrl: 'https://platform.xiaomimimo.com/', inputCostPerMillionUsd: 1.305, cacheReadCostPerMillionUsd: 0.0108, outputCostPerMillionUsd: 2.61 }), + provider('zai-coding-plan', 'Z.AI Coding Plan', 'https://api.z.ai/api/coding/paas/v4', 'glm-4.7', 204800, { category: 'cloud', apiKeyUrl: 'https://docs.z.ai/devpack/overview' }), + provider('zenmux', 'ZenMux', 'https://zenmux.ai/api/v1', 'inclusionai/ling-1t', 128000, { apiKeyUrl: 'https://docs.zenmux.ai', inputCostPerMillionUsd: 0.56, cacheReadCostPerMillionUsd: 0.11, outputCostPerMillionUsd: 2.24 }), + provider('zhipuai', 'Zhipu AI', 'https://open.bigmodel.cn/api/paas/v4', 'glm-5.1', 200000, { category: 'cloud', apiKeyUrl: 'https://open.bigmodel.cn/usercenter/apikeys', inputCostPerMillionUsd: 1.4, cacheReadCostPerMillionUsd: 0.26, outputCostPerMillionUsd: 4.4 }), + provider('zhipuai-coding-plan', 'Zhipu AI Coding Plan', 'https://open.bigmodel.cn/api/coding/paas/v4', 'glm-5.1', 200000, { category: 'cloud', apiKeyUrl: 'https://docs.bigmodel.cn/cn/coding-plan/overview' }), +]; + +export const ADDITIONAL_PROVIDER_IDS = Object.freeze(PROVIDERS.map(({ id }) => id)); + +export const ADDITIONAL_PROVIDER_DEFAULTS = Object.freeze(Object.fromEntries( + PROVIDERS.map(({ id, config }) => [id, Object.freeze(config)]), +)); + +export const ADDITIONAL_PROVIDER_UI = Object.freeze(Object.fromEntries( + PROVIDERS.map(({ id, ui }) => [id, Object.freeze(ui)]), +)); diff --git a/src/chrome/src/providers/provider-compatibility.js b/src/chrome/src/providers/provider-compatibility.js index 0c7a0b6fa..60d1c026f 100644 --- a/src/chrome/src/providers/provider-compatibility.js +++ b/src/chrome/src/providers/provider-compatibility.js @@ -57,6 +57,7 @@ export function isOfficialOpenAIConfig(config = {}) { } export function shouldUseOpenAIResponsesApi(config = {}) { + if (config.apiFormat === 'responses') return true; if (!isOfficialOpenAIConfig(config)) return false; const model = String(config.model || '').trim().toLowerCase(); // GPT-5.6 needs Responses for reliable reasoning/tool replay. GPT-5 Pro, diff --git a/src/chrome/src/providers/vertex-anthropic.js b/src/chrome/src/providers/vertex-anthropic.js new file mode 100644 index 000000000..f25a0a7e6 --- /dev/null +++ b/src/chrome/src/providers/vertex-anthropic.js @@ -0,0 +1,63 @@ +import { AnthropicProvider } from './anthropic.js'; + +/** + * Anthropic Claude through Vertex AI's rawPredict/streamRawPredict endpoints. + * Authentication uses a user-created Google authorization key rather than an + * interactive OAuth flow. + */ +export class VertexAnthropicProvider extends AnthropicProvider { + get name() { + return 'google-vertex-anthropic'; + } + + get supportsVision() { + return this.config.supportsVision !== false; + } + + _vertexCoordinates() { + const project = String(this.config.project || '').trim(); + const location = String(this.config.location || '').trim(); + if (!/^[a-z][a-z0-9:._-]{4,127}$/i.test(project)) { + throw new Error('Google Cloud project ID is required.'); + } + if (!/^[a-z0-9-]+$/i.test(location)) { + throw new Error('Google Cloud location is required.'); + } + if (!String(this.config.apiKey || '').trim()) { + throw new Error('Google authorization key is required.'); + } + return { project, location }; + } + + _headers() { + return { + 'Content-Type': 'application/json', + 'x-goog-api-key': String(this.config.apiKey || ''), + }; + } + + _vertexEndpointHost(location) { + const normalized = String(location || '').trim().toLowerCase(); + if (normalized === 'global') return 'aiplatform.googleapis.com'; + if (normalized === 'us' || normalized === 'eu') { + return `aiplatform.${normalized}.rep.googleapis.com`; + } + return `${normalized}-aiplatform.googleapis.com`; + } + + _messagesUrl(stream = false) { + const { project, location } = this._vertexCoordinates(); + const action = stream ? 'streamRawPredict' : 'rawPredict'; + const endpointHost = this._vertexEndpointHost(location); + return `https://${endpointHost}/v1/projects/${encodeURIComponent(project)}/locations/${encodeURIComponent(location)}/publishers/anthropic/models/${encodeURIComponent(this.model)}:${action}`; + } + + _prepareRequestBody(body, _options = {}, stream = false) { + const { model: _model, stream: _stream, ...payload } = body; + return { + ...payload, + anthropic_version: 'vertex-2023-10-16', + ...(stream ? { stream: true } : {}), + }; + } +} diff --git a/src/chrome/src/ui/locales/ar.js b/src/chrome/src/ui/locales/ar.js index ba46dff9e..722e7c1d9 100644 --- a/src/chrome/src/ui/locales/ar.js +++ b/src/chrome/src/ui/locales/ar.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'انقطع بث الاستجابة؛ تتم إعادة محاولة دور Ask هذا بدون بث.', 'sp.providers.no_setup_group': 'لا يتطلب إعدادًا', 'sp.providers.no_setup': 'بلا إعداد', 'sp.providers.active_group': 'المزوّدون النشطون', @@ -640,8 +641,8 @@ export default { 'st.display.clarify_timeout.instant': 'فوري', 'st.display.api_mutation_observer.label': 'مراقب تحولات API', 'st.display.api_mutation_observer.desc': 'مراقبة عناوين URL وطرق طلبات XHR/fetch في نفس التبويب ليتمكن WebBrain من اكتشاف إجراءات الواجهة المتكررة واقتراح أنماط اختصارات API. معطل افتراضياً؛ قم بتفعيله فقط أثناء التحقيق في سلوك الاختصار أو زمن الاستجابة.', - 'st.display.openai_ask_streaming.label': 'بث ردود OpenAI في وضع السؤال', - 'st.display.openai_ask_streaming.desc': 'اعرض نص OpenAI Responses الرسمية فور وصوله في وضع السؤال. تنتظر استدعاءات الأدوات response.completed؛ وتبقى تشغيلات Act وDev والمجدولة والسحابية وContinue بدون بث. مفعّل افتراضياً.', + 'st.display.openai_ask_streaming.label': "?? ?????? ?? ??? ??????", + 'st.display.openai_ask_streaming.desc': "???? ???? ??????? ??? ?????? ?? ??? ??????. ????? ????????? ??????? ??? ?????? ??????? ???? ?????? Act ?Dev ????????? ????????? ?Continue ??? ??. ????? ?????????.", 'st.display.plan_before_act.label': 'التخطيط قبل التنفيذ', 'st.display.plan_before_act.desc': 'يجري وضعا Act وDev دائمًا فحصًا منظمًا للنية قبل تشغيل الأدوات. وضع المحاولة (الافتراضي) ينشئ أيضًا خططًا كاملة، لكنه قد يعيد استخدام خطة معتمدة حديثًا لمتابعة قصيرة؛ الوضع الصارم ينشئ خطة كاملة في كل دورة. يعود وضع المحاولة إلى دورة للقراءة فقط إذا ظل القصد أو التخطيط غير صالح بعد محاولة إصلاح واحدة؛ ويتوقف الوضع الصارم قبل تشغيل الأدوات.', 'st.display.plan_before_act.try': 'محاولة التخطيط (افتراضياً)', diff --git a/src/chrome/src/ui/locales/bn.js b/src/chrome/src/ui/locales/bn.js index 1ed42c37d..a704fc6d3 100644 --- a/src/chrome/src/ui/locales/bn.js +++ b/src/chrome/src/ui/locales/bn.js @@ -1,5 +1,6 @@ // Bengali — translated from the canonical English locale. export default { + 'sp.streaming.fallback': 'প্রতিক্রিয়া স্ট্রিম বাধাগ্রস্ত হয়েছে; স্ট্রিমিং ছাড়া এই Ask পালাটি আবার চেষ্টা করা হচ্ছে।', 'sp.providers.no_setup_group': "কোন সেটআপ প্রয়োজন", 'sp.providers.no_setup': "কোনো সেটআপ নেই", 'sp.providers.active_group': "সক্রিয় প্রদানকারী", @@ -494,8 +495,8 @@ export default { 'st.display.api_mutation_observer.desc': "একই-ট্যাব XHR/ফেচ অনুরোধ URL এবং পদ্ধতিগুলি পর্যবেক্ষণ করুন যাতে WebBrain বারবার UI অ্যাকশন সনাক্ত করতে পারে এবং API শর্টকাট প্যাটার্নের পরামর্শ দিতে পারে। ডিফল্টরূপে বন্ধ; শুধুমাত্র শর্টকাট আচরণ বা লেটেন্সি তদন্ত করার সময় সক্ষম করুন।", 'st.display.webmcp.label': "পরীক্ষামূলক WebMCP", 'st.display.webmcp.desc': "WebBrain সমর্থিত Chrome পৃষ্ঠাগুলির দ্বারা প্রকাশিত কাঠামোগত সরঞ্জামগুলি আবিষ্কার এবং চালানোর অনুমতি দিন৷ এটি সক্ষম করলে মডেল প্রসঙ্গে পরীক্ষামূলক WebMCP টুল এবং নির্দেশিকা যোগ হয়। ডিফল্টরূপে বন্ধ।", - 'st.display.openai_ask_streaming.label': "স্ট্রীম OpenAI উত্তর জিজ্ঞাসা করুন", - 'st.display.openai_ask_streaming.desc': "আস্ক মোডে আসার সাথে সাথে অফিসিয়াল OpenAI প্রতিক্রিয়া টেক্সট দেখান। টুল কল প্রতিক্রিয়া জন্য অপেক্ষা করুন.completed; অ্যাক্ট, দেব, নির্ধারিত, ক্লাউড, এবং চালিয়ে যান নন-স্ট্রিমিং থাকুন। ডিফল্টরূপে চালু", + 'st.display.openai_ask_streaming.label': "Ask ????? ????? ??????? ????", + 'st.display.openai_ask_streaming.desc': "Ask ???? ???????????? ????? ???? ????? ????? ?????? ??? ?? ???? ???????? ??????? ???????? ???? ??????? ???; Act, Dev, ?????????, ?????? ? Continue ??? ??????? ??? ??? ?????????? ?????", 'st.display.plan_before_act.label': "আইনের আগে পরিকল্পনা করুন", 'st.display.plan_before_act.desc': "Act এবং Dev সবসময় টুলের আগে একটি স্ট্রাকচার্ড ইনটেন্ট চেক চালান। চেষ্টা করুন (ডিফল্ট) সম্পূর্ণ পরিকল্পনা তৈরি করে তবে একটি সংক্ষিপ্ত ফলো-আপের জন্য সম্প্রতি অনুমোদিত একটি পরিকল্পনা পুনরায় ব্যবহার করতে পারে; কঠোর প্রতি পাল্লায় একটি পূর্ণ পরিকল্পনা তৈরি করে। একটি মেরামতের পরে যদি অভিপ্রায় বা পরিকল্পনা অবৈধ থেকে যায় তবে একটি শুধুমাত্র-পঠনযোগ্য মোড়তে ফিরে যাওয়ার চেষ্টা করুন; সরঞ্জামের আগে কঠোর স্টপ।", 'st.display.plan_before_act.try': "পরিকল্পনা করার চেষ্টা করুন (ডিফল্ট)", diff --git a/src/chrome/src/ui/locales/de.js b/src/chrome/src/ui/locales/de.js index f24d843be..a60c6975d 100644 --- a/src/chrome/src/ui/locales/de.js +++ b/src/chrome/src/ui/locales/de.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Der Antwortstream wurde unterbrochen; dieser Ask-Durchgang wird ohne Streaming erneut versucht.', 'sp.providers.no_setup_group': 'Keine Einrichtung erforderlich', 'sp.providers.no_setup': 'Keine Einrichtung', 'sp.providers.active_group': 'Aktive Anbieter', @@ -489,8 +490,8 @@ export default { 'st.display.api_mutation_observer.desc': 'Beobachtet XHR/fetch-Anfragen-URLs und Methoden im selben Tab, damit WebBrain wiederkehrende UI-Aktionen erkennen und API-Verknüpfungsmuster vorschlagen kann.', 'st.display.webmcp.label': 'Experimentelles WebMCP', 'st.display.webmcp.desc': 'Ermöglicht es WebBrain, von unterstützten Chrome-Seiten bereitgestellte strukturierte Tools zu entdecken und auszuführen.', - 'st.display.openai_ask_streaming.label': 'OpenAI Ask-Antworten streamen', - 'st.display.openai_ask_streaming.desc': 'Zeigt den offiziellen OpenAI Responses-Text in Echtzeit im Fragen-Modus an.', + 'st.display.openai_ask_streaming.label': 'Ask-Antworten streamen', + 'st.display.openai_ask_streaming.desc': 'Zeigt Text für unterstützte Anbieter im Ask-Modus während des Empfangs an. Unterbrochene Streams zeigen einen Hinweis und werden einmal ohne Streaming wiederholt. Werkzeugaufrufe warten auf das Stream-Ende; Act-, Dev-, geplante, Cloud- und Continue-Läufe bleiben ohne Streaming. Standardmäßig aktiviert.', 'st.display.plan_before_act.label': 'Vor dem Handeln planen', 'st.display.plan_before_act.desc': 'Handeln und Dev führen immer eine strukturierte Intent-Prüfung vor den Tools durch.', 'st.display.plan_before_act.try': 'Planierung versuchen (Standard)', diff --git a/src/chrome/src/ui/locales/en.js b/src/chrome/src/ui/locales/en.js index 0948eb048..373125169 100644 --- a/src/chrome/src/ui/locales/en.js +++ b/src/chrome/src/ui/locales/en.js @@ -1,5 +1,6 @@ // English — canonical locale. Other locales inherit key names from this file. export default { + 'sp.streaming.fallback': 'Response streaming was interrupted; retrying this Ask turn without streaming.', 'sp.providers.no_setup_group': 'No setup required', 'sp.providers.no_setup': 'No setup', 'sp.providers.active_group': 'Active providers', @@ -496,7 +497,7 @@ export default { 'st.display.webmcp.desc': 'Allow WebBrain to discover and run structured tools exposed by supported Chrome pages. Enabling this adds experimental WebMCP tools and guidance to the model context. Off by default.', // TRANSLATORS: Updated for multi-provider Ask streaming and silent transport fallback. 'st.display.openai_ask_streaming.label': 'Stream Ask responses', - 'st.display.openai_ask_streaming.desc': 'Show text as it arrives in Ask mode for supported providers. Interrupted streams silently retry once without streaming; provider/API errors are still shown. Tool calls wait for stream completion; Act, Dev, scheduled, cloud, and Continue runs stay non-streaming. On by default.', + 'st.display.openai_ask_streaming.desc': 'Show text as it arrives in Ask mode for supported providers. Interrupted streams show a notice and retry once without streaming; provider/API errors are still shown. Tool calls wait for stream completion; Act, Dev, scheduled, cloud, and Continue runs stay non-streaming. On by default.', 'st.display.plan_before_act.label': 'Plan before Act', 'st.display.plan_before_act.desc': 'Act and Dev always run a structured intent check before tools. Try (default) also builds full plans but may reuse a recently approved plan for a short follow-up; Strict builds a full plan every turn. Try falls back to a read-only turn if intent or planning remains invalid after one repair; Strict stops before tools.', 'st.display.plan_before_act.try': 'Try planning (default)', diff --git a/src/chrome/src/ui/locales/es.js b/src/chrome/src/ui/locales/es.js index 6621b4e00..504ed363c 100644 --- a/src/chrome/src/ui/locales/es.js +++ b/src/chrome/src/ui/locales/es.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Se interrumpió la transmisión de la respuesta; reintentando este turno de Ask sin transmisión.', 'sp.providers.no_setup_group': 'Sin configuración', 'sp.providers.no_setup': 'No requiere configuración', 'sp.providers.active_group': 'Proveedores activos', @@ -640,8 +641,8 @@ export default { 'st.display.clarify_timeout.instant': 'Instantáneo', 'st.display.api_mutation_observer.label': 'Observador de mutaciones de API', 'st.display.api_mutation_observer.desc': 'Observa las URLs y métodos de peticiones XHR/fetch en la misma pestaña para que WebBrain pueda detectar acciones repetidas de la interfaz y sugerir patrones de acceso directo por API. Desactivado por defecto; actívalo solo mientras investigas comportamientos de acceso directo o latencia.', - 'st.display.openai_ask_streaming.label': 'Transmitir respuestas OpenAI en Ask', - 'st.display.openai_ask_streaming.desc': 'Muestra el texto de OpenAI Responses oficial a medida que llega en modo Ask. Las llamadas a herramientas esperan a response.completed; Act, Dev, las ejecuciones programadas, en la nube y Continue siguen sin transmisión. Activado por defecto.', + 'st.display.openai_ask_streaming.label': "Transmitir respuestas en modo Ask", + 'st.display.openai_ask_streaming.desc': "Muestra las respuestas del proveedor a medida que llegan en modo Ask. Las llamadas a herramientas esperan un evento final del flujo; Act, Dev, las ejecuciones programadas, en la nube y Continue siguen sin transmisi?n. Activado por defecto.", 'st.display.plan_before_act.label': 'Planificar antes de actuar', 'st.display.plan_before_act.desc': 'Los modos Actuar y Dev siempre ejecutan una comprobación estructurada de intención antes de las herramientas. Intentar (predeterminado) también crea planes completos, pero puede reutilizar un plan aprobado recientemente para un seguimiento breve; Estricto crea un plan completo en cada turno. Intentar recurre a un turno de solo lectura si la intención o el plan siguen siendo inválidos tras una reparación; Estricto se detiene antes de usar herramientas.', 'st.display.plan_before_act.try': 'Intentar planificar (por defecto)', diff --git a/src/chrome/src/ui/locales/fa.js b/src/chrome/src/ui/locales/fa.js index 4923606cd..df69e5ccc 100644 --- a/src/chrome/src/ui/locales/fa.js +++ b/src/chrome/src/ui/locales/fa.js @@ -1,5 +1,6 @@ // Persian — translated from the canonical English locale. export default { + 'sp.streaming.fallback': 'جریان پاسخ قطع شد؛ این نوبت Ask بدون پخش جریانی دوباره امتحان می‌شود.', 'sp.providers.no_setup_group': "بدون نیاز به راه اندازی", 'sp.providers.no_setup': "بدون راه اندازی", 'sp.providers.active_group': "ارائه دهندگان فعال", @@ -494,8 +495,8 @@ export default { 'st.display.api_mutation_observer.desc': "نشانی‌های وب و روش‌های درخواستی XHR/واکشی همان تب را مشاهده کنید تا WebBrain بتواند اقدامات مکرر UI را تشخیص دهد و الگوهای میانبر API را پیشنهاد کند. خاموش به طور پیش فرض؛ فقط هنگام بررسی رفتار میانبر یا تأخیر فعال شود.", 'st.display.webmcp.label': "WebMCP آزمایشی", 'st.display.webmcp.desc': "به WebBrain اجازه دهید ابزارهای ساخت یافته ای را که توسط صفحات پشتیبانی شده Chrome در معرض دید قرار گرفته اند را کشف و اجرا کند. فعال کردن این، ابزارهای آزمایشی WebMCP و راهنمایی را به بافت مدل اضافه می کند. به طور پیش فرض خاموش است.", - 'st.display.openai_ask_streaming.label': "پخش جریانی OpenAI پاسخ‌ها را بپرسید", - 'st.display.openai_ask_streaming.desc': "نمایش رسمی OpenAI به متن پاسخ می دهد که در حالت سؤال می رسد. فراخوانی ابزار منتظر answer.completed است. اجراهای Act، Dev، برنامه‌ریزی‌شده، ابری و Continue پخش نمی‌شوند. به طور پیش فرض روشن است.", + 'st.display.openai_ask_streaming.label': "??? ??????? ?? ???? Ask", + 'st.display.openai_ask_streaming.desc': "???????? ??????????? ?? ????? ?????? ?? ???? Ask ????? ????. ???????? ????? ????? ?????? ?????? ????? ???????? ??????? Act? Dev? ?????????????? ???? ? Continue ???? ??? ???? ????????. ?????? ??????? ???? ???.", 'st.display.plan_before_act.label': "قبل از قانون برنامه ریزی کنید", 'st.display.plan_before_act.desc': "Act و Dev همیشه قبل از ابزارها یک بررسی قصد ساخت یافته انجام می دهند. سعی کنید (پیش‌فرض) همچنین برنامه‌های کاملی را ایجاد می‌کند، اما ممکن است از طرحی که اخیراً تأیید شده است برای یک پیگیری کوتاه دوباره استفاده کنید. Strict در هر نوبت یک برنامه کامل می سازد. اگر بعد از یک بار تعمیر، قصد یا برنامه ریزی نامعتبر باقی بماند، سعی به یک نوبت فقط خواندنی برمی گردد. توقف های سخت قبل از ابزار.", 'st.display.plan_before_act.try': "برنامه ریزی را امتحان کنید (پیش فرض)", diff --git a/src/chrome/src/ui/locales/fr.js b/src/chrome/src/ui/locales/fr.js index 50af2789f..b3e909bd6 100644 --- a/src/chrome/src/ui/locales/fr.js +++ b/src/chrome/src/ui/locales/fr.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Le flux de réponse a été interrompu ; nouvelle tentative de ce tour Ask sans streaming.', 'sp.providers.no_setup_group': 'Sans configuration', 'sp.providers.no_setup': 'Aucune configuration requise', 'sp.providers.active_group': 'Fournisseurs actifs', @@ -640,8 +641,8 @@ export default { 'st.display.clarify_timeout.instant': 'Immédiat', 'st.display.api_mutation_observer.label': 'Observateur de mutations API', 'st.display.api_mutation_observer.desc': 'Observer les URLs et méthodes des requêtes XHR/fetch dans le même onglet pour que WebBrain puisse détecter des actions UI répétées et suggérer des modèles de raccourcis API. Désactivé par défaut ; activer seulement lors de l\'investigation de comportements de raccourci ou de latence.', - 'st.display.openai_ask_streaming.label': 'Diffuser les réponses OpenAI en mode Ask', - 'st.display.openai_ask_streaming.desc': 'Afficher le texte officiel de OpenAI Responses au fil de son arrivée en mode Ask. Les appels outils attendent response.completed ; Act, Dev, les exécutions planifiées, cloud et Continue restent sans diffusion. Activé par défaut.', + 'st.display.openai_ask_streaming.label': "Diffuser les r?ponses en mode Ask", + 'st.display.openai_ask_streaming.desc': "Afficher les r?ponses du fournisseur au fil de leur arriv?e en mode Ask. Les appels d?outils attendent un ?v?nement terminal du flux ; Act, Dev, les ex?cutions planifi?es, cloud et Continue restent sans diffusion. Activ? par d?faut.", 'st.display.plan_before_act.label': 'Planifier avant d\'agir', 'st.display.plan_before_act.desc': 'Les modes Act et Dev effectuent toujours une vérification structurée de l’intention avant les outils. Essai (par défaut) crée aussi des plans complets, mais peut réutiliser un plan récemment approuvé pour un bref suivi ; Strict crée un plan complet à chaque tour. Essai passe à un tour en lecture seule si l’intention ou le plan reste invalide après une réparation ; Strict s’arrête avant les outils.', 'st.display.plan_before_act.try': 'Essayer la planification (par défaut)', diff --git a/src/chrome/src/ui/locales/he.js b/src/chrome/src/ui/locales/he.js index 597fd984f..03a98d94b 100644 --- a/src/chrome/src/ui/locales/he.js +++ b/src/chrome/src/ui/locales/he.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'הזרמת התשובה נקטעה; מתבצע ניסיון חוזר לתור Ask הזה ללא הזרמה.', 'sp.providers.no_setup_group': 'ללא הגדרה', 'sp.providers.no_setup': 'אין צורך בהגדרה', 'sp.providers.active_group': 'ספקים פעילים', @@ -462,8 +463,8 @@ export default { "st.display.voice_input.desc": "תן ללחצן המיקרופון בקלט הצ'אט להכתיב טקסט באמצעות זיהוי הדיבור של הדפדפן שלך. פועל כברירת מחדל בדפדפנים התומכים בו.", "st.display.api_mutation_observer.label": "מעקב אחר שינויי API", "st.display.api_mutation_observer.desc": "עקוב אחר כתובות URL ושיטות של בקשות XHR/fetch באותה כרטיסייה, כדי ש-WebBrain יוכל לזהות פעולות חוזרות בממשק ולהציע דפוסי קיצור דרך דרך ה-API. כבוי כברירת מחדל; הפעל רק בעת בדיקת קיצורי דרך או זמני תגובה.", - "st.display.openai_ask_streaming.label": "הזרמת תשובות OpenAI במצב Ask", - "st.display.openai_ask_streaming.desc": "הצג טקסט רשמי של OpenAI Responses בזמן הגעתו במצב Ask. קריאות לכלים ממתינות ל-response.completed; הפעלות Act, Dev, מתוזמנות, בענן ו-Continue נשארות ללא הזרמה. מופעל כברירת מחדל.", + 'st.display.openai_ask_streaming.label': "????? ?????? ???? Ask", + 'st.display.openai_ask_streaming.desc': "??? ?? ?????? ???? ???? ????? ???? Ask. ?????? ????? ??????? ?????? ???? ?? ????; ?????? Act, Dev, ????????, ???? ?-Continue ?????? ??? ?????. ????? ?????? ????.", "st.display.webmcp.label": "WebMCP ניסיוני", "st.display.webmcp.desc": "אפשר ל-WebBrain לגלות ולהפעיל כלים מובנים שדפי Chrome נתמכים חושפים. הפעלה מוסיפה את כלי WebMCP הניסיוניים ואת ההנחיות שלהם להקשר של המודל. כבוי כברירת מחדל.", "st.display.plan_before_act.label": "תכנן לפני מעשה", diff --git a/src/chrome/src/ui/locales/hi.js b/src/chrome/src/ui/locales/hi.js index 8b647cc71..9dbeea5e8 100644 --- a/src/chrome/src/ui/locales/hi.js +++ b/src/chrome/src/ui/locales/hi.js @@ -1,5 +1,6 @@ // Hindi — translated from the canonical English locale. export default { + 'sp.streaming.fallback': 'प्रतिक्रिया स्ट्रीम बाधित हुई; इस Ask टर्न को बिना स्ट्रीमिंग के फिर से आज़माया जा रहा है।', 'sp.providers.no_setup_group': "किसी सेटअप की आवश्यकता नहीं है", 'sp.providers.no_setup': "कोई सेटअप नहीं", 'sp.providers.active_group': "सक्रिय प्रदाता", @@ -494,8 +495,8 @@ export default { 'st.display.api_mutation_observer.desc': "समान-टैब XHR/फ़ेच अनुरोध URL और विधियों का निरीक्षण करें ताकि WebBrain बार-बार होने वाली UI क्रियाओं का पता लगा सके और API शॉर्टकट पैटर्न सुझा सके। डिफ़ॉल्ट रूप से बंद; शॉर्टकट व्यवहार या विलंबता की जांच करते समय ही सक्षम करें।", 'st.display.webmcp.label': "प्रायोगिक वेबएमसीपी", 'st.display.webmcp.desc': "WebBrain को समर्थित Chrome पृष्ठों द्वारा प्रदर्शित संरचित टूल को खोजने और चलाने की अनुमति दें। इसे सक्षम करने से मॉडल संदर्भ में प्रयोगात्मक WebMCP उपकरण और मार्गदर्शन जुड़ जाता है। डिफ़ॉल्ट रूप से बंद.", - 'st.display.openai_ask_streaming.label': "स्ट्रीम OpenAI प्रतिक्रियाएँ पूछें", - 'st.display.openai_ask_streaming.desc': "आस्क मोड में आते ही आधिकारिक OpenAI प्रतिक्रिया टेक्स्ट दिखाएं। टूल कॉल प्रतिक्रिया के लिए प्रतीक्षा करें। पूर्ण; एक्ट, डेव, शेड्यूल्ड, क्लाउड और कंटिन्यू रन नॉन-स्ट्रीमिंग रहते हैं। डिफ़ॉल्ट रूप से चालू.", + 'st.display.openai_ask_streaming.label': "Ask ??? ??? ????? ??????? ????", + 'st.display.openai_ask_streaming.desc': "Ask ??? ??? ??????? ?? ????? ??? ?? ??????? ??? ??? ????? ??????? ????? ?? ????????? ???? ???; Act, Dev, ?????????, ?????? ?? Continue ?? ???? ?????????? ?? ???? ???? ???????? ??? ?? ?????", 'st.display.plan_before_act.label': "अधिनियम से पहले योजना बनाएं", 'st.display.plan_before_act.desc': "एक्ट और डेव हमेशा टूल से पहले एक संरचित इरादे की जांच चलाते हैं। प्रयास (डिफ़ॉल्ट) भी पूर्ण योजनाएँ बनाता है, लेकिन संक्षिप्त अनुवर्ती कार्रवाई के लिए हाल ही में स्वीकृत योजना का पुन: उपयोग कर सकता है; स्ट्रिक्ट हर मोड़ पर एक पूर्ण योजना बनाता है। यदि एक मरम्मत के बाद इरादा या योजना अमान्य रहती है तो प्रयास केवल पढ़ने योग्य मोड़ पर वापस आ जाता है; औजारों से पहले सख्त रोक.", 'st.display.plan_before_act.try': "योजना बनाने का प्रयास करें (डिफ़ॉल्ट)", diff --git a/src/chrome/src/ui/locales/id.js b/src/chrome/src/ui/locales/id.js index 9a96d45bc..78cdc8400 100644 --- a/src/chrome/src/ui/locales/id.js +++ b/src/chrome/src/ui/locales/id.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Streaming respons terputus; mencoba kembali giliran Ask ini tanpa streaming.', 'sp.providers.no_setup_group': 'Tanpa penyiapan', 'sp.providers.no_setup': 'Tidak perlu penyiapan', 'sp.providers.active_group': 'Penyedia aktif', @@ -640,8 +641,8 @@ export default { 'st.display.clarify_timeout.instant': 'Instan', 'st.display.api_mutation_observer.label': 'Pengamat mutasi API', 'st.display.api_mutation_observer.desc': 'Amati URL dan metode permintaan XHR/fetch pada tab yang sama sehingga WebBrain dapat mendeteksi tindakan UI berulang dan menyarankan pola pintasan API. Nonaktif secara default; aktifkan hanya saat menyelidiki perilaku pintasan atau latensi.', - 'st.display.openai_ask_streaming.label': 'Streaming respons OpenAI di mode Ask', - 'st.display.openai_ask_streaming.desc': 'Tampilkan teks OpenAI Responses resmi saat tiba di mode Ask. Panggilan alat menunggu response.completed; Act, Dev, proses terjadwal, cloud, dan Continue tetap tanpa streaming. Aktif secara default.', + 'st.display.openai_ask_streaming.label': "Streaming respons dalam mode Ask", + 'st.display.openai_ask_streaming.desc': "Tampilkan respons penyedia saat diterima dalam mode Ask. Panggilan alat menunggu peristiwa akhir stream; proses Act, Dev, terjadwal, cloud, dan Continue tetap tanpa streaming. Aktif secara default.", 'st.display.plan_before_act.label': 'Rencanakan sebelum Bertindak', 'st.display.plan_before_act.desc': 'Mode Bertindak dan Dev selalu menjalankan pemeriksaan niat terstruktur sebelum alat. Coba (default) juga membuat rencana lengkap, tetapi dapat memakai kembali rencana yang baru disetujui untuk tindak lanjut singkat; Ketat membuat rencana lengkap setiap giliran. Coba beralih ke giliran hanya-baca jika niat atau rencana tetap tidak valid setelah satu perbaikan; Ketat berhenti sebelum alat.', 'st.display.plan_before_act.try': 'Coba perencanaan (default)', diff --git a/src/chrome/src/ui/locales/ja.js b/src/chrome/src/ui/locales/ja.js index 18a0c1354..9356cf620 100644 --- a/src/chrome/src/ui/locales/ja.js +++ b/src/chrome/src/ui/locales/ja.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': '応答ストリームが中断されました。この Ask ターンをストリーミングなしで再試行します。', 'sp.providers.no_setup_group': '設定不要', 'sp.providers.no_setup': '設定なし', 'sp.providers.active_group': '有効なプロバイダー', @@ -640,8 +641,8 @@ export default { 'st.display.clarify_timeout.instant': '即時', 'st.display.api_mutation_observer.label': 'API変更オブザーバー', 'st.display.api_mutation_observer.desc': '同じタブの XHR/fetch リクエスト URL とメソッドを監視し、WebBrain が繰り返しの UI アクションを検出して API ショートカットパターンを提案できるようにします。デフォルトではオフ。ショートカット動作やレイテンシの調査中のみ有効にしてください。', - 'st.display.openai_ask_streaming.label': 'Ask の OpenAI 応答をストリーミング', - 'st.display.openai_ask_streaming.desc': 'Ask モードで公式 OpenAI Responses のテキストを到着と同時に表示します。ツール呼び出しは response.completed を待ち、Act、Dev、スケジュール、クラウド、Continue の実行は非ストリーミングのままです。デフォルトでオンです。', + 'st.display.openai_ask_streaming.label': "Ask ???????????", + 'st.display.openai_ask_streaming.desc': "Ask ??????????????????????????????????????????????????Act?Dev?????????????Continue ?????????????????????????????", 'st.display.plan_before_act.label': '実行前に計画', 'st.display.plan_before_act.desc': 'Act と Dev はツール実行前に必ず構造化された意図確認を行います。試行(デフォルト)は完全な計画も作成しますが、短いフォローアップでは直近に承認された計画を再利用できます。厳格は毎ターン完全な計画を作成します。意図または計画が1回の修復後も無効な場合、試行は読み取り専用ターンに切り替え、厳格はツール実行前に停止します。', 'st.display.plan_before_act.try': '計画を試す(デフォルト)', diff --git a/src/chrome/src/ui/locales/ko.js b/src/chrome/src/ui/locales/ko.js index c4a5d59ea..9e75cc03b 100644 --- a/src/chrome/src/ui/locales/ko.js +++ b/src/chrome/src/ui/locales/ko.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': '응답 스트리밍이 중단되었습니다. 이 Ask 요청을 스트리밍 없이 다시 시도합니다.', 'sp.providers.no_setup_group': '설정 필요 없음', 'sp.providers.no_setup': '설정 없음', 'sp.providers.active_group': '활성 공급자', @@ -640,8 +641,8 @@ export default { 'st.display.clarify_timeout.instant': '즉시', 'st.display.api_mutation_observer.label': 'API 변경 관찰자', 'st.display.api_mutation_observer.desc': '동일한 탭의 XHR/fetch 요청 URL 및 메서드를 관찰하여 WebBrain이 반복되는 UI 작업을 감지하고 API 바로가기 패턴을 제안할 수 있도록 합니다. 기본적으로 꺼져 있습니다. 바로가기 동작이나 지연 시간을 조사할 때만 활성화하세요.', - 'st.display.openai_ask_streaming.label': 'Ask에서 OpenAI 응답 스트리밍', - 'st.display.openai_ask_streaming.desc': 'Ask 모드에서 공식 OpenAI Responses 텍스트를 도착하는 즉시 표시합니다. 도구 호출은 response.completed를 기다리며 Act, Dev, 예약, 클라우드 및 Continue 실행은 스트리밍하지 않습니다. 기본적으로 켜져 있습니다.', + 'st.display.openai_ask_streaming.label': "Ask ?? ????", + 'st.display.openai_ask_streaming.desc': "Ask ???? ??? ??? ???? ?? ?????. ?? ??? ??? ?? ???? ???? Act, Dev, ??, ???? ? Continue ??? ?????? ????. ????? ?? ????.", 'st.display.plan_before_act.label': '실행 전 계획', 'st.display.plan_before_act.desc': 'Act 및 Dev 모드는 도구 실행 전에 항상 구조화된 의도 확인을 수행합니다. 시도(기본값)는 전체 계획도 만들지만 짧은 후속 요청에서는 최근 승인된 계획을 재사용할 수 있습니다. 엄격 모드는 매 턴 전체 계획을 만듭니다. 의도나 계획이 한 번의 복구 후에도 유효하지 않으면 시도는 읽기 전용 턴으로 전환하고 엄격 모드는 도구 실행 전에 중지합니다.', 'st.display.plan_before_act.try': '계획 시도 (기본값)', diff --git a/src/chrome/src/ui/locales/ms.js b/src/chrome/src/ui/locales/ms.js index 360d1d8c9..f539a1a83 100644 --- a/src/chrome/src/ui/locales/ms.js +++ b/src/chrome/src/ui/locales/ms.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Penstriman respons terganggu; mencuba semula giliran Ask ini tanpa penstriman.', 'sp.providers.no_setup_group': 'Tanpa persediaan', 'sp.providers.no_setup': 'Tiada persediaan diperlukan', 'sp.providers.active_group': 'Penyedia aktif', @@ -640,8 +641,8 @@ export default { 'st.display.clarify_timeout.instant': 'Segera', 'st.display.api_mutation_observer.label': 'Pemerhati mutasi API', 'st.display.api_mutation_observer.desc': 'Perhatikan URL dan metode permintaan XHR/fetch tab yang sama supaya WebBrain dapat mengesan tindakan UI berulang dan mencadangkan corak pintasan API. Dimatikan secara lalai; aktifkan hanya semasa menyiasat tingkah laku pintasan atau kependaman.', - 'st.display.openai_ask_streaming.label': 'Strim respons OpenAI dalam mod Ask', - 'st.display.openai_ask_streaming.desc': 'Paparkan teks OpenAI Responses rasmi sebaik sahaja tiba dalam mod Ask. Panggilan alat menunggu response.completed; Act, Dev, tugas berjadual, awan dan Continue kekal tanpa penstriman. Dihidupkan secara lalai.', + 'st.display.openai_ask_streaming.label': "Strim respons dalam mod Ask", + 'st.display.openai_ask_streaming.desc': "Paparkan respons penyedia sebaik sahaja diterima dalam mod Ask. Panggilan alat menunggu peristiwa akhir strim; tugas Act, Dev, berjadual, awan dan Continue kekal tanpa penstriman. Dihidupkan secara lalai.", 'st.display.plan_before_act.label': 'Rancang sebelum Bertindak', 'st.display.plan_before_act.desc': 'Mod Bertindak dan Dev sentiasa menjalankan semakan niat berstruktur sebelum alatan. Cuba (lalai) turut membina rancangan penuh tetapi boleh menggunakan semula rancangan yang baru diluluskan untuk susulan ringkas; Ketat membina rancangan penuh setiap giliran. Cuba beralih kepada giliran baca sahaja jika niat atau rancangan masih tidak sah selepas satu pembaikan; Ketat berhenti sebelum alatan.', 'st.display.plan_before_act.try': 'Cuba perancangan (lalai)', diff --git a/src/chrome/src/ui/locales/nl.js b/src/chrome/src/ui/locales/nl.js index 683cd96d5..d71cb3492 100644 --- a/src/chrome/src/ui/locales/nl.js +++ b/src/chrome/src/ui/locales/nl.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'De antwoordstream is onderbroken; deze Ask-beurt wordt opnieuw geprobeerd zonder streaming.', 'sp.providers.no_setup_group': 'Geen configuratie nodig', 'sp.providers.no_setup': 'Geen configuratie', 'sp.providers.active_group': 'Actieve providers', @@ -471,8 +472,8 @@ export default { 'st.display.api_mutation_observer.desc': 'Observeer XHR/fetch-verzoek-URL\'s en -methoden op hetzelfde tabblad...', 'st.display.webmcp.label': 'Experimenteel WebMCP', 'st.display.webmcp.desc': 'Sta WebBrain toe om gestructureerde tools te ontdekken en uit te voeren die worden aangeboden door ondersteunde Chrome-pagina\'s...', - 'st.display.openai_ask_streaming.label': 'Stream OpenAI Antwoord-respondenties', - 'st.display.openai_ask_streaming.desc': 'Toon officiële OpenAI Responses-tekst zodat deze binnenkomt in Vraagmodus...', + 'st.display.openai_ask_streaming.label': 'Ask-antwoorden streamen', + 'st.display.openai_ask_streaming.desc': 'Toon tekst van ondersteunde providers zodra deze binnenkomt in Ask-modus. Onderbroken streams tonen een melding en worden eenmaal opnieuw geprobeerd zonder streaming. Toolaanroepen wachten op het einde van de stream; Act-, Dev-, geplande, cloud- en Continue-runs blijven niet-streamend. Standaard ingeschakeld.', 'st.display.plan_before_act.label': 'Plannen voor Handelen', 'st.display.plan_before_act.desc': 'Handelen en Ontwikkelaar voeren altijd een gestructureerde intentiecontrole uit voordat tools worden gebruikt...', 'st.display.plan_before_act.try': 'Probeer plannen (standaard)', diff --git a/src/chrome/src/ui/locales/pl.js b/src/chrome/src/ui/locales/pl.js index 34ef73be9..33a4b4502 100644 --- a/src/chrome/src/ui/locales/pl.js +++ b/src/chrome/src/ui/locales/pl.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Strumieniowanie odpowiedzi zostało przerwane; ponawiam tę turę Ask bez strumieniowania.', 'sp.providers.no_setup_group': 'Bez konfiguracji', 'sp.providers.no_setup': 'Konfiguracja nie jest wymagana', 'sp.providers.active_group': 'Aktywni dostawcy', @@ -631,8 +632,8 @@ export default { 'st.display.clarify_timeout.instant': 'Natychmiast', 'st.display.api_mutation_observer.label': 'Obserwator mutacji API', 'st.display.api_mutation_observer.desc': 'Obserwuj URL-e i metody żądań XHR/fetch w tej samej karcie, aby WebBrain mógł wykrywać powtarzające się akcje UI i sugerować wzorce skrótów API. Wyłączone domyślnie; włącz tylko podczas badania zachowania skrótów lub opóźnień.', - 'st.display.openai_ask_streaming.label': 'Strumieniuj odpowiedzi OpenAI w Ask', - 'st.display.openai_ask_streaming.desc': 'Pokazuj tekst oficjalnego OpenAI Responses w miarę napływania w trybie Ask. Wywołania narzędzi czekają na response.completed; Act, Dev, zadania zaplanowane, chmurowe i Continue pozostają bez strumieniowania. Domyślnie włączone.', + 'st.display.openai_ask_streaming.label': "Strumieniuj odpowiedzi w trybie Ask", + 'st.display.openai_ask_streaming.desc': "Pokazuj odpowiedzi dostawcy w miar? nap?ywania w trybie Ask. Wywo?ania narz?dzi czekaj? na ko?cowe zdarzenie strumienia; Act, Dev, zadania zaplanowane, chmurowe i Continue pozostaj? bez strumieniowania. Domy?lnie w??czone.", 'st.display.plan_before_act.label': 'Planuj przed działaniem', 'st.display.plan_before_act.desc': 'Tryby Działaj i Dev zawsze wykonują ustrukturyzowaną kontrolę intencji przed użyciem narzędzi. Próba (domyślnie) tworzy też pełne plany, ale przy krótkiej kontynuacji może ponownie użyć niedawno zatwierdzonego planu; tryb Ścisły tworzy pełny plan w każdej turze. Jeśli intencja lub plan nadal są nieprawidłowe po jednej naprawie, Próba przechodzi do tury tylko do odczytu, a tryb Ścisły zatrzymuje się przed narzędziami.', 'st.display.plan_before_act.try': 'Spróbuj planowania (domyślnie)', diff --git a/src/chrome/src/ui/locales/pt.js b/src/chrome/src/ui/locales/pt.js index 9787deb8c..dfd17a4c6 100644 --- a/src/chrome/src/ui/locales/pt.js +++ b/src/chrome/src/ui/locales/pt.js @@ -1,5 +1,6 @@ // Portuguese — translated from the canonical English locale. export default { + 'sp.streaming.fallback': 'A transmissão da resposta foi interrompida; tentando novamente esta interação Ask sem transmissão.', 'sp.providers.no_setup_group': "Nenhuma configuração necessária", 'sp.providers.no_setup': "Sem configuração", 'sp.providers.active_group': "Provedores ativos", @@ -494,8 +495,8 @@ export default { 'st.display.api_mutation_observer.desc': "Observe URLs e métodos de solicitação de busca/XHR na mesma guia para que WebBrain possa detectar ações repetidas da interface do usuário e sugerir padrões de atalho de API. Desativado por padrão; habilite apenas ao investigar o comportamento ou a latência do atalho.", 'st.display.webmcp.label': "WebMCP Experimental", 'st.display.webmcp.desc': "Permitir que WebBrain descubra e execute ferramentas estruturadas expostas pelas páginas Chrome suportadas. Habilitar isso adiciona ferramentas experimentais do WebMCP e orientação ao contexto do modelo. Desativado por padrão.", - 'st.display.openai_ask_streaming.label': "Stream OpenAI Perguntar respostas", - 'st.display.openai_ask_streaming.desc': "Mostre o texto oficial das respostas OpenAI assim que chegar no modo Perguntar. As chamadas de ferramenta aguardam resposta.completa; As execuções Act, Dev, Scheduled, Cloud e Continue permanecem sem streaming. Ativado por padrão.", + 'st.display.openai_ask_streaming.label': "Transmitir respostas no modo Ask", + 'st.display.openai_ask_streaming.desc': "Mostre as respostas do provedor assim que chegarem no modo Ask. As chamadas de ferramenta aguardam um evento final do fluxo; execu??es Act, Dev, agendadas, na nuvem e Continue permanecem sem streaming. Ativado por padr?o.", 'st.display.plan_before_act.label': "Planeje antes de agir", 'st.display.plan_before_act.desc': "Act e Dev sempre executam uma verificação de intenção estruturada antes das ferramentas. Try (padrão) também cria planos completos, mas pode reutilizar um plano recentemente aprovado para um breve acompanhamento; Strict constrói um plano completo a cada passo. Tente voltar para uma curva somente leitura se a intenção ou o planejamento permanecerem inválidos após um reparo; Paradas rigorosas antes das ferramentas.", 'st.display.plan_before_act.try': "Tente planejar (padrão)", diff --git a/src/chrome/src/ui/locales/ru.js b/src/chrome/src/ui/locales/ru.js index dca71d9a5..170faa7e3 100644 --- a/src/chrome/src/ui/locales/ru.js +++ b/src/chrome/src/ui/locales/ru.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Поток ответа был прерван; этот запрос Ask повторяется без потоковой передачи.', 'sp.providers.no_setup_group': 'Без настройки', 'sp.providers.no_setup': 'Настройка не требуется', 'sp.providers.active_group': 'Активные провайдеры', @@ -640,8 +641,8 @@ export default { 'st.display.clarify_timeout.instant': 'Сразу', 'st.display.api_mutation_observer.label': 'Наблюдатель мутаций API', 'st.display.api_mutation_observer.desc': 'Наблюдайте за URL-адресами и методами запросов XHR/fetch на той же вкладке, чтобы WebBrain мог обнаруживать повторяющиеся действия UI и предлагать шаблоны API-шорткатов. Отключено по умолчанию; включайте только при исследовании поведения шорткатов или задержек.', - 'st.display.openai_ask_streaming.label': 'Потоковые ответы OpenAI в Ask', - 'st.display.openai_ask_streaming.desc': 'Показывать текст официального OpenAI Responses по мере поступления в режиме Ask. Вызовы инструментов ждут response.completed; Act, Dev, запланированные, облачные и Continue-запуски остаются без потоковой передачи. Включено по умолчанию.', + 'st.display.openai_ask_streaming.label': "????????? ?????? ? ?????? Ask", + 'st.display.openai_ask_streaming.desc': "?????????? ?????? ?????????? ?? ???? ??????????? ? ?????? Ask. ?????? ???????????? ???? ???????????? ??????? ??????; Act, Dev, ???????????????, ???????? ? Continue-??????? ???????? ??? ????????? ????????. ???????? ?? ?????????.", 'st.display.plan_before_act.label': 'Планировать перед действием', 'st.display.plan_before_act.desc': 'Режимы Действия и Dev всегда выполняют структурированную проверку намерения перед запуском инструментов. Попытка (по умолчанию) также строит полные планы, но для короткого продолжения может повторно использовать недавно одобренный план; Строгий режим строит полный план на каждом ходу. Если намерение или план остаются недействительными после одной попытки исправления, Попытка переходит в режим только для чтения, а Строгий режим останавливается до запуска инструментов.', 'st.display.plan_before_act.try': 'Попробовать планирование (по умолчанию)', diff --git a/src/chrome/src/ui/locales/th.js b/src/chrome/src/ui/locales/th.js index 590d1ea83..35778123c 100644 --- a/src/chrome/src/ui/locales/th.js +++ b/src/chrome/src/ui/locales/th.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'การสตรีมคำตอบถูกขัดจังหวะ กำลังลอง Ask รอบนี้อีกครั้งโดยไม่ใช้สตรีม', 'sp.providers.no_setup_group': 'ไม่ต้องตั้งค่า', 'sp.providers.no_setup': 'ไม่ต้องตั้งค่า', 'sp.providers.active_group': 'ผู้ให้บริการที่ใช้งานอยู่', @@ -640,8 +641,8 @@ export default { 'st.display.clarify_timeout.instant': 'ทันที', 'st.display.api_mutation_observer.label': 'ตัวสังเกตการกลายพันธุ์ของ API', 'st.display.api_mutation_observer.desc': 'สังเกต URL และวิธีการของคำขอ XHR/fetch ในแท็บเดียวกัน เพื่อให้ WebBrain ตรวจจับการกระทำ UI ที่ซ้ำและแนะนำรูปแบบทางลัด API ปิดโดยค่าเริ่มต้น เปิดใช้งานเฉพาะเมื่อตรวจสอบพฤติกรรมทางลัดหรือความหน่วง', - 'st.display.openai_ask_streaming.label': 'สตรีมคำตอบ OpenAI ในโหมด Ask', - 'st.display.openai_ask_streaming.desc': 'แสดงข้อความจาก OpenAI Responses อย่างเป็นทางการทันทีที่มาถึงในโหมด Ask การเรียกเครื่องมือจะรอ response.completed ส่วน Act, Dev, งานตามกำหนดเวลา งานคลาวด์ และ Continue จะยังไม่สตรีม เปิดโดยค่าเริ่มต้น', + 'st.display.openai_ask_streaming.label': "???????????????? Ask", + 'st.display.openai_ask_streaming.desc': "??????????????????????????????????????????? Ask ??????????????????????????????????????????? ???? Act, Dev, ??????????????? ????????? ??? Continue ????????????? ??????????????????", 'st.display.plan_before_act.label': 'วางแผนก่อนดำเนินการ', 'st.display.plan_before_act.desc': 'โหมดดำเนินการและ Dev จะตรวจสอบเจตนาแบบมีโครงสร้างก่อนใช้เครื่องมือเสมอ โหมดลอง (ค่าเริ่มต้น) จะสร้างแผนฉบับเต็มด้วย แต่อาจใช้แผนที่เพิ่งอนุมัติซ้ำสำหรับคำขอต่อเนื่องสั้น ๆ ส่วนโหมดเข้มงวดจะสร้างแผนฉบับเต็มทุกครั้ง หากเจตนาหรือแผนยังไม่ถูกต้องหลังซ่อมหนึ่งครั้ง โหมดลองจะเปลี่ยนเป็นเทิร์นอ่านอย่างเดียว ส่วนโหมดเข้มงวดจะหยุดก่อนใช้เครื่องมือ', 'st.display.plan_before_act.try': 'ลองวางแผน (ค่าเริ่มต้น)', diff --git a/src/chrome/src/ui/locales/tl.js b/src/chrome/src/ui/locales/tl.js index a6b9b3fb1..1568fe14e 100644 --- a/src/chrome/src/ui/locales/tl.js +++ b/src/chrome/src/ui/locales/tl.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Naputol ang pag-stream ng tugon; sinusubukang muli ang Ask turn na ito nang walang streaming.', 'sp.providers.no_setup_group': 'Walang setup', 'sp.providers.no_setup': 'Hindi kailangan ng setup', 'sp.providers.active_group': 'Mga aktibong provider', @@ -640,8 +641,8 @@ export default { 'st.display.clarify_timeout.instant': 'Agad', 'st.display.api_mutation_observer.label': 'Tagamasid ng mutasyon ng API', 'st.display.api_mutation_observer.desc': 'Obserbahan ang mga URL at paraan ng XHR/fetch request sa parehong tab upang matukoy ng WebBrain ang mga paulit-ulit na aksyon sa UI at magmungkahi ng mga pattern ng shortcut sa API. Naka-off bilang default; paganahin lamang habang iniimbestigahan ang pag-uugali ng shortcut o latency.', - 'st.display.openai_ask_streaming.label': 'I-stream ang mga sagot ng OpenAI sa Ask', - 'st.display.openai_ask_streaming.desc': 'Ipakita ang opisyal na OpenAI Responses text habang dumarating sa Ask mode. Maghihintay ang mga tool call sa response.completed; mananatiling hindi naka-stream ang Act, Dev, scheduled, cloud, at Continue runs. Naka-on bilang default.', + 'st.display.openai_ask_streaming.label': "I-stream ang mga sagot sa Ask mode", + 'st.display.openai_ask_streaming.desc': "Ipakita ang mga sagot ng provider habang dumarating sa Ask mode. Naghihintay ang mga tool call sa pangwakas na stream event; mananatiling hindi naka-stream ang Act, Dev, scheduled, cloud, at Continue runs. Naka-on bilang default.", 'st.display.plan_before_act.label': 'Magplano bago Kumilos', 'st.display.plan_before_act.desc': 'Palaging nagsasagawa ang mga mode na Kumilos at Dev ng nakaayos na pagsusuri ng layunin bago gumamit ng mga tool. Gumagawa rin ng buong plano ang Subukan (default), ngunit maaari nitong gamitin muli ang kamakailang inaprubahang plano para sa maikling follow-up; gumagawa ng buong plano ang Mahigpit sa bawat turno. Kung hindi pa rin valid ang layunin o plano matapos ang isang pag-aayos, lilipat ang Subukan sa read-only na turn at hihinto ang Mahigpit bago gumamit ng mga tool.', 'st.display.plan_before_act.try': 'Subukan ang pagpaplano (default)', diff --git a/src/chrome/src/ui/locales/tr.js b/src/chrome/src/ui/locales/tr.js index 3ba3b584b..64cc13ea4 100644 --- a/src/chrome/src/ui/locales/tr.js +++ b/src/chrome/src/ui/locales/tr.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Yanıt akışı kesildi; bu Ask turu akış olmadan yeniden deneniyor.', 'sp.providers.no_setup_group': 'Kurulum gerektirmez', 'sp.providers.no_setup': 'Kurulum yok', 'sp.providers.active_group': 'Etkin sağlayıcılar', @@ -646,7 +647,7 @@ export default { 'st.display.api_mutation_observer.label': 'API mutasyon gözlemcisi', 'st.display.api_mutation_observer.desc': 'WebBrain\'in tekrarlanan UI eylemlerini tespit etmesi ve API kısayol kalıpları önermesi için aynı sekmedeki XHR/fetch istek URL\'lerini ve yöntemlerini gözlemle. Varsayılan olarak kapalı; yalnızca kısayol davranışını veya gecikmeyi araştırırken etkinleştir.', 'st.display.openai_ask_streaming.label': 'Ask yanıtlarını akışla', - 'st.display.openai_ask_streaming.desc': 'Desteklenen sağlayıcılarda Ask metnini geldikçe göster. Kesilen akış aynı turda sessizce ve akışsız olarak bir kez yeniden denenir; sağlayıcı/API hataları yine gösterilir. Araç çağrıları akış tamamlanana kadar bekler; Act, Dev, zamanlanmış, bulut ve Continue çalıştırmaları akışsız kalır. Varsayılan olarak açık.', + 'st.display.openai_ask_streaming.desc': 'Desteklenen sağlayıcılarda Ask metnini geldikçe göster. Kesilen akış bir bildirim gösterir ve aynı turu akışsız olarak bir kez yeniden dener; sağlayıcı/API hataları yine gösterilir. Araç çağrıları akış tamamlanana kadar bekler; Act, Dev, zamanlanmış, bulut ve Continue çalıştırmaları akışsız kalır. Varsayılan olarak açık.', 'st.display.plan_before_act.label': 'Eylemden önce planla', 'st.display.plan_before_act.desc': 'Aktif ve Dev modları araçlardan önce her zaman yapılandırılmış bir niyet kontrolü çalıştırır. Dene (varsayılan) ayrıca tam planlar oluşturur ancak kısa bir takipte yakın zamanda onaylanmış planı yeniden kullanabilir; Katı her turda tam plan oluşturur. Niyet veya planlama bir onarımdan sonra hâlâ geçersizse Dene salt okunur bir tura geçer; Katı araçlardan önce durur.', 'st.display.plan_before_act.try': 'Planlamayı dene (varsayılan)', diff --git a/src/chrome/src/ui/locales/uk.js b/src/chrome/src/ui/locales/uk.js index a76ce5d89..cd9b155cf 100644 --- a/src/chrome/src/ui/locales/uk.js +++ b/src/chrome/src/ui/locales/uk.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Потік відповіді перервано; цей запит Ask повторюється без потокової передачі.', 'sp.providers.no_setup_group': 'Без налаштування', 'sp.providers.no_setup': 'Налаштування не потрібне', 'sp.providers.active_group': 'Активні провайдери', @@ -640,8 +641,8 @@ export default { 'st.display.clarify_timeout.instant': 'Миттєво', 'st.display.api_mutation_observer.label': 'Спостерігач мутацій API', 'st.display.api_mutation_observer.desc': 'Спостерігайте за URL-адресами та методами запитів XHR/fetch на тій самій вкладці, щоб WebBrain міг виявляти повторювані дії інтерфейсу та пропонувати шаблони API-скорочень. Вимкнено за замовчуванням; вмикайте лише під час дослідження поведінки скорочень або затримки.', - 'st.display.openai_ask_streaming.label': 'Потокові відповіді OpenAI в Ask', - 'st.display.openai_ask_streaming.desc': 'Показувати текст офіційного OpenAI Responses у міру надходження в режимі Ask. Виклики інструментів чекають на response.completed; Act, Dev, заплановані, хмарні та Continue-запуски залишаються без потокової передачі. Увімкнено за замовчуванням.', + 'st.display.openai_ask_streaming.label': "???????? ????????? ? ?????? Ask", + 'st.display.openai_ask_streaming.desc': "?????????? ????????? ?????????? ? ???? ??????????? ? ?????? Ask. ??????? ???????????? ??????? ?? ??????????? ????? ??????; Act, Dev, ???????????, ?????? ?? Continue-??????? ??????????? ??? ????????? ????????. ????????? ?? ?????????????.", 'st.display.plan_before_act.label': 'Планувати перед дією', 'st.display.plan_before_act.desc': 'Режими Дії та Dev завжди виконують структуровану перевірку наміру перед запуском інструментів. Спроба (типово) також створює повні плани, але для короткого продовження може повторно використати нещодавно схвалений план; Суворий режим створює повний план на кожному кроці. Якщо намір або план лишаються недійсними після одного виправлення, Спроба переходить у режим лише для читання, а Суворий режим зупиняється до запуску інструментів.', 'st.display.plan_before_act.try': 'Спробувати планування (за замовчуванням)', diff --git a/src/chrome/src/ui/locales/vi.js b/src/chrome/src/ui/locales/vi.js index 9c936383c..8dae161c7 100644 --- a/src/chrome/src/ui/locales/vi.js +++ b/src/chrome/src/ui/locales/vi.js @@ -1,5 +1,6 @@ // Vietnamese — translated from the canonical English locale. export default { + 'sp.streaming.fallback': 'Luồng phản hồi bị gián đoạn; đang thử lại lượt Ask này mà không phát trực tuyến.', 'sp.providers.no_setup_group': "Không cần thiết lập", 'sp.providers.no_setup': "Không cần thiết lập", 'sp.providers.active_group': "Nhà cung cấp đang hoạt động", @@ -494,8 +495,8 @@ export default { 'st.display.api_mutation_observer.desc': "Quan sát các URL và phương thức yêu cầu XHR/tìm nạp cùng một tab để WebBrain có thể phát hiện các hành động giao diện người dùng lặp lại và đề xuất các mẫu phím tắt API. Tắt theo mặc định; chỉ bật trong khi điều tra hành vi hoặc độ trễ của phím tắt.", 'st.display.webmcp.label': "WebMCP thử nghiệm", 'st.display.webmcp.desc': "Cho phép WebBrain khám phá và chạy các công cụ có cấu trúc được hiển thị bởi các trang Chrome được hỗ trợ. Việc kích hoạt tính năng này sẽ bổ sung thêm các công cụ và hướng dẫn WebMCP thử nghiệm vào bối cảnh mô hình. Tắt theo mặc định.", - 'st.display.openai_ask_streaming.label': "Truyền trực tuyến OpenAI Hỏi câu trả lời", - 'st.display.openai_ask_streaming.desc': "Hiển thị văn bản Phản hồi OpenAI chính thức khi nó đến ở chế độ Hỏi. Cuộc gọi công cụ chờ phản hồi.completed; Các hoạt động Hành động, Nhà phát triển, đã lên lịch, đám mây và Tiếp tục vẫn không phát trực tuyến. Bật theo mặc định.", + 'st.display.openai_ask_streaming.label': "Truy?n tr?c tuy?n c?u tr? l?i ? ch? ?? Ask", + 'st.display.openai_ask_streaming.desc': "Hi?n th? c?u tr? l?i c?a nh? cung c?p ngay khi nh?n ???c trong ch? ?? Ask. L?nh g?i c?ng c? ch? s? ki?n k?t th?c lu?ng; c?c l?n ch?y Act, Dev, theo l?ch, ??m m?y v? Continue v?n kh?ng ph?t tr?c tuy?n. B?t theo m?c ??nh.", 'st.display.plan_before_act.label': "Lập kế hoạch trước khi hành động", 'st.display.plan_before_act.desc': "Act và Dev luôn tiến hành kiểm tra ý định có cấu trúc trước các công cụ. Try (mặc định) cũng xây dựng các kế hoạch đầy đủ nhưng có thể sử dụng lại kế hoạch đã được phê duyệt gần đây để theo dõi trong thời gian ngắn; Strict xây dựng một kế hoạch đầy đủ mỗi lượt. Thử quay lại chế độ chỉ đọc nếu ý định hoặc kế hoạch vẫn không hợp lệ sau một lần sửa chữa; Dừng lại nghiêm ngặt trước các công cụ.", 'st.display.plan_before_act.try': "Hãy thử lập kế hoạch (mặc định)", diff --git a/src/chrome/src/ui/locales/zh.js b/src/chrome/src/ui/locales/zh.js index ef7ffc0a8..b2f1ec1c2 100644 --- a/src/chrome/src/ui/locales/zh.js +++ b/src/chrome/src/ui/locales/zh.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': '响应流已中断;正在以非流式方式重试本次 Ask。', 'sp.providers.no_setup_group': '无需配置', 'sp.providers.no_setup': '无需设置', 'sp.providers.active_group': '已启用的提供商', @@ -640,8 +641,8 @@ export default { 'st.display.clarify_timeout.instant': '立即', 'st.display.api_mutation_observer.label': 'API 变更观察器', 'st.display.api_mutation_observer.desc': '观察同标签页中的 XHR/fetch 请求 URL 和方法,以便 WebBrain 可以检测重复的界面操作并建议 API 快捷模式。默认关闭;仅在调查快捷行为或延迟时启用。', - 'st.display.openai_ask_streaming.label': '在 Ask 模式流式显示 OpenAI 回复', - 'st.display.openai_ask_streaming.desc': '在 Ask 模式中随到随显官方 OpenAI Responses 文本。工具调用会等待 response.completed;Act、Dev、计划、云端和 Continue 运行仍不使用流式传输。默认开启。', + 'st.display.openai_ask_streaming.label': "? Ask ????????", + 'st.display.openai_ask_streaming.desc': "? Ask ???????????????????????????Act?Dev??????? Continue ????????????????", 'st.display.plan_before_act.label': '在执行前规划', 'st.display.plan_before_act.desc': '操作和 Dev 模式在使用工具前始终执行结构化意图检查。尝试(默认)还会生成完整计划,但在简短跟进中可复用最近批准的计划;严格模式每轮都生成完整计划。如果意图或计划在一次修复后仍无效,尝试模式会切换为只读轮次;严格模式会在使用工具前停止。', 'st.display.plan_before_act.try': '尝试规划(默认)', diff --git a/src/chrome/src/ui/provider-icons.js b/src/chrome/src/ui/provider-icons.js index c097fa641..a40ac795c 100644 --- a/src/chrome/src/ui/provider-icons.js +++ b/src/chrome/src/ui/provider-icons.js @@ -5,6 +5,10 @@ * marks for brands Lobe does not ship). See icons/providers/SOURCES.md. * Unknown ids return empty so we never invent monograms. */ +import { + ADDITIONAL_PROVIDER_DEFAULTS, + ADDITIONAL_PROVIDER_IDS, +} from '../providers/provider-catalog.js'; export const PROVIDER_ICON_FILES = { webbrain_cloud: 'webbrain_cloud.png', @@ -34,6 +38,7 @@ export const PROVIDER_ICON_FILES = { huggingface: 'huggingface.svg', fireworks: 'fireworks.svg', z_ai: 'z_ai.svg', + ...Object.fromEntries(ADDITIONAL_PROVIDER_IDS.map((id) => [id, `${id}.svg`])), }; export function providerIconUrl(id) { @@ -97,6 +102,10 @@ export const PROVIDER_SHORT_LABELS = { huggingface: 'Hugging Face', fireworks: 'Fireworks', z_ai: 'z.ai GLM', + ...Object.fromEntries(ADDITIONAL_PROVIDER_IDS.map((id) => [ + id, + ADDITIONAL_PROVIDER_DEFAULTS[id].label, + ])), }; /** Hostname equals domain or is a subdomain of it (avoids substring spoofing). */ diff --git a/src/chrome/src/ui/settings.js b/src/chrome/src/ui/settings.js index 92b1ab1a2..15e884695 100644 --- a/src/chrome/src/ui/settings.js +++ b/src/chrome/src/ui/settings.js @@ -43,6 +43,7 @@ import { PROVIDER_SHORT_LABELS, sniffProviderIdFromBaseUrl, } from './provider-icons.js'; +import { ADDITIONAL_PROVIDER_UI } from '../providers/provider-catalog.js'; // Version shown in the subtitle. Kept here so it only needs one update per // release; the subtitle string itself is translated. @@ -2185,6 +2186,7 @@ function renderProviders() { fields: [ { key: 'apiKey', labelKey: 'st.provider.field.api_key', type: 'password', placeholder: 'API token' }, { key: 'accountId', label: 'Cloudflare Account ID', type: 'text', placeholder: '0123456789abcdef0123456789abcdef' }, + { key: 'gatewayId', label: 'AI Gateway ID (optional; @cf defaults to default)', type: 'text', placeholder: 'my-gateway' }, { key: 'model', labelKey: 'st.provider.field.model', type: 'text', placeholder: '@cf/zai-org/glm-5.2', suggestions: ['@cf/zai-org/glm-5.2'] }, { key: 'baseUrl', labelKey: 'st.provider.field.api_base_url', type: 'text', placeholder: 'https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/v1' }, @@ -2292,6 +2294,50 @@ function renderProviders() { // "All" includes everything; the per-category pills hide cards whose // `category` doesn't match. The selected provider is ALWAYS visible // regardless of filter (so the user never loses track of it). + // Additional providers share a predictable OpenAI-compatible settings + // shape. Provider-specific suggestions/placeholders stay in the catalog; + // UI-only metadata is never persisted with credentials. + for (const [id, meta] of Object.entries(ADDITIONAL_PROVIDER_UI)) { + const config = providersData[id] || {}; + const fields = [ + { + key: 'apiKey', + labelKey: 'st.provider.field.api_key', + type: 'password', + placeholder: meta.apiKeyPlaceholder || 'API key', + }, + ]; + if (id === 'azure-cognitive-services') { + fields.push({ key: 'resource', label: 'Azure resource name', type: 'text', placeholder: 'my-resource' }); + } + if (id === 'google-vertex' || id === 'google-vertex-anthropic') { + fields.push( + { key: 'project', label: 'Google Cloud project ID', type: 'text', placeholder: 'my-project' }, + { key: 'location', label: 'Google Cloud location', type: 'text', placeholder: id === 'google-vertex' ? 'us-central1' : 'us-east5' }, + ); + } + fields.push( + { + key: 'model', + labelKey: 'st.provider.field.model', + type: 'text', + placeholder: config.model || (id === 'azure-cognitive-services' ? 'deployed-model-name' : 'model-id'), + suggestions: meta.suggestions || [], + }, + { + key: 'baseUrl', + labelKey: 'st.provider.field.api_base_url', + type: 'text', + placeholder: config.baseUrl || 'https://provider.example/v1', + }, + CONTEXT_WINDOW_FIELD, + { key: 'supportsVision', labelKey: 'st.provider.field.supports_vision', type: 'checkbox' }, + ); + if (config.category === 'router' || config.category === 'local') fields.push(PROMPT_TIER_FIELD); + fields.push(...COST_ESTIMATE_FIELDS); + providerConfigs[id] = { fields }; + } + providersContainer.appendChild(renderProviderFilterBar()); let entries = Object.entries(providersData); diff --git a/src/chrome/src/ui/sidepanel.js b/src/chrome/src/ui/sidepanel.js index fa966a769..0b4be47dc 100644 --- a/src/chrome/src/ui/sidepanel.js +++ b/src/chrome/src/ui/sidepanel.js @@ -6999,6 +6999,9 @@ function handleAgentUpdateMessage(msg) { case 'warning': hideActivity(); + if (data?.code === 'ask_stream_fallback') { + showComposerToast(t('sp.streaming.fallback'), { duration: 6000 }); + } break; case 'run_complete': diff --git a/src/firefox/icons/providers/302ai.svg b/src/firefox/icons/providers/302ai.svg new file mode 100644 index 000000000..46f2e4315 --- /dev/null +++ b/src/firefox/icons/providers/302ai.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/firefox/icons/providers/SOURCES.md b/src/firefox/icons/providers/SOURCES.md index 3495050a5..7c8855c3e 100644 --- a/src/firefox/icons/providers/SOURCES.md +++ b/src/firefox/icons/providers/SOURCES.md @@ -11,5 +11,6 @@ Most brand marks come from [Lobe Icons](https://github.com/lobehub/lobe-icons) | localai | LocalAI official logo (`mudler/LocalAI`) | | sglang | SGLang official `logo_square` (`sgl-project/sglang`) | | webbrain_cloud | WebBrain extension icon | +| 302ai, abacus, aihubmix, alibaba-coding-plan, alibaba-coding-plan-cn, azure-cognitive-services, bailing, baseten, berget, cerebras, chutes, clarifai, cloudferro-sherlock, cohere, cortecs, deepinfra, digitalocean, dinference, drun, evroc, fastrouter, friendli, google-vertex, google-vertex-anthropic, helicone, iflowcn, inception, inference, io-net, jiekou, kilo, kimi-for-coding, kuae-cloud-coding-plan, llama, lucidquery, meganova, minimax-cn-coding-plan, minimax-coding-plan, moark, modelscope, morph, nano-gpt, nebius, nova, novita-ai, ollama-cloud, opencode, opencode-go, ovhcloud, perplexity, perplexity-agent, poe, privatemode-ai, qihang-ai, qiniu-ai, requesty, scaleway, siliconflow, siliconflow-cn, stackit, stepfun, submodel, synthetic, tencent-coding-plan, upstage, v0, venice, vercel, vivgrid, vultr, wandb, xiaomi, zai-coding-plan, zenmux, zhipuai, zhipuai-coding-plan | OpenCode provider icon set at commit `62e4641235d7847dadc60da37cca8a023dd54fc1` (MIT); DInference SVG normalized with a `viewBox` | Brand trademarks remain property of their owners; used only for provider identification in the settings UI. diff --git a/src/firefox/icons/providers/abacus.svg b/src/firefox/icons/providers/abacus.svg new file mode 100644 index 000000000..121a91d98 --- /dev/null +++ b/src/firefox/icons/providers/abacus.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/firefox/icons/providers/aihubmix.svg b/src/firefox/icons/providers/aihubmix.svg new file mode 100644 index 000000000..33164b78b --- /dev/null +++ b/src/firefox/icons/providers/aihubmix.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/alibaba-coding-plan-cn.svg b/src/firefox/icons/providers/alibaba-coding-plan-cn.svg new file mode 100644 index 000000000..b3a2edc3c --- /dev/null +++ b/src/firefox/icons/providers/alibaba-coding-plan-cn.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/alibaba-coding-plan.svg b/src/firefox/icons/providers/alibaba-coding-plan.svg new file mode 100644 index 000000000..b3a2edc3c --- /dev/null +++ b/src/firefox/icons/providers/alibaba-coding-plan.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/azure-cognitive-services.svg b/src/firefox/icons/providers/azure-cognitive-services.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/firefox/icons/providers/azure-cognitive-services.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/firefox/icons/providers/bailing.svg b/src/firefox/icons/providers/bailing.svg new file mode 100644 index 000000000..b8ed486a8 --- /dev/null +++ b/src/firefox/icons/providers/bailing.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/baseten.svg b/src/firefox/icons/providers/baseten.svg new file mode 100644 index 000000000..ffd4fbd8b --- /dev/null +++ b/src/firefox/icons/providers/baseten.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/berget.svg b/src/firefox/icons/providers/berget.svg new file mode 100644 index 000000000..831547a59 --- /dev/null +++ b/src/firefox/icons/providers/berget.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/firefox/icons/providers/cerebras.svg b/src/firefox/icons/providers/cerebras.svg new file mode 100644 index 000000000..b16759672 --- /dev/null +++ b/src/firefox/icons/providers/cerebras.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/firefox/icons/providers/chutes.svg b/src/firefox/icons/providers/chutes.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/firefox/icons/providers/chutes.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/firefox/icons/providers/clarifai.svg b/src/firefox/icons/providers/clarifai.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/firefox/icons/providers/clarifai.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/firefox/icons/providers/cloudferro-sherlock.svg b/src/firefox/icons/providers/cloudferro-sherlock.svg new file mode 100644 index 000000000..6f09a794e --- /dev/null +++ b/src/firefox/icons/providers/cloudferro-sherlock.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/firefox/icons/providers/cohere.svg b/src/firefox/icons/providers/cohere.svg new file mode 100644 index 000000000..cfeaa6002 --- /dev/null +++ b/src/firefox/icons/providers/cohere.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/firefox/icons/providers/cortecs.svg b/src/firefox/icons/providers/cortecs.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/firefox/icons/providers/cortecs.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/firefox/icons/providers/deepinfra.svg b/src/firefox/icons/providers/deepinfra.svg new file mode 100644 index 000000000..c35ab7183 --- /dev/null +++ b/src/firefox/icons/providers/deepinfra.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/firefox/icons/providers/digitalocean.svg b/src/firefox/icons/providers/digitalocean.svg new file mode 100644 index 000000000..5be390b9d --- /dev/null +++ b/src/firefox/icons/providers/digitalocean.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/firefox/icons/providers/dinference.svg b/src/firefox/icons/providers/dinference.svg new file mode 100644 index 000000000..e161327d4 --- /dev/null +++ b/src/firefox/icons/providers/dinference.svg @@ -0,0 +1 @@ + diff --git a/src/firefox/icons/providers/drun.svg b/src/firefox/icons/providers/drun.svg new file mode 100644 index 000000000..472dee912 --- /dev/null +++ b/src/firefox/icons/providers/drun.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/firefox/icons/providers/evroc.svg b/src/firefox/icons/providers/evroc.svg new file mode 100644 index 000000000..7597820a1 --- /dev/null +++ b/src/firefox/icons/providers/evroc.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/firefox/icons/providers/fastrouter.svg b/src/firefox/icons/providers/fastrouter.svg new file mode 100644 index 000000000..ec73dc49c --- /dev/null +++ b/src/firefox/icons/providers/fastrouter.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/friendli.svg b/src/firefox/icons/providers/friendli.svg new file mode 100644 index 000000000..8acb7632d --- /dev/null +++ b/src/firefox/icons/providers/friendli.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/google-vertex-anthropic.svg b/src/firefox/icons/providers/google-vertex-anthropic.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/firefox/icons/providers/google-vertex-anthropic.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/firefox/icons/providers/google-vertex.svg b/src/firefox/icons/providers/google-vertex.svg new file mode 100644 index 000000000..fda56b447 --- /dev/null +++ b/src/firefox/icons/providers/google-vertex.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/firefox/icons/providers/helicone.svg b/src/firefox/icons/providers/helicone.svg new file mode 100644 index 000000000..8a4bd43ad --- /dev/null +++ b/src/firefox/icons/providers/helicone.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/firefox/icons/providers/iflowcn.svg b/src/firefox/icons/providers/iflowcn.svg new file mode 100644 index 000000000..6f35a7d59 --- /dev/null +++ b/src/firefox/icons/providers/iflowcn.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/inception.svg b/src/firefox/icons/providers/inception.svg new file mode 100644 index 000000000..f70ffbc78 --- /dev/null +++ b/src/firefox/icons/providers/inception.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/firefox/icons/providers/inference.svg b/src/firefox/icons/providers/inference.svg new file mode 100644 index 000000000..c17f66574 --- /dev/null +++ b/src/firefox/icons/providers/inference.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/io-net.svg b/src/firefox/icons/providers/io-net.svg new file mode 100644 index 000000000..651e57df8 --- /dev/null +++ b/src/firefox/icons/providers/io-net.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/firefox/icons/providers/jiekou.svg b/src/firefox/icons/providers/jiekou.svg new file mode 100644 index 000000000..7fe6378e5 --- /dev/null +++ b/src/firefox/icons/providers/jiekou.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/firefox/icons/providers/kilo.svg b/src/firefox/icons/providers/kilo.svg new file mode 100644 index 000000000..0a761347a --- /dev/null +++ b/src/firefox/icons/providers/kilo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/firefox/icons/providers/kimi-for-coding.svg b/src/firefox/icons/providers/kimi-for-coding.svg new file mode 100644 index 000000000..8f2af02e6 --- /dev/null +++ b/src/firefox/icons/providers/kimi-for-coding.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/kuae-cloud-coding-plan.svg b/src/firefox/icons/providers/kuae-cloud-coding-plan.svg new file mode 100644 index 000000000..3d0d0c455 --- /dev/null +++ b/src/firefox/icons/providers/kuae-cloud-coding-plan.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/llama.svg b/src/firefox/icons/providers/llama.svg new file mode 100644 index 000000000..3053b251f --- /dev/null +++ b/src/firefox/icons/providers/llama.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/lucidquery.svg b/src/firefox/icons/providers/lucidquery.svg new file mode 100644 index 000000000..6420a042e --- /dev/null +++ b/src/firefox/icons/providers/lucidquery.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/meganova.svg b/src/firefox/icons/providers/meganova.svg new file mode 100644 index 000000000..59e8b3a1f --- /dev/null +++ b/src/firefox/icons/providers/meganova.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/minimax-cn-coding-plan.svg b/src/firefox/icons/providers/minimax-cn-coding-plan.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/firefox/icons/providers/minimax-cn-coding-plan.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/firefox/icons/providers/minimax-coding-plan.svg b/src/firefox/icons/providers/minimax-coding-plan.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/firefox/icons/providers/minimax-coding-plan.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/firefox/icons/providers/moark.svg b/src/firefox/icons/providers/moark.svg new file mode 100644 index 000000000..dc84a9191 --- /dev/null +++ b/src/firefox/icons/providers/moark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/modelscope.svg b/src/firefox/icons/providers/modelscope.svg new file mode 100644 index 000000000..94a894a55 --- /dev/null +++ b/src/firefox/icons/providers/modelscope.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/firefox/icons/providers/morph.svg b/src/firefox/icons/providers/morph.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/firefox/icons/providers/morph.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/firefox/icons/providers/nano-gpt.svg b/src/firefox/icons/providers/nano-gpt.svg new file mode 100644 index 000000000..f7fbb4cdc --- /dev/null +++ b/src/firefox/icons/providers/nano-gpt.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/firefox/icons/providers/nebius.svg b/src/firefox/icons/providers/nebius.svg new file mode 100644 index 000000000..aeba5890d --- /dev/null +++ b/src/firefox/icons/providers/nebius.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/firefox/icons/providers/nova.svg b/src/firefox/icons/providers/nova.svg new file mode 100644 index 000000000..9fcae228c --- /dev/null +++ b/src/firefox/icons/providers/nova.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/novita-ai.svg b/src/firefox/icons/providers/novita-ai.svg new file mode 100644 index 000000000..ac537b8dd --- /dev/null +++ b/src/firefox/icons/providers/novita-ai.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/firefox/icons/providers/ollama-cloud.svg b/src/firefox/icons/providers/ollama-cloud.svg new file mode 100644 index 000000000..08c05cf28 --- /dev/null +++ b/src/firefox/icons/providers/ollama-cloud.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/firefox/icons/providers/opencode-go.svg b/src/firefox/icons/providers/opencode-go.svg new file mode 100644 index 000000000..e0833b923 --- /dev/null +++ b/src/firefox/icons/providers/opencode-go.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/opencode.svg b/src/firefox/icons/providers/opencode.svg new file mode 100644 index 000000000..950846582 --- /dev/null +++ b/src/firefox/icons/providers/opencode.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/ovhcloud.svg b/src/firefox/icons/providers/ovhcloud.svg new file mode 100644 index 000000000..064b0835b --- /dev/null +++ b/src/firefox/icons/providers/ovhcloud.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/perplexity-agent.svg b/src/firefox/icons/providers/perplexity-agent.svg new file mode 100644 index 000000000..a0f38862a --- /dev/null +++ b/src/firefox/icons/providers/perplexity-agent.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/perplexity.svg b/src/firefox/icons/providers/perplexity.svg new file mode 100644 index 000000000..a0f38862a --- /dev/null +++ b/src/firefox/icons/providers/perplexity.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/poe.svg b/src/firefox/icons/providers/poe.svg new file mode 100644 index 000000000..a5ab62d72 --- /dev/null +++ b/src/firefox/icons/providers/poe.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/firefox/icons/providers/privatemode-ai.svg b/src/firefox/icons/providers/privatemode-ai.svg new file mode 100644 index 000000000..edb5a6d76 --- /dev/null +++ b/src/firefox/icons/providers/privatemode-ai.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/firefox/icons/providers/qihang-ai.svg b/src/firefox/icons/providers/qihang-ai.svg new file mode 100644 index 000000000..9e58c7440 --- /dev/null +++ b/src/firefox/icons/providers/qihang-ai.svg @@ -0,0 +1,9 @@ + + + diff --git a/src/firefox/icons/providers/qiniu-ai.svg b/src/firefox/icons/providers/qiniu-ai.svg new file mode 100644 index 000000000..858560f9f --- /dev/null +++ b/src/firefox/icons/providers/qiniu-ai.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/firefox/icons/providers/requesty.svg b/src/firefox/icons/providers/requesty.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/firefox/icons/providers/requesty.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/firefox/icons/providers/scaleway.svg b/src/firefox/icons/providers/scaleway.svg new file mode 100644 index 000000000..7574f72f3 --- /dev/null +++ b/src/firefox/icons/providers/scaleway.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/firefox/icons/providers/siliconflow-cn.svg b/src/firefox/icons/providers/siliconflow-cn.svg new file mode 100644 index 000000000..13cac22b9 --- /dev/null +++ b/src/firefox/icons/providers/siliconflow-cn.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/siliconflow.svg b/src/firefox/icons/providers/siliconflow.svg new file mode 100644 index 000000000..13cac22b9 --- /dev/null +++ b/src/firefox/icons/providers/siliconflow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/stackit.svg b/src/firefox/icons/providers/stackit.svg new file mode 100644 index 000000000..0d78b781a --- /dev/null +++ b/src/firefox/icons/providers/stackit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/firefox/icons/providers/stepfun.svg b/src/firefox/icons/providers/stepfun.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/firefox/icons/providers/stepfun.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/firefox/icons/providers/submodel.svg b/src/firefox/icons/providers/submodel.svg new file mode 100644 index 000000000..5bef03c64 --- /dev/null +++ b/src/firefox/icons/providers/submodel.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/synthetic.svg b/src/firefox/icons/providers/synthetic.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/firefox/icons/providers/synthetic.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/firefox/icons/providers/tencent-coding-plan.svg b/src/firefox/icons/providers/tencent-coding-plan.svg new file mode 100644 index 000000000..502e51a5b --- /dev/null +++ b/src/firefox/icons/providers/tencent-coding-plan.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/firefox/icons/providers/upstage.svg b/src/firefox/icons/providers/upstage.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/firefox/icons/providers/upstage.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/firefox/icons/providers/v0.svg b/src/firefox/icons/providers/v0.svg new file mode 100644 index 000000000..09f3b411e --- /dev/null +++ b/src/firefox/icons/providers/v0.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/venice.svg b/src/firefox/icons/providers/venice.svg new file mode 100644 index 000000000..3d5809e3b --- /dev/null +++ b/src/firefox/icons/providers/venice.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/firefox/icons/providers/vercel.svg b/src/firefox/icons/providers/vercel.svg new file mode 100644 index 000000000..a99425f2a --- /dev/null +++ b/src/firefox/icons/providers/vercel.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/vivgrid.svg b/src/firefox/icons/providers/vivgrid.svg new file mode 100644 index 000000000..928fa3ff1 --- /dev/null +++ b/src/firefox/icons/providers/vivgrid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/firefox/icons/providers/vultr.svg b/src/firefox/icons/providers/vultr.svg new file mode 100644 index 000000000..9205d4484 --- /dev/null +++ b/src/firefox/icons/providers/vultr.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/firefox/icons/providers/wandb.svg b/src/firefox/icons/providers/wandb.svg new file mode 100644 index 000000000..086e9aa1f --- /dev/null +++ b/src/firefox/icons/providers/wandb.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/firefox/icons/providers/xiaomi.svg b/src/firefox/icons/providers/xiaomi.svg new file mode 100644 index 000000000..4a893919e --- /dev/null +++ b/src/firefox/icons/providers/xiaomi.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/zai-coding-plan.svg b/src/firefox/icons/providers/zai-coding-plan.svg new file mode 100644 index 000000000..d7da9b7c5 --- /dev/null +++ b/src/firefox/icons/providers/zai-coding-plan.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/zenmux.svg b/src/firefox/icons/providers/zenmux.svg new file mode 100644 index 000000000..9eb8045e4 --- /dev/null +++ b/src/firefox/icons/providers/zenmux.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/firefox/icons/providers/zhipuai-coding-plan.svg b/src/firefox/icons/providers/zhipuai-coding-plan.svg new file mode 100644 index 000000000..3d0d0c455 --- /dev/null +++ b/src/firefox/icons/providers/zhipuai-coding-plan.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/icons/providers/zhipuai.svg b/src/firefox/icons/providers/zhipuai.svg new file mode 100644 index 000000000..d7da9b7c5 --- /dev/null +++ b/src/firefox/icons/providers/zhipuai.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/firefox/src/agent/agent.js b/src/firefox/src/agent/agent.js index 1df924d8b..07bac9ad2 100644 --- a/src/firefox/src/agent/agent.js +++ b/src/firefox/src/agent/agent.js @@ -1152,6 +1152,27 @@ export class Agent { return result; } + _estimateAskStreamUsage(messages, options, content, reasoningContent, toolCalls) { + let toolSchemaChars = 0; + let toolCallChars = 0; + try { toolSchemaChars = JSON.stringify(options?.tools || []).length; } catch {} + try { toolCallChars = JSON.stringify(toolCalls || []).length; } catch {} + const promptTokens = Math.max( + 1, + Math.ceil((this._estimateContextChars(Array.isArray(messages) ? messages : []) + toolSchemaChars) / 4), + ); + const completionChars = String(content || '').length + + String(reasoningContent || '').length + + toolCallChars; + const completionTokens = completionChars > 0 ? Math.max(1, Math.ceil(completionChars / 4)) : 0; + return { + prompt_tokens: promptTokens, + completion_tokens: completionTokens, + total_tokens: promptTokens + completionTokens, + estimated: true, + }; + } + _shouldStreamInteractiveAsk(provider, mode, runOptions = {}, disabledForRun = false) { const streamingEnabled = runOptions?.askStreamingEnabled ?? runOptions?.openaiAskStreamingEnabled; @@ -1201,6 +1222,18 @@ export class Agent { usageRecorded = true; return this._recordCostUsage(provider, usage, costState); }; + const estimateUsageIfMissing = (completed = false) => { + if (usage) return; + const partialToolCalls = [...toolCalls.values()]; + if (!completed && !content && !reasoningContent && partialToolCalls.length === 0) return; + usage = this._estimateAskStreamUsage( + messages, + streamOptions, + content, + reasoningContent, + partialToolCalls, + ); + }; const mergeToolCall = (toolCall, fallbackIndex = 0) => { if (!toolCall || typeof toolCall !== 'object') return; const index = Number.isInteger(toolCall.index) ? toolCall.index : fallbackIndex; @@ -1260,10 +1293,12 @@ export class Agent { } catch (error) { // Incomplete Responses streams can still report billable usage. Record // that once before the caller either propagates or retries the failure. + estimateUsageIfMissing(false); try { await recordUsage(); } catch {} throw error; } + estimateUsageIfMissing(true); content = Agent._stripReasoningTags(content); const result = { content, @@ -13769,6 +13804,10 @@ Rules: no prose intro, no conclusion, no "this screenshot shows...", no layout d if (emittedText) onUpdate('text', { content: '', replace: true }); if (!this._shouldFallbackAskStream(error)) throw error; askStreamingDisabledForRun = true; + onUpdate('warning', { + code: 'ask_stream_fallback', + message: 'Response streaming was interrupted; retrying this Ask turn without streaming.', + }); this._logDebug({ type: 'llm_stream_fallback', provider: provider.constructor?.name || provider.name, diff --git a/src/firefox/src/providers/anthropic.js b/src/firefox/src/providers/anthropic.js index b6c4ec544..24ba223e9 100644 --- a/src/firefox/src/providers/anthropic.js +++ b/src/firefox/src/providers/anthropic.js @@ -35,6 +35,14 @@ export class AnthropicProvider extends BaseLLMProvider { return true; } + _messagesUrl(_stream = false) { + return `${String(this.baseUrl).replace(/\/+$/, '')}/v1/messages`; + } + + _prepareRequestBody(body, _options = {}, _stream = false) { + return body; + } + _headers() { return { 'Content-Type': 'application/json', @@ -186,7 +194,7 @@ export class AnthropicProvider extends BaseLLMProvider { async chat(messages, options = {}) { const { system, messages: anthropicMessages } = this._convertMessages(messages); - const body = { + let body = { model: this.model, max_tokens: options.maxTokens ?? 4096, messages: anthropicMessages, @@ -197,8 +205,9 @@ export class AnthropicProvider extends BaseLLMProvider { if (options.tools && options.tools.length > 0) { body.tools = this._convertTools(options.tools); } + body = this._prepareRequestBody(body, options, false); - const res = await fetchWithTimeout(`${this.baseUrl}/v1/messages`, { + const res = await fetchWithTimeout(this._messagesUrl(false), { method: 'POST', headers: this._headers(), body: JSON.stringify(body), @@ -246,7 +255,7 @@ export class AnthropicProvider extends BaseLLMProvider { async *chatStream(messages, options = {}) { const { system, messages: anthropicMessages } = this._convertMessages(messages); - const body = { + let body = { model: this.model, max_tokens: options.maxTokens ?? 4096, messages: anthropicMessages, @@ -258,8 +267,9 @@ export class AnthropicProvider extends BaseLLMProvider { if (options.tools && options.tools.length > 0) { body.tools = this._convertTools(options.tools); } + body = this._prepareRequestBody(body, options, true); - const url = `${this.baseUrl}/v1/messages`; + const url = this._messagesUrl(true); let res; try { res = await fetchWithTimeout(url, { diff --git a/src/firefox/src/providers/base.js b/src/firefox/src/providers/base.js index 6452a6347..35169b7ff 100644 --- a/src/firefox/src/providers/base.js +++ b/src/firefox/src/providers/base.js @@ -67,6 +67,15 @@ export class BaseLLMProvider { return false; } + /** + * Whether interactive Ask turns may use this provider's streaming method. + * Providers must opt in explicitly; merely implementing chatStream() is not + * enough because some adapters retain a non-streaming compatibility shim. + */ + get supportsAskStreaming() { + return this.config.supportsAskStreaming === true; + } + /** * Check if this provider supports image inputs (vision). */ diff --git a/src/firefox/src/providers/manager.js b/src/firefox/src/providers/manager.js index 25e4d5662..addf4ba6a 100644 --- a/src/firefox/src/providers/manager.js +++ b/src/firefox/src/providers/manager.js @@ -2,8 +2,10 @@ import { LlamaCppProvider } from './llamacpp.js'; import { OpenAICompatibleProvider } from './openai.js'; import { AzureOpenAIProvider } from './azure-openai.js'; import { AnthropicProvider, AnthropicOAuthProvider } from './anthropic.js'; +import { VertexAnthropicProvider } from './vertex-anthropic.js'; import { signOutClaude } from './oauth-claude.js'; import { AwsBedrockProvider } from './aws-bedrock.js'; +import { ADDITIONAL_PROVIDER_DEFAULTS } from './provider-catalog.js'; import { lmStudioContextWindowIsLive, parseLlamaCppPropsContextWindow, @@ -25,7 +27,7 @@ const OPENROUTER_DEFAULT_MODEL = 'openrouter/free'; const OPENROUTER_LEGACY_DEFAULT_MODEL = 'stepfun/step-3.7-flash'; const OPENAI_DEFAULT_MODEL = 'gpt-5.6-terra'; const OPENAI_LEGACY_DEFAULT_MODEL = 'gpt-5.5'; -const SUPPORTED_PROVIDER_TYPES = new Set(['llamacpp', 'openai', 'azure_openai', 'aws_bedrock', 'anthropic', 'anthropic_oauth']); +const SUPPORTED_PROVIDER_TYPES = new Set(['llamacpp', 'openai', 'azure_openai', 'aws_bedrock', 'anthropic', 'anthropic_oauth', 'vertex_anthropic']); const SAFE_PROVIDER_ID_RE = /^[A-Za-z0-9_-]+$/; const ROUTER_PROVIDER_IDS = ['openrouter', 'cloudflare', 'nvidia', 'groq', 'huggingface', 'fireworks', 'together']; const PROVIDER_CREDENTIAL_KEYS = ['apiKey', 'accessKeyId', 'secretAccessKey', 'sessionToken']; @@ -328,13 +330,14 @@ export class ProviderManager { cloudflare: { type: 'openai', category: 'router', - label: 'Cloudflare Workers AI', + label: 'Cloudflare AI Gateway / Workers AI', providerName: 'cloudflare', baseUrl: 'https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/v1', model: '@cf/zai-org/glm-5.2', contextWindow: 262144, supportsStreamUsageOptions: false, accountId: '', + gatewayId: '', apiKey: '', apiKeyUrl: 'https://dash.cloudflare.com/profile/api-tokens', enabled: false, @@ -517,6 +520,7 @@ export class ProviderManager { apiKeyUrl: 'https://docs.z.ai/guides/overview/quick-start', enabled: false, }, + ...ADDITIONAL_PROVIDER_DEFAULTS, }; } @@ -622,6 +626,14 @@ export class ProviderManager { const normalizedConfig = { ...config, category: ProviderManager.categoryFor(id, config), + supportsAskStreaming: config.supportsAskStreaming ?? [ + 'llamacpp', + 'openai', + 'azure_openai', + 'anthropic', + 'anthropic_oauth', + 'vertex_anthropic', + ].includes(config.type), }; switch (normalizedConfig.type) { case 'llamacpp': @@ -636,6 +648,8 @@ export class ProviderManager { return new AnthropicProvider(normalizedConfig); case 'anthropic_oauth': return new AnthropicOAuthProvider(normalizedConfig); + case 'vertex_anthropic': + return new VertexAnthropicProvider(normalizedConfig); default: throw new Error(`Unknown provider type: ${normalizedConfig.type}`); } diff --git a/src/firefox/src/providers/openai.js b/src/firefox/src/providers/openai.js index 38133fc44..7b0cb8af9 100644 --- a/src/firefox/src/providers/openai.js +++ b/src/firefox/src/providers/openai.js @@ -34,18 +34,48 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { } get baseUrl() { - const baseUrl = this.config.baseUrl || 'https://api.openai.com/v1'; - if ((this.config.providerName || '').toLowerCase() !== 'cloudflare') return baseUrl; - if (!baseUrl.includes('{account_id}')) return baseUrl; - const accountId = String(this.config.accountId || '').trim(); - if (!/^[0-9a-f]{32}$/i.test(accountId)) { - throw new Error('Cloudflare Account ID is required and must be a 32-character hex string.'); + let baseUrl = String(this.config.baseUrl || 'https://api.openai.com/v1').trim(); + const vertexLocation = String(this.config.location || '').trim(); + const replacements = { + account_id: { + value: String(this.config.accountId || '').trim(), + valid: (value) => /^[0-9a-f]{32}$/i.test(value), + message: 'Cloudflare Account ID is required and must be a 32-character hex string.', + }, + project: { + value: String(this.config.project || '').trim(), + valid: (value) => /^[a-z][a-z0-9:._-]{4,127}$/i.test(value), + message: 'Google Cloud project ID is required.', + }, + location: { + value: vertexLocation, + valid: (value) => /^[a-z0-9-]+$/i.test(value), + message: 'Google Cloud location is required.', + }, + resource: { + value: String(this.config.resource || '').trim(), + valid: (value) => /^[a-z0-9-]{2,64}$/i.test(value), + message: 'Azure resource name is required.', + }, + vertex_endpoint: { + value: vertexLocation.toLowerCase() === 'global' + ? 'aiplatform.googleapis.com' + : `${vertexLocation}-aiplatform.googleapis.com`, + valid: (value) => /^(?:[a-z0-9-]+-)?aiplatform\.googleapis\.com$/i.test(value), + message: 'Google Cloud location is required.', + }, + }; + for (const [placeholder, replacement] of Object.entries(replacements)) { + if (!baseUrl.includes(`{${placeholder}}`)) continue; + if (!replacement.valid(replacement.value)) throw new Error(replacement.message); + baseUrl = baseUrl.replaceAll(`{${placeholder}}`, replacement.value); } - return baseUrl.replace('{account_id}', accountId); + return baseUrl.replace(/\/+$/, ''); } get model() { if (this.config.model) return this.config.model; + if (this.config.requiresModel) throw new Error(`${this.config.label || this.name} model is required.`); return String(this.config.providerName || '').toLowerCase() === 'openai' && this._isOfficialOpenAIBaseUrl() ? 'gpt-5.6-terra' @@ -53,7 +83,7 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { } get supportsTools() { - return true; + return this.config.supportsTools !== false; } get supportsVision() { @@ -76,7 +106,13 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { const headers = { 'Content-Type': 'application/json' }; const providerName = (this.config.providerName || '').toLowerCase(); if (this.config.apiKey) { - headers['Authorization'] = `Bearer ${this.config.apiKey}`; + if (this.config.apiKeyHeader === 'x-goog-api-key') { + headers['x-goog-api-key'] = String(this.config.apiKey); + } else if (this.config.apiKeyHeader === 'api-key') { + headers['api-key'] = String(this.config.apiKey); + } else { + headers['Authorization'] = `Bearer ${this.config.apiKey}`; + } } if (providerName === 'webbrain-cloud') { if (this.config.deviceGuid) headers['X-WebBrain-Device-Id'] = this.config.deviceGuid; @@ -88,6 +124,12 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { headers['HTTP-Referer'] = this.config.siteUrl || 'https://github.com/webbrain-one/webbrain'; headers['X-Title'] = 'WebBrain'; } + if (providerName === 'cloudflare') { + const configuredGatewayId = String(this.config.gatewayId || '').trim(); + const gatewayId = configuredGatewayId + || (String(this.model || '').trim().startsWith('@cf/') ? 'default' : ''); + if (gatewayId) headers['cf-aig-gateway-id'] = gatewayId; + } return headers; } @@ -232,7 +274,11 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { // DashScope rejects `tools` together with `stream: true`, while Ask always // supplies its read-only tool catalog. Keep even stale/imported opt-ins on // the safe non-streaming path. - if (String(resolved.providerName || '').trim().toLowerCase() === 'alibaba') { + if ([ + 'alibaba', + 'alibaba-coding-plan', + 'alibaba-coding-plan-cn', + ].includes(String(resolved.providerName || '').trim().toLowerCase())) { return false; } if (isOfficialOpenAIConfig(resolved)) { @@ -878,6 +924,7 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { const decoder = new TextDecoder(); let buffer = ''; let finalUsage = null; + let sawTerminalFinish = false; while (true) { let chunk; @@ -939,6 +986,9 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { `${this.name} Chat Completions stream failed with terminal finish reason "${finishReason}".`, ); } + if (finishReason != null) { + sawTerminalFinish = true; + } const delta = choice?.delta; const reasoningDelta = delta?.reasoning_content || delta?.reasoning; if (typeof reasoningDelta === 'string' && reasoningDelta) { @@ -953,6 +1003,10 @@ export class OpenAICompatibleProvider extends BaseLLMProvider { } } if (finalUsage) yield { type: 'usage', usage: finalUsage }; + if (sawTerminalFinish) { + yield { type: 'done', content: '' }; + return; + } if (this._supportsInteractiveAskStreaming()) { throw this._chatCompletionsStreamTransportError( `${this.name} Chat Completions stream ended before the [DONE] sentinel.`, diff --git a/src/firefox/src/providers/provider-catalog.js b/src/firefox/src/providers/provider-catalog.js new file mode 100644 index 000000000..a607bf805 --- /dev/null +++ b/src/firefox/src/providers/provider-catalog.js @@ -0,0 +1,148 @@ +/** + * Additional built-in providers. + * + * The catalog is a curated, checked-in snapshot of OpenCode's provider data at + * commit 62e4641235d7847dadc60da37cca8a023dd54fc1. Keeping it local makes the + * extension deterministic and avoids loading provider metadata at runtime. + */ + +const DEFAULT_API_KEY_PLACEHOLDER = 'API key'; + +function provider(id, label, baseUrl, model, contextWindow, options = {}) { + const { + category = 'router', + type = 'openai', + apiKeyUrl = '', + supportsVision = false, + supportsTools = true, + supportsAskStreaming = true, + suggestions = model ? [model] : [], + inputCostPerMillionUsd, + cacheReadCostPerMillionUsd, + cacheWriteCostPerMillionUsd, + outputCostPerMillionUsd, + apiKeyPlaceholder = DEFAULT_API_KEY_PLACEHOLDER, + ...config + } = options; + + return { + id, + config: { + type, + category, + label, + providerName: id, + baseUrl, + model, + contextWindow, + supportsVision, + supportsTools, + supportsAskStreaming, + // Chat Completions streaming is broadly supported, but the optional + // stream_options.include_usage extension is not. Individual providers + // can opt in later when their wire contract guarantees it. + supportsStreamUsageOptions: false, + apiKey: '', + apiKeyUrl, + enabled: false, + ...(inputCostPerMillionUsd == null ? {} : { inputCostPerMillionUsd }), + ...(cacheReadCostPerMillionUsd == null ? {} : { cacheReadCostPerMillionUsd }), + ...(cacheWriteCostPerMillionUsd == null ? {} : { cacheWriteCostPerMillionUsd }), + ...(outputCostPerMillionUsd == null ? {} : { outputCostPerMillionUsd }), + ...config, + }, + ui: { + suggestions, + apiKeyPlaceholder, + }, + }; +} + +const PROVIDERS = [ + provider('302ai', '302.AI', 'https://api.302.ai/v1', 'gpt-5.4-mini-2026-03-17', 400000, { apiKeyUrl: 'https://doc.302.ai', supportsVision: true, inputCostPerMillionUsd: 0.75, outputCostPerMillionUsd: 4.5 }), + provider('abacus', 'Abacus', 'https://routellm.abacus.ai/v1', 'o3', 200000, { apiKeyUrl: 'https://abacus.ai/help/api', supportsVision: true, inputCostPerMillionUsd: 2, cacheReadCostPerMillionUsd: 0.5, outputCostPerMillionUsd: 8 }), + provider('aihubmix', 'AIHubMix', 'https://aihubmix.com/v1', 'coding-minimax-m2.7', 204800, { apiKeyUrl: 'https://docs.aihubmix.com', inputCostPerMillionUsd: 0.2, outputCostPerMillionUsd: 0.2 }), + provider('alibaba-coding-plan', 'Alibaba Coding Plan', 'https://coding-intl.dashscope.aliyuncs.com/v1', 'qwen3-coder-plus', 1000000, { category: 'cloud', apiKeyUrl: 'https://www.alibabacloud.com/help/en/model-studio/coding-plan', supportsAskStreaming: false }), + provider('alibaba-coding-plan-cn', 'Alibaba Coding Plan (China)', 'https://coding.dashscope.aliyuncs.com/v1', 'qwen3-coder-plus', 1000000, { category: 'cloud', apiKeyUrl: 'https://help.aliyun.com/zh/model-studio/coding-plan', supportsAskStreaming: false }), + provider('azure-cognitive-services', 'Azure AI Foundry', 'https://{resource}.openai.azure.com/openai/v1', '', 200000, { category: 'cloud', apiKeyUrl: 'https://ai.azure.com/', apiKeyHeader: 'api-key', resource: '', requiresModel: true, supportsVision: true, apiKeyPlaceholder: 'Azure API key' }), + provider('bailing', 'Bailing', 'https://api.tbox.cn/api/llm/v1', 'Ling-1T', 128000, { category: 'cloud', apiKeyUrl: 'https://alipaytbox.yuque.com/sxs0ba/ling/intro', inputCostPerMillionUsd: 0.57, outputCostPerMillionUsd: 2.29 }), + provider('baseten', 'Baseten', 'https://inference.baseten.co/v1', 'moonshotai/Kimi-K2.6', 262000, { apiKeyUrl: 'https://docs.baseten.co/inference/model-apis/overview', supportsVision: true, inputCostPerMillionUsd: 0.95, cacheReadCostPerMillionUsd: 0.16, outputCostPerMillionUsd: 4 }), + provider('berget', 'Berget.AI', 'https://api.berget.ai/v1', 'meta-llama/Llama-3.3-70B-Instruct', 128000, { apiKeyUrl: 'https://api.berget.ai', inputCostPerMillionUsd: 0.99, outputCostPerMillionUsd: 0.99 }), + provider('cerebras', 'Cerebras', 'https://api.cerebras.ai/v1', 'gemma-4-31b', 131072, { category: 'cloud', apiKeyUrl: 'https://cloud.cerebras.ai/', supportsVision: true, inputCostPerMillionUsd: 0.99, outputCostPerMillionUsd: 1.49 }), + provider('chutes', 'Chutes', 'https://llm.chutes.ai/v1', 'moonshotai/Kimi-K2.6-TEE', 262144, { apiKeyUrl: 'https://chutes.ai/', supportsVision: true, inputCostPerMillionUsd: 0.66, cacheReadCostPerMillionUsd: 0.33, outputCostPerMillionUsd: 3.5 }), + provider('clarifai', 'Clarifai', 'https://api.clarifai.com/v2/ext/openai/v1', 'moonshotai/chat-completion/models/Kimi-K2_6', 262144, { apiKeyUrl: 'https://clarifai.com/settings/security', supportsVision: true, inputCostPerMillionUsd: 0.95, outputCostPerMillionUsd: 4, apiKeyPlaceholder: 'Personal access token' }), + provider('cloudferro-sherlock', 'CloudFerro Sherlock', 'https://api-sherlock.cloudferro.com/openai/v1', 'meta-llama/Llama-3.3-70B-Instruct', 70000, { apiKeyUrl: 'https://docs.sherlock.cloudferro.com/', inputCostPerMillionUsd: 2.92, outputCostPerMillionUsd: 2.92 }), + provider('cohere', 'Cohere', 'https://api.cohere.ai/compatibility/v1', 'command-a-03-2025', 256000, { category: 'cloud', apiKeyUrl: 'https://dashboard.cohere.com/api-keys', inputCostPerMillionUsd: 2.5, outputCostPerMillionUsd: 10 }), + provider('cortecs', 'Cortecs', 'https://api.cortecs.ai/v1', 'deepseek-r1-0528', 164000, { apiKeyUrl: 'https://api.cortecs.ai/v1/models', inputCostPerMillionUsd: 0.585, outputCostPerMillionUsd: 2.307 }), + provider('deepinfra', 'DeepInfra', 'https://api.deepinfra.com/v1/openai', 'meta-llama/Llama-4-Scout-17B-16E-Instruct', 327680, { apiKeyUrl: 'https://deepinfra.com/dash/api_keys', supportsVision: true, inputCostPerMillionUsd: 0.1, outputCostPerMillionUsd: 0.3 }), + provider('digitalocean', 'DigitalOcean Gradient AI', 'https://inference.do-ai.run/v1', 'anthropic-claude-haiku-4.5', 200000, { apiKeyUrl: 'https://cloud.digitalocean.com/account/api/tokens', supportsVision: true, inputCostPerMillionUsd: 1, cacheReadCostPerMillionUsd: 1, cacheWriteCostPerMillionUsd: 1.25, outputCostPerMillionUsd: 5, apiKeyPlaceholder: 'Access token' }), + provider('dinference', 'DInference', 'https://api.dinference.com/v1', 'minimax-m2.5', 200000, { apiKeyUrl: 'https://dinference.com', inputCostPerMillionUsd: 0.22, outputCostPerMillionUsd: 0.88 }), + provider('drun', 'D.Run (China)', 'https://chat.d.run/v1', 'public/deepseek-v3', 131072, { apiKeyUrl: 'https://www.d.run', inputCostPerMillionUsd: 0.28, outputCostPerMillionUsd: 1.1 }), + provider('evroc', 'evroc', 'https://models.think.evroc.com/v1', 'moonshotai/Kimi-K2.6', 262144, { apiKeyUrl: 'https://docs.evroc.com/products/think/overview.html', supportsVision: true, inputCostPerMillionUsd: 1.4375, outputCostPerMillionUsd: 5.75 }), + provider('fastrouter', 'FastRouter', 'https://go.fastrouter.ai/api/v1', 'moonshotai/kimi-k2', 131072, { apiKeyUrl: 'https://fastrouter.ai/models', inputCostPerMillionUsd: 0.55, outputCostPerMillionUsd: 2.2 }), + provider('friendli', 'Friendli', 'https://api.friendli.ai/serverless/v1', 'google/gemma-4-31B-it', 262144, { apiKeyUrl: 'https://friendli.ai/docs/guides/serverless_endpoints/introduction', supportsVision: true, inputCostPerMillionUsd: 0.14, outputCostPerMillionUsd: 0.4 }), + provider('google-vertex', 'Google Vertex AI', 'https://{vertex_endpoint}/v1/projects/{project}/locations/{location}/endpoints/openapi', 'gemini-2.5-flash', 1048576, { category: 'cloud', apiKeyUrl: 'https://console.cloud.google.com/apis/credentials', apiKeyHeader: 'x-goog-api-key', project: '', location: 'us-central1', supportsVision: true, apiKeyPlaceholder: 'Google authorization key' }), + provider('google-vertex-anthropic', 'Google Vertex AI (Anthropic)', 'https://{vertex_endpoint}', 'claude-haiku-4-5@20251001', 200000, { category: 'cloud', type: 'vertex_anthropic', apiKeyUrl: 'https://console.cloud.google.com/apis/credentials', project: '', location: 'us-east5', supportsVision: true, inputCostPerMillionUsd: 1, cacheReadCostPerMillionUsd: 0.1, cacheWriteCostPerMillionUsd: 1.25, outputCostPerMillionUsd: 5, apiKeyPlaceholder: 'Google authorization key' }), + provider('helicone', 'Helicone', 'https://ai-gateway.helicone.ai/v1', 'chatgpt-4o-latest', 128000, { apiKeyUrl: 'https://helicone.ai/', inputCostPerMillionUsd: 5, cacheReadCostPerMillionUsd: 2.5, outputCostPerMillionUsd: 20 }), + provider('iflowcn', 'iFlow', 'https://apis.iflow.cn/v1', 'qwen3-coder-plus', 256000, { apiKeyUrl: 'https://platform.iflow.cn/en/docs' }), + provider('inception', 'Inception', 'https://api.inceptionlabs.ai/v1', 'mercury-2', 128000, { category: 'cloud', apiKeyUrl: 'https://platform.inceptionlabs.ai/docs', inputCostPerMillionUsd: 0.25, cacheReadCostPerMillionUsd: 0.025, outputCostPerMillionUsd: 0.75 }), + provider('inference', 'Inference.net', 'https://inference.net/v1', 'mistral/mistral-nemo-12b-instruct', 16000, { apiKeyUrl: 'https://inference.net/models', inputCostPerMillionUsd: 0.038, outputCostPerMillionUsd: 0.1 }), + provider('io-net', 'IO.NET', 'https://api.intelligence.io.solutions/api/v1', 'meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8', 430000, { apiKeyUrl: 'https://io.net/docs/guides/intelligence/io-intelligence', inputCostPerMillionUsd: 0.15, cacheReadCostPerMillionUsd: 0.075, cacheWriteCostPerMillionUsd: 0.3, outputCostPerMillionUsd: 0.6 }), + provider('jiekou', 'Jiekou.AI', 'https://api.jiekou.ai/openai', 'o3', 131072, { apiKeyUrl: 'https://docs.jiekou.ai/docs/support/quickstart', supportsVision: true, inputCostPerMillionUsd: 10, outputCostPerMillionUsd: 40 }), + provider('kilo', 'Kilo Gateway', 'https://api.kilo.ai/api/gateway', 'inclusionai/ling-2.6-1t', 262144, { apiKeyUrl: 'https://kilo.ai', inputCostPerMillionUsd: 0.3, cacheReadCostPerMillionUsd: 0.06, outputCostPerMillionUsd: 2.5 }), + provider('kimi-for-coding', 'Kimi For Coding', 'https://api.kimi.com/coding/v1', 'kimi-for-coding', 262144, { category: 'cloud', apiKeyUrl: 'https://www.kimi.com/code/docs/en/', supportsVision: true, suggestions: ['kimi-for-coding', 'kimi-for-coding-highspeed', 'k3'] }), + provider('kuae-cloud-coding-plan', 'KUAE Cloud Coding Plan', 'https://coding-plan-endpoint.kuaecloud.net/v1', 'GLM-4.7', 204800, { category: 'cloud', apiKeyUrl: 'https://docs.mthreads.com/kuaecloud/kuaecloud-doc-online/coding_plan/' }), + provider('llama', 'Meta Llama API', 'https://api.llama.com/compat/v1', 'llama-4-scout-17b-16e-instruct-fp8', 128000, { category: 'cloud', apiKeyUrl: 'https://llama.developer.meta.com/', supportsVision: true }), + provider('lucidquery', 'LucidQuery', 'https://api.lucidquery.com/v1', 'lucidnova-rf1-100b', 120000, { apiKeyUrl: 'https://lucidquery.com/docs', supportsVision: true, inputCostPerMillionUsd: 2, outputCostPerMillionUsd: 5 }), + provider('meganova', 'Meganova', 'https://api.meganova.ai/v1', 'meta-llama/Llama-3.3-70B-Instruct', 131072, { apiKeyUrl: 'https://docs.meganova.ai', inputCostPerMillionUsd: 0.1, outputCostPerMillionUsd: 0.3 }), + provider('minimax-cn-coding-plan', 'MiniMax Token Plan (China)', 'https://api.minimaxi.com/v1', 'MiniMax-M2.1', 204800, { category: 'cloud', apiKeyUrl: 'https://platform.minimaxi.com/docs/token-plan/intro' }), + provider('minimax-coding-plan', 'MiniMax Token Plan', 'https://api.minimax.io/v1', 'MiniMax-M2.1', 204800, { category: 'cloud', apiKeyUrl: 'https://platform.minimax.io/docs/token-plan/intro' }), + provider('moark', 'Moark', 'https://moark.com/v1', 'MiniMax-M2.1', 204800, { apiKeyUrl: 'https://moark.com/docs/openapi/v1', inputCostPerMillionUsd: 2.1, outputCostPerMillionUsd: 8.4 }), + provider('modelscope', 'ModelScope', 'https://api-inference.modelscope.cn/v1', 'Qwen/Qwen3-30B-A3B-Thinking-2507', 262144, { apiKeyUrl: 'https://modelscope.cn/docs/model-service/API-Inference/intro' }), + provider('morph', 'Morph', 'https://api.morphllm.com/v1', 'morph-v3-fast', 16000, { category: 'cloud', apiKeyUrl: 'https://docs.morphllm.com/api-reference/introduction', supportsTools: false, inputCostPerMillionUsd: 0.8, outputCostPerMillionUsd: 1.2 }), + provider('nano-gpt', 'NanoGPT', 'https://nano-gpt.com/api/v1', 'claude-opus-4-thinking:8192', 200000, { apiKeyUrl: 'https://docs.nano-gpt.com', supportsVision: true, inputCostPerMillionUsd: 14.994, outputCostPerMillionUsd: 75.004 }), + provider('nebius', 'Nebius Token Factory', 'https://api.tokenfactory.nebius.com/v1', 'meta-llama/Llama-3.3-70B-Instruct', 128000, { apiKeyUrl: 'https://docs.tokenfactory.nebius.com/', inputCostPerMillionUsd: 0.13, cacheReadCostPerMillionUsd: 0.013, cacheWriteCostPerMillionUsd: 0.16, outputCostPerMillionUsd: 0.4 }), + provider('nova', 'Amazon Nova', 'https://api.nova.amazon.com/v1', 'nova-2-pro-v1', 1000000, { category: 'cloud', apiKeyUrl: 'https://nova.amazon.com/dev/documentation', supportsVision: true }), + provider('novita-ai', 'NovitaAI', 'https://api.novita.ai/openai', 'inclusionai/ling-2.6-1t', 262144, { apiKeyUrl: 'https://novita.ai/docs/guides/introduction', inputCostPerMillionUsd: 0.3, cacheReadCostPerMillionUsd: 0.06, outputCostPerMillionUsd: 2.5 }), + provider('ollama-cloud', 'Ollama Cloud', 'https://ollama.com/v1', 'deepseek-v4-flash', 1048576, { category: 'cloud', apiKeyUrl: 'https://docs.ollama.com/cloud' }), + provider('opencode', 'OpenCode Zen', 'https://opencode.ai/zen/v1', 'ring-2.6-1t-free', 262000, { apiKeyUrl: 'https://opencode.ai/docs/zen' }), + provider('opencode-go', 'OpenCode Go', 'https://opencode.ai/zen/go/v1', 'deepseek-v4-flash', 1000000, { apiKeyUrl: 'https://opencode.ai/docs/zen', inputCostPerMillionUsd: 0.14, cacheReadCostPerMillionUsd: 0.0028, outputCostPerMillionUsd: 0.28 }), + provider('ovhcloud', 'OVHcloud AI Endpoints', 'https://oai.endpoints.kepler.ai.cloud.ovh.net/v1', 'qwen3-coder-30b-a3b-instruct', 262144, { apiKeyUrl: 'https://www.ovhcloud.com/en/public-cloud/ai-endpoints/catalog/', inputCostPerMillionUsd: 0.07, outputCostPerMillionUsd: 0.26 }), + provider('perplexity', 'Perplexity Sonar', 'https://api.perplexity.ai', 'sonar-reasoning-pro', 128000, { category: 'cloud', apiKeyUrl: 'https://www.perplexity.ai/settings/api', supportsVision: true, supportsTools: false, inputCostPerMillionUsd: 2, outputCostPerMillionUsd: 8 }), + provider('perplexity-agent', 'Perplexity Agent', 'https://api.perplexity.ai/v1', 'xai/grok-4-1-fast-non-reasoning', 2000000, { category: 'cloud', apiKeyUrl: 'https://www.perplexity.ai/settings/api', supportsVision: true, apiFormat: 'responses', inputCostPerMillionUsd: 0.2, cacheReadCostPerMillionUsd: 0.05, outputCostPerMillionUsd: 0.5 }), + provider('poe', 'Poe', 'https://api.poe.com/v1', 'trytako/tako', 2048, { apiKeyUrl: 'https://poe.com/api_key', supportsVision: true }), + provider('privatemode-ai', 'Privatemode AI', 'http://localhost:8080/v1', 'gemma-3-27b', 128000, { category: 'local', apiKeyUrl: 'https://docs.privatemode.ai/api/overview', supportsVision: true }), + provider('qihang-ai', 'QiHang', 'https://api.qhaigc.net/v1', 'claude-haiku-4-5-20251001', 200000, { apiKeyUrl: 'https://www.qhaigc.net/docs', supportsVision: true, inputCostPerMillionUsd: 0.14, outputCostPerMillionUsd: 0.71 }), + provider('qiniu-ai', 'Qiniu', 'https://api.qnaigc.com/v1', 'deepseek-r1-0528', 128000, { apiKeyUrl: 'https://developer.qiniu.com/aitokenapi' }), + provider('requesty', 'Requesty', 'https://router.requesty.ai/v1', 'xai/grok-4', 256000, { apiKeyUrl: 'https://requesty.ai/solution/llm-routing/models', supportsVision: true, inputCostPerMillionUsd: 3, cacheReadCostPerMillionUsd: 0.75, cacheWriteCostPerMillionUsd: 3, outputCostPerMillionUsd: 15 }), + provider('scaleway', 'Scaleway', 'https://api.scaleway.ai/v1', 'qwen3-235b-a22b-instruct-2507', 260000, { apiKeyUrl: 'https://www.scaleway.com/en/docs/generative-apis/', inputCostPerMillionUsd: 0.75, outputCostPerMillionUsd: 2.25 }), + provider('siliconflow', 'SiliconFlow', 'https://api.siliconflow.com/v1', 'moonshotai/Kimi-K2.6', 262000, { apiKeyUrl: 'https://cloud.siliconflow.com/account/ak', inputCostPerMillionUsd: 0.77, cacheReadCostPerMillionUsd: 0.2, outputCostPerMillionUsd: 4 }), + provider('siliconflow-cn', 'SiliconFlow (China)', 'https://api.siliconflow.cn/v1', 'baidu/ERNIE-4.5-300B-A47B', 131000, { apiKeyUrl: 'https://cloud.siliconflow.cn/account/ak', inputCostPerMillionUsd: 0.28, outputCostPerMillionUsd: 1.1 }), + provider('stackit', 'STACKIT', 'https://api.openai-compat.model-serving.eu01.onstackit.cloud/v1', 'cortecs/Llama-3.3-70B-Instruct-FP8-Dynamic', 128000, { apiKeyUrl: 'https://docs.stackit.cloud/products/data-and-ai/ai-model-serving/', inputCostPerMillionUsd: 0.53, outputCostPerMillionUsd: 0.76 }), + provider('stepfun', 'StepFun', 'https://api.stepfun.com/v1', 'step-1-32k', 32768, { category: 'cloud', apiKeyUrl: 'https://platform.stepfun.com/docs/zh/overview/concept', inputCostPerMillionUsd: 2.05, cacheReadCostPerMillionUsd: 0.41, outputCostPerMillionUsd: 9.59 }), + provider('submodel', 'submodel', 'https://llm.submodel.ai/v1', 'Qwen/Qwen3-235B-A22B-Thinking-2507', 262144, { apiKeyUrl: 'https://submodel.gitbook.io', inputCostPerMillionUsd: 0.2, outputCostPerMillionUsd: 0.6 }), + provider('synthetic', 'Synthetic', 'https://api.synthetic.new/openai/v1', 'hf:moonshotai/Kimi-K2.7-Code', 262144, { apiKeyUrl: 'https://synthetic.new/', supportsVision: true, inputCostPerMillionUsd: 0.95, cacheReadCostPerMillionUsd: 0.95, outputCostPerMillionUsd: 4 }), + provider('tencent-coding-plan', 'Tencent Coding Plan (China)', 'https://api.lkeap.cloud.tencent.com/coding/v3', 'minimax-m2.5', 204800, { category: 'cloud', apiKeyUrl: 'https://cloud.tencent.com/document/product/1772/128947' }), + provider('upstage', 'Upstage', 'https://api.upstage.ai/v1/solar', 'solar-pro2', 65536, { category: 'cloud', apiKeyUrl: 'https://console.upstage.ai/api-keys', inputCostPerMillionUsd: 0.25, outputCostPerMillionUsd: 0.25 }), + provider('v0', 'v0', 'https://api.v0.dev/v1', 'v0-1.0-md', 128000, { category: 'cloud', apiKeyUrl: 'https://v0.dev/chat/settings/keys', supportsVision: true, inputCostPerMillionUsd: 3, outputCostPerMillionUsd: 15 }), + provider('venice', 'Venice AI', 'https://api.venice.ai/api/v1', 'z-ai-glm-5-turbo', 200000, { apiKeyUrl: 'https://venice.ai/settings/api', inputCostPerMillionUsd: 1.2, cacheReadCostPerMillionUsd: 0.24, outputCostPerMillionUsd: 4 }), + provider('vercel', 'Vercel AI Gateway', 'https://ai-gateway.vercel.sh/v1', 'xai/grok-4.1-fast-reasoning', 1000000, { apiKeyUrl: 'https://vercel.com/ai-gateway', inputCostPerMillionUsd: 0.2, cacheReadCostPerMillionUsd: 0.05, outputCostPerMillionUsd: 0.5 }), + provider('vivgrid', 'Vivgrid', 'https://api.vivgrid.com/v1', 'deepseek-v4-pro', 1000000, { apiKeyUrl: 'https://docs.vivgrid.com/models', inputCostPerMillionUsd: 0.435, cacheReadCostPerMillionUsd: 0.003625, outputCostPerMillionUsd: 0.87 }), + provider('vultr', 'Vultr', 'https://api.vultrinference.com/v1', 'moonshotai/Kimi-K2.6', 262144, { apiKeyUrl: 'https://my.vultr.com/', supportsVision: true, inputCostPerMillionUsd: 0.3, outputCostPerMillionUsd: 1.2 }), + provider('wandb', 'Weights & Biases', 'https://api.inference.wandb.ai/v1', 'ibm-granite/granite-4.1-8b', 131072, { apiKeyUrl: 'https://wandb.ai/authorize', inputCostPerMillionUsd: 0.05, cacheReadCostPerMillionUsd: 0.05, outputCostPerMillionUsd: 0.1 }), + provider('xiaomi', 'Xiaomi MiMo', 'https://api.xiaomimimo.com/v1', 'mimo-v2.5-pro-ultraspeed', 1048576, { category: 'cloud', apiKeyUrl: 'https://platform.xiaomimimo.com/', inputCostPerMillionUsd: 1.305, cacheReadCostPerMillionUsd: 0.0108, outputCostPerMillionUsd: 2.61 }), + provider('zai-coding-plan', 'Z.AI Coding Plan', 'https://api.z.ai/api/coding/paas/v4', 'glm-4.7', 204800, { category: 'cloud', apiKeyUrl: 'https://docs.z.ai/devpack/overview' }), + provider('zenmux', 'ZenMux', 'https://zenmux.ai/api/v1', 'inclusionai/ling-1t', 128000, { apiKeyUrl: 'https://docs.zenmux.ai', inputCostPerMillionUsd: 0.56, cacheReadCostPerMillionUsd: 0.11, outputCostPerMillionUsd: 2.24 }), + provider('zhipuai', 'Zhipu AI', 'https://open.bigmodel.cn/api/paas/v4', 'glm-5.1', 200000, { category: 'cloud', apiKeyUrl: 'https://open.bigmodel.cn/usercenter/apikeys', inputCostPerMillionUsd: 1.4, cacheReadCostPerMillionUsd: 0.26, outputCostPerMillionUsd: 4.4 }), + provider('zhipuai-coding-plan', 'Zhipu AI Coding Plan', 'https://open.bigmodel.cn/api/coding/paas/v4', 'glm-5.1', 200000, { category: 'cloud', apiKeyUrl: 'https://docs.bigmodel.cn/cn/coding-plan/overview' }), +]; + +export const ADDITIONAL_PROVIDER_IDS = Object.freeze(PROVIDERS.map(({ id }) => id)); + +export const ADDITIONAL_PROVIDER_DEFAULTS = Object.freeze(Object.fromEntries( + PROVIDERS.map(({ id, config }) => [id, Object.freeze(config)]), +)); + +export const ADDITIONAL_PROVIDER_UI = Object.freeze(Object.fromEntries( + PROVIDERS.map(({ id, ui }) => [id, Object.freeze(ui)]), +)); diff --git a/src/firefox/src/providers/provider-compatibility.js b/src/firefox/src/providers/provider-compatibility.js index 0c7a0b6fa..60d1c026f 100644 --- a/src/firefox/src/providers/provider-compatibility.js +++ b/src/firefox/src/providers/provider-compatibility.js @@ -57,6 +57,7 @@ export function isOfficialOpenAIConfig(config = {}) { } export function shouldUseOpenAIResponsesApi(config = {}) { + if (config.apiFormat === 'responses') return true; if (!isOfficialOpenAIConfig(config)) return false; const model = String(config.model || '').trim().toLowerCase(); // GPT-5.6 needs Responses for reliable reasoning/tool replay. GPT-5 Pro, diff --git a/src/firefox/src/providers/vertex-anthropic.js b/src/firefox/src/providers/vertex-anthropic.js new file mode 100644 index 000000000..f25a0a7e6 --- /dev/null +++ b/src/firefox/src/providers/vertex-anthropic.js @@ -0,0 +1,63 @@ +import { AnthropicProvider } from './anthropic.js'; + +/** + * Anthropic Claude through Vertex AI's rawPredict/streamRawPredict endpoints. + * Authentication uses a user-created Google authorization key rather than an + * interactive OAuth flow. + */ +export class VertexAnthropicProvider extends AnthropicProvider { + get name() { + return 'google-vertex-anthropic'; + } + + get supportsVision() { + return this.config.supportsVision !== false; + } + + _vertexCoordinates() { + const project = String(this.config.project || '').trim(); + const location = String(this.config.location || '').trim(); + if (!/^[a-z][a-z0-9:._-]{4,127}$/i.test(project)) { + throw new Error('Google Cloud project ID is required.'); + } + if (!/^[a-z0-9-]+$/i.test(location)) { + throw new Error('Google Cloud location is required.'); + } + if (!String(this.config.apiKey || '').trim()) { + throw new Error('Google authorization key is required.'); + } + return { project, location }; + } + + _headers() { + return { + 'Content-Type': 'application/json', + 'x-goog-api-key': String(this.config.apiKey || ''), + }; + } + + _vertexEndpointHost(location) { + const normalized = String(location || '').trim().toLowerCase(); + if (normalized === 'global') return 'aiplatform.googleapis.com'; + if (normalized === 'us' || normalized === 'eu') { + return `aiplatform.${normalized}.rep.googleapis.com`; + } + return `${normalized}-aiplatform.googleapis.com`; + } + + _messagesUrl(stream = false) { + const { project, location } = this._vertexCoordinates(); + const action = stream ? 'streamRawPredict' : 'rawPredict'; + const endpointHost = this._vertexEndpointHost(location); + return `https://${endpointHost}/v1/projects/${encodeURIComponent(project)}/locations/${encodeURIComponent(location)}/publishers/anthropic/models/${encodeURIComponent(this.model)}:${action}`; + } + + _prepareRequestBody(body, _options = {}, stream = false) { + const { model: _model, stream: _stream, ...payload } = body; + return { + ...payload, + anthropic_version: 'vertex-2023-10-16', + ...(stream ? { stream: true } : {}), + }; + } +} diff --git a/src/firefox/src/ui/locales/ar.js b/src/firefox/src/ui/locales/ar.js index d6951916a..0127081eb 100644 --- a/src/firefox/src/ui/locales/ar.js +++ b/src/firefox/src/ui/locales/ar.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'انقطع بث الاستجابة؛ تتم إعادة محاولة دور Ask هذا بدون بث.', 'sp.providers.no_setup_group': 'لا يتطلب إعدادًا', 'sp.providers.no_setup': 'بلا إعداد', 'sp.providers.active_group': 'المزوّدون النشطون', @@ -631,8 +632,8 @@ export default { 'st.display.clarify_timeout.instant': 'فوري', 'st.display.api_mutation_observer.label': 'مراقب تحولات API', 'st.display.api_mutation_observer.desc': 'مراقبة عناوين URL وطرق طلبات XHR/fetch في نفس التبويب ليتمكن WebBrain من اكتشاف إجراءات الواجهة المتكررة واقتراح أنماط اختصارات API. معطل افتراضياً؛ قم بتفعيله فقط أثناء التحقيق في سلوك الاختصار أو زمن الاستجابة.', - 'st.display.openai_ask_streaming.label': 'بث ردود OpenAI في وضع السؤال', - 'st.display.openai_ask_streaming.desc': 'اعرض نص OpenAI Responses الرسمية فور وصوله في وضع السؤال. تنتظر استدعاءات الأدوات response.completed؛ وتبقى تشغيلات Act وDev والمجدولة والسحابية وContinue بدون بث. مفعّل افتراضياً.', + 'st.display.openai_ask_streaming.label': "?? ?????? ?? ??? ??????", + 'st.display.openai_ask_streaming.desc': "???? ???? ??????? ??? ?????? ?? ??? ??????. ????? ????????? ??????? ??? ?????? ??????? ???? ?????? Act ?Dev ????????? ????????? ?Continue ??? ??. ????? ?????????.", 'st.display.plan_before_act.label': 'التخطيط قبل التنفيذ', 'st.display.plan_before_act.desc': 'يجري وضعا Act وDev دائمًا فحصًا منظمًا للنية قبل تشغيل الأدوات. وضع المحاولة (الافتراضي) ينشئ أيضًا خططًا كاملة، لكنه قد يعيد استخدام خطة معتمدة حديثًا لمتابعة قصيرة؛ الوضع الصارم ينشئ خطة كاملة في كل دورة. يعود وضع المحاولة إلى دورة للقراءة فقط إذا ظل القصد أو التخطيط غير صالح بعد محاولة إصلاح واحدة؛ ويتوقف الوضع الصارم قبل تشغيل الأدوات.', 'st.display.plan_before_act.try': 'محاولة التخطيط (افتراضياً)', diff --git a/src/firefox/src/ui/locales/bn.js b/src/firefox/src/ui/locales/bn.js index 59c929fba..509eec294 100644 --- a/src/firefox/src/ui/locales/bn.js +++ b/src/firefox/src/ui/locales/bn.js @@ -1,5 +1,6 @@ // Bengali — translated from the canonical English locale. export default { + 'sp.streaming.fallback': 'প্রতিক্রিয়া স্ট্রিম বাধাগ্রস্ত হয়েছে; স্ট্রিমিং ছাড়া এই Ask পালাটি আবার চেষ্টা করা হচ্ছে।', 'sp.providers.no_setup_group': "কোন সেটআপ প্রয়োজন", 'sp.providers.no_setup': "কোনো সেটআপ নেই", 'sp.providers.active_group': "সক্রিয় প্রদানকারী", @@ -490,8 +491,8 @@ export default { 'st.display.voice_input.desc': "চ্যাট ইনপুটে মাইক বোতামটিকে আপনার ব্রাউজারের স্পিচ রিকগনিশনের মাধ্যমে পাঠ্য নির্দেশ করতে দিন। এটি সমর্থন করে এমন ব্রাউজারগুলিতে ডিফল্টরূপে চালু৷", 'st.display.api_mutation_observer.label': "API মিউটেশন পর্যবেক্ষক", 'st.display.api_mutation_observer.desc': "একই-ট্যাব XHR/ফেচ অনুরোধ URL এবং পদ্ধতিগুলি পর্যবেক্ষণ করুন যাতে WebBrain বারবার UI অ্যাকশন সনাক্ত করতে পারে এবং API শর্টকাট প্যাটার্নের পরামর্শ দিতে পারে। ডিফল্টরূপে বন্ধ; শুধুমাত্র শর্টকাট আচরণ বা লেটেন্সি তদন্ত করার সময় সক্ষম করুন।", - 'st.display.openai_ask_streaming.label': "স্ট্রীম OpenAI উত্তর জিজ্ঞাসা করুন", - 'st.display.openai_ask_streaming.desc': "আস্ক মোডে আসার সাথে সাথে অফিসিয়াল OpenAI প্রতিক্রিয়া টেক্সট দেখান। টুল কল প্রতিক্রিয়া জন্য অপেক্ষা করুন.completed; অ্যাক্ট, দেব, নির্ধারিত, ক্লাউড, এবং চালিয়ে যান নন-স্ট্রিমিং থাকুন। ডিফল্টরূপে চালু", + 'st.display.openai_ask_streaming.label': "Ask ????? ????? ??????? ????", + 'st.display.openai_ask_streaming.desc': "Ask ???? ???????????? ????? ???? ????? ????? ?????? ??? ?? ???? ???????? ??????? ???????? ???? ??????? ???; Act, Dev, ?????????, ?????? ? Continue ??? ??????? ??? ??? ?????????? ?????", 'st.display.plan_before_act.label': "আইনের আগে পরিকল্পনা করুন", 'st.display.plan_before_act.desc': "Act এবং Dev সবসময় টুলের আগে একটি স্ট্রাকচার্ড ইনটেন্ট চেক চালান। চেষ্টা করুন (ডিফল্ট) সম্পূর্ণ পরিকল্পনা তৈরি করে তবে একটি সংক্ষিপ্ত ফলো-আপের জন্য সম্প্রতি অনুমোদিত একটি পরিকল্পনা পুনরায় ব্যবহার করতে পারে; কঠোর প্রতি পাল্লায় একটি পূর্ণ পরিকল্পনা তৈরি করে। একটি মেরামতের পরে যদি অভিপ্রায় বা পরিকল্পনা অবৈধ থেকে যায় তবে একটি শুধুমাত্র-পঠনযোগ্য মোড়তে ফিরে যাওয়ার চেষ্টা করুন; সরঞ্জামের আগে কঠোর স্টপ।", 'st.display.plan_before_act.try': "পরিকল্পনা করার চেষ্টা করুন (ডিফল্ট)", diff --git a/src/firefox/src/ui/locales/de.js b/src/firefox/src/ui/locales/de.js index 4dd379dd1..7c761e730 100644 --- a/src/firefox/src/ui/locales/de.js +++ b/src/firefox/src/ui/locales/de.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Der Antwortstream wurde unterbrochen; dieser Ask-Durchgang wird ohne Streaming erneut versucht.', 'sp.providers.no_setup_group': 'Keine Einrichtung erforderlich', 'sp.providers.no_setup': 'Keine Einrichtung', 'sp.providers.active_group': 'Aktive Anbieter', @@ -485,8 +486,8 @@ export default { 'st.display.voice_input.desc': 'Ermöglicht dem Mikrofon-Button in der Chat-Eingabe, Text über die Spracherkennung Ihres Browsers zu diktieren.', 'st.display.api_mutation_observer.label': 'API-Mutations-Observer', 'st.display.api_mutation_observer.desc': 'Beobachtet XHR/fetch-Anfragen-URLs und Methoden im selben Tab, damit WebBrain wiederkehrende UI-Aktionen erkennen und API-Verknüpfungsmuster vorschlagen kann.', - 'st.display.openai_ask_streaming.label': 'OpenAI Ask-Antworten streamen', - 'st.display.openai_ask_streaming.desc': 'Zeigt den offiziellen OpenAI Responses-Text in Echtzeit im Fragen-Modus an.', + 'st.display.openai_ask_streaming.label': 'Ask-Antworten streamen', + 'st.display.openai_ask_streaming.desc': 'Zeigt Text für unterstützte Anbieter im Ask-Modus während des Empfangs an. Unterbrochene Streams zeigen einen Hinweis und werden einmal ohne Streaming wiederholt. Werkzeugaufrufe warten auf das Stream-Ende; Act-, Dev-, geplante, Cloud- und Continue-Läufe bleiben ohne Streaming. Standardmäßig aktiviert.', 'st.display.plan_before_act.label': 'Vor dem Handeln planen', 'st.display.plan_before_act.desc': 'Handeln und Dev führen immer eine strukturierte Intent-Prüfung vor den Tools durch.', 'st.display.plan_before_act.try': 'Planierung versuchen (Standard)', diff --git a/src/firefox/src/ui/locales/en.js b/src/firefox/src/ui/locales/en.js index 74019f5ea..fd0694ed6 100644 --- a/src/firefox/src/ui/locales/en.js +++ b/src/firefox/src/ui/locales/en.js @@ -1,5 +1,6 @@ // English — canonical locale. Other locales inherit key names from this file. export default { + 'sp.streaming.fallback': 'Response streaming was interrupted; retrying this Ask turn without streaming.', 'sp.providers.no_setup_group': 'No setup required', 'sp.providers.no_setup': 'No setup', 'sp.providers.active_group': 'Active providers', @@ -492,7 +493,7 @@ export default { 'st.display.api_mutation_observer.desc': 'Observe same-tab XHR/fetch request URLs and methods so WebBrain can detect repeated UI actions and suggest API shortcut patterns. Off by default; enable only while investigating shortcut behavior or latency.', // TRANSLATORS: Updated for multi-provider Ask streaming and silent transport fallback. 'st.display.openai_ask_streaming.label': 'Stream Ask responses', - 'st.display.openai_ask_streaming.desc': 'Show text as it arrives in Ask mode for supported providers. Interrupted streams silently retry once without streaming; provider/API errors are still shown. Tool calls wait for stream completion; Act, Dev, scheduled, cloud, and Continue runs stay non-streaming. On by default.', + 'st.display.openai_ask_streaming.desc': 'Show text as it arrives in Ask mode for supported providers. Interrupted streams show a notice and retry once without streaming; provider/API errors are still shown. Tool calls wait for stream completion; Act, Dev, scheduled, cloud, and Continue runs stay non-streaming. On by default.', 'st.display.plan_before_act.label': 'Plan before Act', 'st.display.plan_before_act.desc': 'Act and Dev always run a structured intent check before tools. Try (default) also builds full plans but may reuse a recently approved plan for a short follow-up; Strict builds a full plan every turn. Try falls back to a read-only turn if intent or planning remains invalid after one repair; Strict stops before tools.', 'st.display.plan_before_act.try': 'Try planning (default)', diff --git a/src/firefox/src/ui/locales/es.js b/src/firefox/src/ui/locales/es.js index 935a5546a..14e6f5504 100644 --- a/src/firefox/src/ui/locales/es.js +++ b/src/firefox/src/ui/locales/es.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Se interrumpió la transmisión de la respuesta; reintentando este turno de Ask sin transmisión.', 'sp.providers.no_setup_group': 'Sin configuración', 'sp.providers.no_setup': 'No requiere configuración', 'sp.providers.active_group': 'Proveedores activos', @@ -631,8 +632,8 @@ export default { 'st.display.clarify_timeout.instant': 'Instantáneo', 'st.display.api_mutation_observer.label': 'Observador de mutaciones de API', 'st.display.api_mutation_observer.desc': 'Observa las URLs y métodos de peticiones XHR/fetch en la misma pestaña para que WebBrain pueda detectar acciones repetidas de la interfaz y sugerir patrones de acceso directo por API. Desactivado por defecto; actívalo solo mientras investigas comportamientos de acceso directo o latencia.', - 'st.display.openai_ask_streaming.label': 'Transmitir respuestas OpenAI en Ask', - 'st.display.openai_ask_streaming.desc': 'Muestra el texto de OpenAI Responses oficial a medida que llega en modo Ask. Las llamadas a herramientas esperan a response.completed; Act, Dev, las ejecuciones programadas, en la nube y Continue siguen sin transmisión. Activado por defecto.', + 'st.display.openai_ask_streaming.label': "Transmitir respuestas en modo Ask", + 'st.display.openai_ask_streaming.desc': "Muestra las respuestas del proveedor a medida que llegan en modo Ask. Las llamadas a herramientas esperan un evento final del flujo; Act, Dev, las ejecuciones programadas, en la nube y Continue siguen sin transmisi?n. Activado por defecto.", 'st.display.plan_before_act.label': 'Planificar antes de actuar', 'st.display.plan_before_act.desc': 'Los modos Actuar y Dev siempre ejecutan una comprobación estructurada de intención antes de las herramientas. Intentar (predeterminado) también crea planes completos, pero puede reutilizar un plan aprobado recientemente para un seguimiento breve; Estricto crea un plan completo en cada turno. Intentar recurre a un turno de solo lectura si la intención o el plan siguen siendo inválidos tras una reparación; Estricto se detiene antes de usar herramientas.', 'st.display.plan_before_act.try': 'Intentar planificar (por defecto)', diff --git a/src/firefox/src/ui/locales/fa.js b/src/firefox/src/ui/locales/fa.js index e9d9790a8..9d3119b5b 100644 --- a/src/firefox/src/ui/locales/fa.js +++ b/src/firefox/src/ui/locales/fa.js @@ -1,5 +1,6 @@ // Persian — translated from the canonical English locale. export default { + 'sp.streaming.fallback': 'جریان پاسخ قطع شد؛ این نوبت Ask بدون پخش جریانی دوباره امتحان می‌شود.', 'sp.providers.no_setup_group': "بدون نیاز به راه اندازی", 'sp.providers.no_setup': "بدون راه اندازی", 'sp.providers.active_group': "ارائه دهندگان فعال", @@ -490,8 +491,8 @@ export default { 'st.display.voice_input.desc': "اجازه دهید دکمه میکروفون در ورودی چت، متن را از طریق تشخیص گفتار مرورگر شما دیکته کند. به طور پیش فرض در مرورگرهایی که از آن پشتیبانی می کنند روشن است.", 'st.display.api_mutation_observer.label': "مشاهده گر جهش API", 'st.display.api_mutation_observer.desc': "نشانی‌های وب و روش‌های درخواستی XHR/واکشی همان تب را مشاهده کنید تا WebBrain بتواند اقدامات مکرر UI را تشخیص دهد و الگوهای میانبر API را پیشنهاد کند. خاموش به طور پیش فرض؛ فقط هنگام بررسی رفتار میانبر یا تأخیر فعال شود.", - 'st.display.openai_ask_streaming.label': "پخش جریانی OpenAI پاسخ‌ها را بپرسید", - 'st.display.openai_ask_streaming.desc': "نمایش رسمی OpenAI به متن پاسخ می دهد که در حالت سؤال می رسد. فراخوانی ابزار منتظر answer.completed است. اجراهای Act، Dev، برنامه‌ریزی‌شده، ابری و Continue پخش نمی‌شوند. به طور پیش فرض روشن است.", + 'st.display.openai_ask_streaming.label': "??? ??????? ?? ???? Ask", + 'st.display.openai_ask_streaming.desc': "???????? ??????????? ?? ????? ?????? ?? ???? Ask ????? ????. ???????? ????? ????? ?????? ?????? ????? ???????? ??????? Act? Dev? ?????????????? ???? ? Continue ???? ??? ???? ????????. ?????? ??????? ???? ???.", 'st.display.plan_before_act.label': "قبل از قانون برنامه ریزی کنید", 'st.display.plan_before_act.desc': "Act و Dev همیشه قبل از ابزارها یک بررسی قصد ساخت یافته انجام می دهند. سعی کنید (پیش‌فرض) همچنین برنامه‌های کاملی را ایجاد می‌کند، اما ممکن است از طرحی که اخیراً تأیید شده است برای یک پیگیری کوتاه دوباره استفاده کنید. Strict در هر نوبت یک برنامه کامل می سازد. اگر بعد از یک بار تعمیر، قصد یا برنامه ریزی نامعتبر باقی بماند، سعی به یک نوبت فقط خواندنی برمی گردد. توقف های سخت قبل از ابزار.", 'st.display.plan_before_act.try': "برنامه ریزی را امتحان کنید (پیش فرض)", diff --git a/src/firefox/src/ui/locales/fr.js b/src/firefox/src/ui/locales/fr.js index 834b8746c..81bdc2c1e 100644 --- a/src/firefox/src/ui/locales/fr.js +++ b/src/firefox/src/ui/locales/fr.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Le flux de réponse a été interrompu ; nouvelle tentative de ce tour Ask sans streaming.', 'sp.providers.no_setup_group': 'Sans configuration', 'sp.providers.no_setup': 'Aucune configuration requise', 'sp.providers.active_group': 'Fournisseurs actifs', @@ -631,8 +632,8 @@ export default { 'st.display.clarify_timeout.instant': 'Immédiat', 'st.display.api_mutation_observer.label': 'Observateur de mutations API', 'st.display.api_mutation_observer.desc': 'Observer les URLs et méthodes des requêtes XHR/fetch dans le même onglet pour que WebBrain puisse détecter des actions UI répétées et suggérer des modèles de raccourcis API. Désactivé par défaut ; activer seulement lors de l\'investigation de comportements de raccourci ou de latence.', - 'st.display.openai_ask_streaming.label': 'Diffuser les réponses OpenAI en mode Ask', - 'st.display.openai_ask_streaming.desc': 'Afficher le texte officiel de OpenAI Responses au fil de son arrivée en mode Ask. Les appels outils attendent response.completed ; Act, Dev, les exécutions planifiées, cloud et Continue restent sans diffusion. Activé par défaut.', + 'st.display.openai_ask_streaming.label': "Diffuser les r?ponses en mode Ask", + 'st.display.openai_ask_streaming.desc': "Afficher les r?ponses du fournisseur au fil de leur arriv?e en mode Ask. Les appels d?outils attendent un ?v?nement terminal du flux ; Act, Dev, les ex?cutions planifi?es, cloud et Continue restent sans diffusion. Activ? par d?faut.", 'st.display.plan_before_act.label': 'Planifier avant d\'agir', 'st.display.plan_before_act.desc': 'Les modes Act et Dev effectuent toujours une vérification structurée de l’intention avant les outils. Essai (par défaut) crée aussi des plans complets, mais peut réutiliser un plan récemment approuvé pour un bref suivi ; Strict crée un plan complet à chaque tour. Essai passe à un tour en lecture seule si l’intention ou le plan reste invalide après une réparation ; Strict s’arrête avant les outils.', 'st.display.plan_before_act.try': 'Essayer la planification (par défaut)', diff --git a/src/firefox/src/ui/locales/he.js b/src/firefox/src/ui/locales/he.js index 0aedceb10..35d465b25 100644 --- a/src/firefox/src/ui/locales/he.js +++ b/src/firefox/src/ui/locales/he.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'הזרמת התשובה נקטעה; מתבצע ניסיון חוזר לתור Ask הזה ללא הזרמה.', 'sp.providers.no_setup_group': 'ללא הגדרה', 'sp.providers.no_setup': 'אין צורך בהגדרה', 'sp.providers.active_group': 'ספקים פעילים', @@ -453,8 +454,8 @@ export default { "st.display.voice_input.desc": "תן ללחצן המיקרופון בקלט הצ'אט להכתיב טקסט באמצעות זיהוי הדיבור של הדפדפן שלך. פועל כברירת מחדל בדפדפנים התומכים בו.", "st.display.api_mutation_observer.label": "מעקב אחר שינויי API", "st.display.api_mutation_observer.desc": "עקוב אחר כתובות URL ושיטות של בקשות XHR/fetch באותה כרטיסייה, כדי ש-WebBrain יוכל לזהות פעולות חוזרות בממשק ולהציע דפוסי קיצור דרך דרך ה-API. כבוי כברירת מחדל; הפעל רק בעת בדיקת קיצורי דרך או זמני תגובה.", - "st.display.openai_ask_streaming.label": "הזרמת תשובות OpenAI במצב Ask", - "st.display.openai_ask_streaming.desc": "הצג טקסט רשמי של OpenAI Responses בזמן הגעתו במצב Ask. קריאות לכלים ממתינות ל-response.completed; הפעלות Act, Dev, מתוזמנות, בענן ו-Continue נשארות ללא הזרמה. מופעל כברירת מחדל.", + 'st.display.openai_ask_streaming.label': "????? ?????? ???? Ask", + 'st.display.openai_ask_streaming.desc': "??? ?? ?????? ???? ???? ????? ???? Ask. ?????? ????? ??????? ?????? ???? ?? ????; ?????? Act, Dev, ????????, ???? ?-Continue ?????? ??? ?????. ????? ?????? ????.", "st.display.plan_before_act.label": "תכנן לפני מעשה", "st.display.plan_before_act.desc": "מצבי Act ו-Dev מבצעים תמיד בדיקת כוונה מובנית לפני הפעלת כלים. מצב ניסיון (ברירת המחדל) גם יוצר תוכניות מלאות, אך עשוי להשתמש שוב בתוכנית שאושרה לאחרונה לצורך המשך קצר; מצב קפדני יוצר תוכנית מלאה בכל תור. מצב ניסיון עובר לתור קריאה בלבד אם הכוונה או התכנון עדיין לא תקינים לאחר ניסיון תיקון אחד; מצב קפדני נעצר לפני הכלים.", "st.display.plan_before_act.try": "נסה לתכנן (ברירת מחדל)", diff --git a/src/firefox/src/ui/locales/hi.js b/src/firefox/src/ui/locales/hi.js index 696a75e87..40c4437d4 100644 --- a/src/firefox/src/ui/locales/hi.js +++ b/src/firefox/src/ui/locales/hi.js @@ -1,5 +1,6 @@ // Hindi — translated from the canonical English locale. export default { + 'sp.streaming.fallback': 'प्रतिक्रिया स्ट्रीम बाधित हुई; इस Ask टर्न को बिना स्ट्रीमिंग के फिर से आज़माया जा रहा है।', 'sp.providers.no_setup_group': "किसी सेटअप की आवश्यकता नहीं है", 'sp.providers.no_setup': "कोई सेटअप नहीं", 'sp.providers.active_group': "सक्रिय प्रदाता", @@ -490,8 +491,8 @@ export default { 'st.display.voice_input.desc': "चैट इनपुट में माइक बटन को अपने ब्राउज़र की वाक् पहचान के माध्यम से टेक्स्ट निर्देशित करने दें। इसका समर्थन करने वाले ब्राउज़र में डिफ़ॉल्ट रूप से चालू।", 'st.display.api_mutation_observer.label': "एपीआई उत्परिवर्तन पर्यवेक्षक", 'st.display.api_mutation_observer.desc': "समान-टैब XHR/फ़ेच अनुरोध URL और विधियों का निरीक्षण करें ताकि WebBrain बार-बार होने वाली UI क्रियाओं का पता लगा सके और API शॉर्टकट पैटर्न सुझा सके। डिफ़ॉल्ट रूप से बंद; शॉर्टकट व्यवहार या विलंबता की जांच करते समय ही सक्षम करें।", - 'st.display.openai_ask_streaming.label': "स्ट्रीम OpenAI प्रतिक्रियाएँ पूछें", - 'st.display.openai_ask_streaming.desc': "आस्क मोड में आते ही आधिकारिक OpenAI प्रतिक्रिया टेक्स्ट दिखाएं। टूल कॉल प्रतिक्रिया के लिए प्रतीक्षा करें। पूर्ण; एक्ट, डेव, शेड्यूल्ड, क्लाउड और कंटिन्यू रन नॉन-स्ट्रीमिंग रहते हैं। डिफ़ॉल्ट रूप से चालू.", + 'st.display.openai_ask_streaming.label': "Ask ??? ??? ????? ??????? ????", + 'st.display.openai_ask_streaming.desc': "Ask ??? ??? ??????? ?? ????? ??? ?? ??????? ??? ??? ????? ??????? ????? ?? ????????? ???? ???; Act, Dev, ?????????, ?????? ?? Continue ?? ???? ?????????? ?? ???? ???? ???????? ??? ?? ?????", 'st.display.plan_before_act.label': "अधिनियम से पहले योजना बनाएं", 'st.display.plan_before_act.desc': "एक्ट और डेव हमेशा टूल से पहले एक संरचित इरादे की जांच चलाते हैं। प्रयास (डिफ़ॉल्ट) भी पूर्ण योजनाएँ बनाता है, लेकिन संक्षिप्त अनुवर्ती कार्रवाई के लिए हाल ही में स्वीकृत योजना का पुन: उपयोग कर सकता है; स्ट्रिक्ट हर मोड़ पर एक पूर्ण योजना बनाता है। यदि एक मरम्मत के बाद इरादा या योजना अमान्य रहती है तो प्रयास केवल पढ़ने योग्य मोड़ पर वापस आ जाता है; औजारों से पहले सख्त रोक.", 'st.display.plan_before_act.try': "योजना बनाने का प्रयास करें (डिफ़ॉल्ट)", diff --git a/src/firefox/src/ui/locales/id.js b/src/firefox/src/ui/locales/id.js index cefb08548..bc5ee98a1 100644 --- a/src/firefox/src/ui/locales/id.js +++ b/src/firefox/src/ui/locales/id.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Streaming respons terputus; mencoba kembali giliran Ask ini tanpa streaming.', 'sp.providers.no_setup_group': 'Tanpa penyiapan', 'sp.providers.no_setup': 'Tidak perlu penyiapan', 'sp.providers.active_group': 'Penyedia aktif', @@ -631,8 +632,8 @@ export default { 'st.display.clarify_timeout.instant': 'Instan', 'st.display.api_mutation_observer.label': 'Pengamat mutasi API', 'st.display.api_mutation_observer.desc': 'Amati URL dan metode permintaan XHR/fetch pada tab yang sama sehingga WebBrain dapat mendeteksi tindakan UI berulang dan menyarankan pola pintasan API. Nonaktif secara default; aktifkan hanya saat menyelidiki perilaku pintasan atau latensi.', - 'st.display.openai_ask_streaming.label': 'Streaming respons OpenAI di mode Ask', - 'st.display.openai_ask_streaming.desc': 'Tampilkan teks OpenAI Responses resmi saat tiba di mode Ask. Panggilan alat menunggu response.completed; Act, Dev, proses terjadwal, cloud, dan Continue tetap tanpa streaming. Aktif secara default.', + 'st.display.openai_ask_streaming.label': "Streaming respons dalam mode Ask", + 'st.display.openai_ask_streaming.desc': "Tampilkan respons penyedia saat diterima dalam mode Ask. Panggilan alat menunggu peristiwa akhir stream; proses Act, Dev, terjadwal, cloud, dan Continue tetap tanpa streaming. Aktif secara default.", 'st.display.plan_before_act.label': 'Rencanakan sebelum Bertindak', 'st.display.plan_before_act.desc': 'Mode Bertindak dan Dev selalu menjalankan pemeriksaan niat terstruktur sebelum alat. Coba (default) juga membuat rencana lengkap, tetapi dapat memakai kembali rencana yang baru disetujui untuk tindak lanjut singkat; Ketat membuat rencana lengkap setiap giliran. Coba beralih ke giliran hanya-baca jika niat atau rencana tetap tidak valid setelah satu perbaikan; Ketat berhenti sebelum alat.', 'st.display.plan_before_act.try': 'Coba perencanaan (default)', diff --git a/src/firefox/src/ui/locales/ja.js b/src/firefox/src/ui/locales/ja.js index b5ac6b3f8..67360691c 100644 --- a/src/firefox/src/ui/locales/ja.js +++ b/src/firefox/src/ui/locales/ja.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': '応答ストリームが中断されました。この Ask ターンをストリーミングなしで再試行します。', 'sp.providers.no_setup_group': '設定不要', 'sp.providers.no_setup': '設定なし', 'sp.providers.active_group': '有効なプロバイダー', @@ -631,8 +632,8 @@ export default { 'st.display.clarify_timeout.instant': '即時', 'st.display.api_mutation_observer.label': 'API変更オブザーバー', 'st.display.api_mutation_observer.desc': '同じタブの XHR/fetch リクエスト URL とメソッドを監視し、WebBrain が繰り返しの UI アクションを検出して API ショートカットパターンを提案できるようにします。デフォルトではオフ。ショートカット動作やレイテンシの調査中のみ有効にしてください。', - 'st.display.openai_ask_streaming.label': 'Ask の OpenAI 応答をストリーミング', - 'st.display.openai_ask_streaming.desc': 'Ask モードで公式 OpenAI Responses のテキストを到着と同時に表示します。ツール呼び出しは response.completed を待ち、Act、Dev、スケジュール、クラウド、Continue の実行は非ストリーミングのままです。デフォルトでオンです。', + 'st.display.openai_ask_streaming.label': "Ask ???????????", + 'st.display.openai_ask_streaming.desc': "Ask ??????????????????????????????????????????????????Act?Dev?????????????Continue ?????????????????????????????", 'st.display.plan_before_act.label': '実行前に計画', 'st.display.plan_before_act.desc': 'Act と Dev はツール実行前に必ず構造化された意図確認を行います。試行(デフォルト)は完全な計画も作成しますが、短いフォローアップでは直近に承認された計画を再利用できます。厳格は毎ターン完全な計画を作成します。意図または計画が1回の修復後も無効な場合、試行は読み取り専用ターンに切り替え、厳格はツール実行前に停止します。', 'st.display.plan_before_act.try': '計画を試す(デフォルト)', diff --git a/src/firefox/src/ui/locales/ko.js b/src/firefox/src/ui/locales/ko.js index 3c5e06247..a86573c2c 100644 --- a/src/firefox/src/ui/locales/ko.js +++ b/src/firefox/src/ui/locales/ko.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': '응답 스트리밍이 중단되었습니다. 이 Ask 요청을 스트리밍 없이 다시 시도합니다.', 'sp.providers.no_setup_group': '설정 필요 없음', 'sp.providers.no_setup': '설정 없음', 'sp.providers.active_group': '활성 공급자', @@ -631,8 +632,8 @@ export default { 'st.display.clarify_timeout.instant': '즉시', 'st.display.api_mutation_observer.label': 'API 변경 관찰자', 'st.display.api_mutation_observer.desc': '동일한 탭의 XHR/fetch 요청 URL 및 메서드를 관찰하여 WebBrain이 반복되는 UI 작업을 감지하고 API 바로가기 패턴을 제안할 수 있도록 합니다. 기본적으로 꺼져 있습니다. 바로가기 동작이나 지연 시간을 조사할 때만 활성화하세요.', - 'st.display.openai_ask_streaming.label': 'Ask에서 OpenAI 응답 스트리밍', - 'st.display.openai_ask_streaming.desc': 'Ask 모드에서 공식 OpenAI Responses 텍스트를 도착하는 즉시 표시합니다. 도구 호출은 response.completed를 기다리며 Act, Dev, 예약, 클라우드 및 Continue 실행은 스트리밍하지 않습니다. 기본적으로 켜져 있습니다.', + 'st.display.openai_ask_streaming.label': "Ask ?? ????", + 'st.display.openai_ask_streaming.desc': "Ask ???? ??? ??? ???? ?? ?????. ?? ??? ??? ?? ???? ???? Act, Dev, ??, ???? ? Continue ??? ?????? ????. ????? ?? ????.", 'st.display.plan_before_act.label': '실행 전 계획', 'st.display.plan_before_act.desc': 'Act 및 Dev 모드는 도구 실행 전에 항상 구조화된 의도 확인을 수행합니다. 시도(기본값)는 전체 계획도 만들지만 짧은 후속 요청에서는 최근 승인된 계획을 재사용할 수 있습니다. 엄격 모드는 매 턴 전체 계획을 만듭니다. 의도나 계획이 한 번의 복구 후에도 유효하지 않으면 시도는 읽기 전용 턴으로 전환하고 엄격 모드는 도구 실행 전에 중지합니다.', 'st.display.plan_before_act.try': '계획 시도 (기본값)', diff --git a/src/firefox/src/ui/locales/ms.js b/src/firefox/src/ui/locales/ms.js index 1f101152b..29f87e461 100644 --- a/src/firefox/src/ui/locales/ms.js +++ b/src/firefox/src/ui/locales/ms.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Penstriman respons terganggu; mencuba semula giliran Ask ini tanpa penstriman.', 'sp.providers.no_setup_group': 'Tanpa persediaan', 'sp.providers.no_setup': 'Tiada persediaan diperlukan', 'sp.providers.active_group': 'Penyedia aktif', @@ -631,8 +632,8 @@ export default { 'st.display.clarify_timeout.instant': 'Segera', 'st.display.api_mutation_observer.label': 'Pemerhati mutasi API', 'st.display.api_mutation_observer.desc': 'Perhatikan URL dan metode permintaan XHR/fetch tab yang sama supaya WebBrain dapat mengesan tindakan UI berulang dan mencadangkan corak pintasan API. Dimatikan secara lalai; aktifkan hanya semasa menyiasat tingkah laku pintasan atau kependaman.', - 'st.display.openai_ask_streaming.label': 'Strim respons OpenAI dalam mod Ask', - 'st.display.openai_ask_streaming.desc': 'Paparkan teks OpenAI Responses rasmi sebaik sahaja tiba dalam mod Ask. Panggilan alat menunggu response.completed; Act, Dev, tugas berjadual, awan dan Continue kekal tanpa penstriman. Dihidupkan secara lalai.', + 'st.display.openai_ask_streaming.label': "Strim respons dalam mod Ask", + 'st.display.openai_ask_streaming.desc': "Paparkan respons penyedia sebaik sahaja diterima dalam mod Ask. Panggilan alat menunggu peristiwa akhir strim; tugas Act, Dev, berjadual, awan dan Continue kekal tanpa penstriman. Dihidupkan secara lalai.", 'st.display.plan_before_act.label': 'Rancang sebelum Bertindak', 'st.display.plan_before_act.desc': 'Mod Bertindak dan Dev sentiasa menjalankan semakan niat berstruktur sebelum alatan. Cuba (lalai) turut membina rancangan penuh tetapi boleh menggunakan semula rancangan yang baru diluluskan untuk susulan ringkas; Ketat membina rancangan penuh setiap giliran. Cuba beralih kepada giliran baca sahaja jika niat atau rancangan masih tidak sah selepas satu pembaikan; Ketat berhenti sebelum alatan.', 'st.display.plan_before_act.try': 'Cuba perancangan (lalai)', diff --git a/src/firefox/src/ui/locales/nl.js b/src/firefox/src/ui/locales/nl.js index 9603d7930..21c04680f 100644 --- a/src/firefox/src/ui/locales/nl.js +++ b/src/firefox/src/ui/locales/nl.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'De antwoordstream is onderbroken; deze Ask-beurt wordt opnieuw geprobeerd zonder streaming.', 'sp.providers.no_setup_group': 'Geen configuratie nodig', 'sp.providers.no_setup': 'Geen configuratie', 'sp.providers.active_group': 'Actieve providers', @@ -467,8 +468,8 @@ export default { 'st.display.voice_input.desc': 'Laat de microfoonknop in de chatinvoer tekst dicteren via de spraakherkenning van uw browser...', 'st.display.api_mutation_observer.label': 'API-wijzigingsobserver', 'st.display.api_mutation_observer.desc': 'Observeer XHR/fetch-verzoek-URL\'s en -methoden op hetzelfde tabblad...', - 'st.display.openai_ask_streaming.label': 'Stream OpenAI Antwoord-respondenties', - 'st.display.openai_ask_streaming.desc': 'Toon officiële OpenAI Responses-tekst zodat deze binnenkomt in Vraagmodus...', + 'st.display.openai_ask_streaming.label': 'Ask-antwoorden streamen', + 'st.display.openai_ask_streaming.desc': 'Toon tekst van ondersteunde providers zodra deze binnenkomt in Ask-modus. Onderbroken streams tonen een melding en worden eenmaal opnieuw geprobeerd zonder streaming. Toolaanroepen wachten op het einde van de stream; Act-, Dev-, geplande, cloud- en Continue-runs blijven niet-streamend. Standaard ingeschakeld.', 'st.display.plan_before_act.label': 'Plannen voor Handelen', 'st.display.plan_before_act.desc': 'Handelen en Ontwikkelaar voeren altijd een gestructureerde intentiecontrole uit voordat tools worden gebruikt...', 'st.display.plan_before_act.try': 'Probeer plannen (standaard)', diff --git a/src/firefox/src/ui/locales/pl.js b/src/firefox/src/ui/locales/pl.js index 434e5ad78..55610585e 100644 --- a/src/firefox/src/ui/locales/pl.js +++ b/src/firefox/src/ui/locales/pl.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Strumieniowanie odpowiedzi zostało przerwane; ponawiam tę turę Ask bez strumieniowania.', 'sp.providers.no_setup_group': 'Bez konfiguracji', 'sp.providers.no_setup': 'Konfiguracja nie jest wymagana', 'sp.providers.active_group': 'Aktywni dostawcy', @@ -622,8 +623,8 @@ export default { 'st.display.clarify_timeout.instant': 'Natychmiast', 'st.display.api_mutation_observer.label': 'Obserwator mutacji API', 'st.display.api_mutation_observer.desc': 'Obserwuj URL-e i metody żądań XHR/fetch w tej samej karcie, aby WebBrain mógł wykrywać powtarzające się akcje UI i sugerować wzorce skrótów API. Wyłączone domyślnie; włącz tylko podczas badania zachowania skrótów lub opóźnień.', - 'st.display.openai_ask_streaming.label': 'Strumieniuj odpowiedzi OpenAI w Ask', - 'st.display.openai_ask_streaming.desc': 'Pokazuj tekst oficjalnego OpenAI Responses w miarę napływania w trybie Ask. Wywołania narzędzi czekają na response.completed; Act, Dev, zadania zaplanowane, chmurowe i Continue pozostają bez strumieniowania. Domyślnie włączone.', + 'st.display.openai_ask_streaming.label': "Strumieniuj odpowiedzi w trybie Ask", + 'st.display.openai_ask_streaming.desc': "Pokazuj odpowiedzi dostawcy w miar? nap?ywania w trybie Ask. Wywo?ania narz?dzi czekaj? na ko?cowe zdarzenie strumienia; Act, Dev, zadania zaplanowane, chmurowe i Continue pozostaj? bez strumieniowania. Domy?lnie w??czone.", 'st.display.plan_before_act.label': 'Planuj przed działaniem', 'st.display.plan_before_act.desc': 'Tryby Działaj i Dev zawsze wykonują ustrukturyzowaną kontrolę intencji przed użyciem narzędzi. Próba (domyślnie) tworzy też pełne plany, ale przy krótkiej kontynuacji może ponownie użyć niedawno zatwierdzonego planu; tryb Ścisły tworzy pełny plan w każdej turze. Jeśli intencja lub plan nadal są nieprawidłowe po jednej naprawie, Próba przechodzi do tury tylko do odczytu, a tryb Ścisły zatrzymuje się przed narzędziami.', 'st.display.plan_before_act.try': 'Spróbuj planowania (domyślnie)', diff --git a/src/firefox/src/ui/locales/pt.js b/src/firefox/src/ui/locales/pt.js index da70193e5..7370a0fe6 100644 --- a/src/firefox/src/ui/locales/pt.js +++ b/src/firefox/src/ui/locales/pt.js @@ -1,5 +1,6 @@ // Portuguese — translated from the canonical English locale. export default { + 'sp.streaming.fallback': 'A transmissão da resposta foi interrompida; tentando novamente esta interação Ask sem transmissão.', 'sp.providers.no_setup_group': "Nenhuma configuração necessária", 'sp.providers.no_setup': "Sem configuração", 'sp.providers.active_group': "Provedores ativos", @@ -490,8 +491,8 @@ export default { 'st.display.voice_input.desc': "Deixe o botão do microfone na entrada do bate-papo ditar o texto por meio do reconhecimento de fala do seu navegador. Ativado por padrão em navegadores compatíveis.", 'st.display.api_mutation_observer.label': "Observador de mutação de API", 'st.display.api_mutation_observer.desc': "Observe URLs e métodos de solicitação de busca/XHR na mesma guia para que WebBrain possa detectar ações repetidas da interface do usuário e sugerir padrões de atalho de API. Desativado por padrão; habilite apenas ao investigar o comportamento ou a latência do atalho.", - 'st.display.openai_ask_streaming.label': "Stream OpenAI Perguntar respostas", - 'st.display.openai_ask_streaming.desc': "Mostre o texto oficial das respostas OpenAI assim que chegar no modo Perguntar. As chamadas de ferramenta aguardam resposta.completa; As execuções Act, Dev, Scheduled, Cloud e Continue permanecem sem streaming. Ativado por padrão.", + 'st.display.openai_ask_streaming.label': "Transmitir respostas no modo Ask", + 'st.display.openai_ask_streaming.desc': "Mostre as respostas do provedor assim que chegarem no modo Ask. As chamadas de ferramenta aguardam um evento final do fluxo; execu??es Act, Dev, agendadas, na nuvem e Continue permanecem sem streaming. Ativado por padr?o.", 'st.display.plan_before_act.label': "Planeje antes de agir", 'st.display.plan_before_act.desc': "Act e Dev sempre executam uma verificação de intenção estruturada antes das ferramentas. Try (padrão) também cria planos completos, mas pode reutilizar um plano recentemente aprovado para um breve acompanhamento; Strict constrói um plano completo a cada passo. Tente voltar para uma curva somente leitura se a intenção ou o planejamento permanecerem inválidos após um reparo; Paradas rigorosas antes das ferramentas.", 'st.display.plan_before_act.try': "Tente planejar (padrão)", diff --git a/src/firefox/src/ui/locales/ru.js b/src/firefox/src/ui/locales/ru.js index edaeabaa2..413e891d9 100644 --- a/src/firefox/src/ui/locales/ru.js +++ b/src/firefox/src/ui/locales/ru.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Поток ответа был прерван; этот запрос Ask повторяется без потоковой передачи.', 'sp.providers.no_setup_group': 'Без настройки', 'sp.providers.no_setup': 'Настройка не требуется', 'sp.providers.active_group': 'Активные провайдеры', @@ -631,8 +632,8 @@ export default { 'st.display.clarify_timeout.instant': 'Сразу', 'st.display.api_mutation_observer.label': 'Наблюдатель мутаций API', 'st.display.api_mutation_observer.desc': 'Наблюдайте за URL-адресами и методами запросов XHR/fetch на той же вкладке, чтобы WebBrain мог обнаруживать повторяющиеся действия UI и предлагать шаблоны API-шорткатов. Отключено по умолчанию; включайте только при исследовании поведения шорткатов или задержек.', - 'st.display.openai_ask_streaming.label': 'Потоковые ответы OpenAI в Ask', - 'st.display.openai_ask_streaming.desc': 'Показывать текст официального OpenAI Responses по мере поступления в режиме Ask. Вызовы инструментов ждут response.completed; Act, Dev, запланированные, облачные и Continue-запуски остаются без потоковой передачи. Включено по умолчанию.', + 'st.display.openai_ask_streaming.label': "????????? ?????? ? ?????? Ask", + 'st.display.openai_ask_streaming.desc': "?????????? ?????? ?????????? ?? ???? ??????????? ? ?????? Ask. ?????? ???????????? ???? ???????????? ??????? ??????; Act, Dev, ???????????????, ???????? ? Continue-??????? ???????? ??? ????????? ????????. ???????? ?? ?????????.", 'st.display.plan_before_act.label': 'Планировать перед действием', 'st.display.plan_before_act.desc': 'Режимы Действия и Dev всегда выполняют структурированную проверку намерения перед запуском инструментов. Попытка (по умолчанию) также строит полные планы, но для короткого продолжения может повторно использовать недавно одобренный план; Строгий режим строит полный план на каждом ходу. Если намерение или план остаются недействительными после одной попытки исправления, Попытка переходит в режим только для чтения, а Строгий режим останавливается до запуска инструментов.', 'st.display.plan_before_act.try': 'Попробовать планирование (по умолчанию)', diff --git a/src/firefox/src/ui/locales/th.js b/src/firefox/src/ui/locales/th.js index 9aecc5f3d..1e7b923b2 100644 --- a/src/firefox/src/ui/locales/th.js +++ b/src/firefox/src/ui/locales/th.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'การสตรีมคำตอบถูกขัดจังหวะ กำลังลอง Ask รอบนี้อีกครั้งโดยไม่ใช้สตรีม', 'sp.providers.no_setup_group': 'ไม่ต้องตั้งค่า', 'sp.providers.no_setup': 'ไม่ต้องตั้งค่า', 'sp.providers.active_group': 'ผู้ให้บริการที่ใช้งานอยู่', @@ -631,8 +632,8 @@ export default { 'st.display.clarify_timeout.instant': 'ทันที', 'st.display.api_mutation_observer.label': 'ตัวสังเกตการกลายพันธุ์ของ API', 'st.display.api_mutation_observer.desc': 'สังเกต URL และวิธีการของคำขอ XHR/fetch ในแท็บเดียวกัน เพื่อให้ WebBrain ตรวจจับการกระทำ UI ที่ซ้ำและแนะนำรูปแบบทางลัด API ปิดโดยค่าเริ่มต้น เปิดใช้งานเฉพาะเมื่อตรวจสอบพฤติกรรมทางลัดหรือความหน่วง', - 'st.display.openai_ask_streaming.label': 'สตรีมคำตอบ OpenAI ในโหมด Ask', - 'st.display.openai_ask_streaming.desc': 'แสดงข้อความจาก OpenAI Responses อย่างเป็นทางการทันทีที่มาถึงในโหมด Ask การเรียกเครื่องมือจะรอ response.completed ส่วน Act, Dev, งานตามกำหนดเวลา งานคลาวด์ และ Continue จะยังไม่สตรีม เปิดโดยค่าเริ่มต้น', + 'st.display.openai_ask_streaming.label': "???????????????? Ask", + 'st.display.openai_ask_streaming.desc': "??????????????????????????????????????????? Ask ??????????????????????????????????????????? ???? Act, Dev, ??????????????? ????????? ??? Continue ????????????? ??????????????????", 'st.display.plan_before_act.label': 'วางแผนก่อนดำเนินการ', 'st.display.plan_before_act.desc': 'โหมดดำเนินการและ Dev จะตรวจสอบเจตนาแบบมีโครงสร้างก่อนใช้เครื่องมือเสมอ โหมดลอง (ค่าเริ่มต้น) จะสร้างแผนฉบับเต็มด้วย แต่อาจใช้แผนที่เพิ่งอนุมัติซ้ำสำหรับคำขอต่อเนื่องสั้น ๆ ส่วนโหมดเข้มงวดจะสร้างแผนฉบับเต็มทุกครั้ง หากเจตนาหรือแผนยังไม่ถูกต้องหลังซ่อมหนึ่งครั้ง โหมดลองจะเปลี่ยนเป็นเทิร์นอ่านอย่างเดียว ส่วนโหมดเข้มงวดจะหยุดก่อนใช้เครื่องมือ', 'st.display.plan_before_act.try': 'ลองวางแผน (ค่าเริ่มต้น)', diff --git a/src/firefox/src/ui/locales/tl.js b/src/firefox/src/ui/locales/tl.js index 33f71fdee..502c362dd 100644 --- a/src/firefox/src/ui/locales/tl.js +++ b/src/firefox/src/ui/locales/tl.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Naputol ang pag-stream ng tugon; sinusubukang muli ang Ask turn na ito nang walang streaming.', 'sp.providers.no_setup_group': 'Walang setup', 'sp.providers.no_setup': 'Hindi kailangan ng setup', 'sp.providers.active_group': 'Mga aktibong provider', @@ -631,8 +632,8 @@ export default { 'st.display.clarify_timeout.instant': 'Agad', 'st.display.api_mutation_observer.label': 'Tagamasid ng mutasyon ng API', 'st.display.api_mutation_observer.desc': 'Obserbahan ang mga URL at paraan ng XHR/fetch request sa parehong tab upang matukoy ng WebBrain ang mga paulit-ulit na aksyon sa UI at magmungkahi ng mga pattern ng shortcut sa API. Naka-off bilang default; paganahin lamang habang iniimbestigahan ang pag-uugali ng shortcut o latency.', - 'st.display.openai_ask_streaming.label': 'I-stream ang mga sagot ng OpenAI sa Ask', - 'st.display.openai_ask_streaming.desc': 'Ipakita ang opisyal na OpenAI Responses text habang dumarating sa Ask mode. Maghihintay ang mga tool call sa response.completed; mananatiling hindi naka-stream ang Act, Dev, scheduled, cloud, at Continue runs. Naka-on bilang default.', + 'st.display.openai_ask_streaming.label': "I-stream ang mga sagot sa Ask mode", + 'st.display.openai_ask_streaming.desc': "Ipakita ang mga sagot ng provider habang dumarating sa Ask mode. Naghihintay ang mga tool call sa pangwakas na stream event; mananatiling hindi naka-stream ang Act, Dev, scheduled, cloud, at Continue runs. Naka-on bilang default.", 'st.display.plan_before_act.label': 'Magplano bago Kumilos', 'st.display.plan_before_act.desc': 'Palaging nagsasagawa ang mga mode na Kumilos at Dev ng nakaayos na pagsusuri ng layunin bago gumamit ng mga tool. Gumagawa rin ng buong plano ang Subukan (default), ngunit maaari nitong gamitin muli ang kamakailang inaprubahang plano para sa maikling follow-up; gumagawa ng buong plano ang Mahigpit sa bawat turno. Kung hindi pa rin valid ang layunin o plano matapos ang isang pag-aayos, lilipat ang Subukan sa read-only na turn at hihinto ang Mahigpit bago gumamit ng mga tool.', 'st.display.plan_before_act.try': 'Subukan ang pagpaplano (default)', diff --git a/src/firefox/src/ui/locales/tr.js b/src/firefox/src/ui/locales/tr.js index 96dbab13b..8302cdb89 100644 --- a/src/firefox/src/ui/locales/tr.js +++ b/src/firefox/src/ui/locales/tr.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Yanıt akışı kesildi; bu Ask turu akış olmadan yeniden deneniyor.', 'sp.providers.no_setup_group': 'Kurulum gerektirmez', 'sp.providers.no_setup': 'Kurulum yok', 'sp.providers.active_group': 'Etkin sağlayıcılar', @@ -637,7 +638,7 @@ export default { 'st.display.api_mutation_observer.label': 'API mutasyon gözlemcisi', 'st.display.api_mutation_observer.desc': 'WebBrain\'in tekrarlanan UI eylemlerini tespit etmesi ve API kısayol kalıpları önermesi için aynı sekmedeki XHR/fetch istek URL\'lerini ve yöntemlerini gözlemle. Varsayılan olarak kapalı; yalnızca kısayol davranışını veya gecikmeyi araştırırken etkinleştir.', 'st.display.openai_ask_streaming.label': 'Ask yanıtlarını akışla', - 'st.display.openai_ask_streaming.desc': 'Desteklenen sağlayıcılarda Ask metnini geldikçe göster. Kesilen akış aynı turda sessizce ve akışsız olarak bir kez yeniden denenir; sağlayıcı/API hataları yine gösterilir. Araç çağrıları akış tamamlanana kadar bekler; Act, Dev, zamanlanmış, bulut ve Continue çalıştırmaları akışsız kalır. Varsayılan olarak açık.', + 'st.display.openai_ask_streaming.desc': 'Desteklenen sağlayıcılarda Ask metnini geldikçe göster. Kesilen akış bir bildirim gösterir ve aynı turu akışsız olarak bir kez yeniden dener; sağlayıcı/API hataları yine gösterilir. Araç çağrıları akış tamamlanana kadar bekler; Act, Dev, zamanlanmış, bulut ve Continue çalıştırmaları akışsız kalır. Varsayılan olarak açık.', 'st.display.plan_before_act.label': 'Eylemden önce planla', 'st.display.plan_before_act.desc': 'Aktif ve Dev modları araçlardan önce her zaman yapılandırılmış bir niyet kontrolü çalıştırır. Dene (varsayılan) ayrıca tam planlar oluşturur ancak kısa bir takipte yakın zamanda onaylanmış planı yeniden kullanabilir; Katı her turda tam plan oluşturur. Niyet veya planlama bir onarımdan sonra hâlâ geçersizse Dene salt okunur bir tura geçer; Katı araçlardan önce durur.', 'st.display.plan_before_act.try': 'Planlamayı dene (varsayılan)', diff --git a/src/firefox/src/ui/locales/uk.js b/src/firefox/src/ui/locales/uk.js index a129f527b..75f61295a 100644 --- a/src/firefox/src/ui/locales/uk.js +++ b/src/firefox/src/ui/locales/uk.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': 'Потік відповіді перервано; цей запит Ask повторюється без потокової передачі.', 'sp.providers.no_setup_group': 'Без налаштування', 'sp.providers.no_setup': 'Налаштування не потрібне', 'sp.providers.active_group': 'Активні провайдери', @@ -631,8 +632,8 @@ export default { 'st.display.clarify_timeout.instant': 'Миттєво', 'st.display.api_mutation_observer.label': 'Спостерігач мутацій API', 'st.display.api_mutation_observer.desc': 'Спостерігайте за URL-адресами та методами запитів XHR/fetch на тій самій вкладці, щоб WebBrain міг виявляти повторювані дії інтерфейсу та пропонувати шаблони API-скорочень. Вимкнено за замовчуванням; вмикайте лише під час дослідження поведінки скорочень або затримки.', - 'st.display.openai_ask_streaming.label': 'Потокові відповіді OpenAI в Ask', - 'st.display.openai_ask_streaming.desc': 'Показувати текст офіційного OpenAI Responses у міру надходження в режимі Ask. Виклики інструментів чекають на response.completed; Act, Dev, заплановані, хмарні та Continue-запуски залишаються без потокової передачі. Увімкнено за замовчуванням.', + 'st.display.openai_ask_streaming.label': "???????? ????????? ? ?????? Ask", + 'st.display.openai_ask_streaming.desc': "?????????? ????????? ?????????? ? ???? ??????????? ? ?????? Ask. ??????? ???????????? ??????? ?? ??????????? ????? ??????; Act, Dev, ???????????, ?????? ?? Continue-??????? ??????????? ??? ????????? ????????. ????????? ?? ?????????????.", 'st.display.plan_before_act.label': 'Планувати перед дією', 'st.display.plan_before_act.desc': 'Режими Дії та Dev завжди виконують структуровану перевірку наміру перед запуском інструментів. Спроба (типово) також створює повні плани, але для короткого продовження може повторно використати нещодавно схвалений план; Суворий режим створює повний план на кожному кроці. Якщо намір або план лишаються недійсними після одного виправлення, Спроба переходить у режим лише для читання, а Суворий режим зупиняється до запуску інструментів.', 'st.display.plan_before_act.try': 'Спробувати планування (за замовчуванням)', diff --git a/src/firefox/src/ui/locales/vi.js b/src/firefox/src/ui/locales/vi.js index dc0f7d3c5..835ced489 100644 --- a/src/firefox/src/ui/locales/vi.js +++ b/src/firefox/src/ui/locales/vi.js @@ -1,5 +1,6 @@ // Vietnamese — translated from the canonical English locale. export default { + 'sp.streaming.fallback': 'Luồng phản hồi bị gián đoạn; đang thử lại lượt Ask này mà không phát trực tuyến.', 'sp.providers.no_setup_group': "Không cần thiết lập", 'sp.providers.no_setup': "Không cần thiết lập", 'sp.providers.active_group': "Nhà cung cấp đang hoạt động", @@ -490,8 +491,8 @@ export default { 'st.display.voice_input.desc': "Để nút micrô trong đầu vào trò chuyện đọc chính tả văn bản thông qua tính năng nhận dạng giọng nói của trình duyệt. Bật theo mặc định trong các trình duyệt hỗ trợ nó.", 'st.display.api_mutation_observer.label': "Người quan sát đột biến API", 'st.display.api_mutation_observer.desc': "Quan sát các URL và phương thức yêu cầu XHR/tìm nạp cùng một tab để WebBrain có thể phát hiện các hành động giao diện người dùng lặp lại và đề xuất các mẫu phím tắt API. Tắt theo mặc định; chỉ bật trong khi điều tra hành vi hoặc độ trễ của phím tắt.", - 'st.display.openai_ask_streaming.label': "Truyền trực tuyến OpenAI Hỏi câu trả lời", - 'st.display.openai_ask_streaming.desc': "Hiển thị văn bản Phản hồi OpenAI chính thức khi nó đến ở chế độ Hỏi. Cuộc gọi công cụ chờ phản hồi.completed; Các hoạt động Hành động, Nhà phát triển, đã lên lịch, đám mây và Tiếp tục vẫn không phát trực tuyến. Bật theo mặc định.", + 'st.display.openai_ask_streaming.label': "Truy?n tr?c tuy?n c?u tr? l?i ? ch? ?? Ask", + 'st.display.openai_ask_streaming.desc': "Hi?n th? c?u tr? l?i c?a nh? cung c?p ngay khi nh?n ???c trong ch? ?? Ask. L?nh g?i c?ng c? ch? s? ki?n k?t th?c lu?ng; c?c l?n ch?y Act, Dev, theo l?ch, ??m m?y v? Continue v?n kh?ng ph?t tr?c tuy?n. B?t theo m?c ??nh.", 'st.display.plan_before_act.label': "Lập kế hoạch trước khi hành động", 'st.display.plan_before_act.desc': "Act và Dev luôn tiến hành kiểm tra ý định có cấu trúc trước các công cụ. Try (mặc định) cũng xây dựng các kế hoạch đầy đủ nhưng có thể sử dụng lại kế hoạch đã được phê duyệt gần đây để theo dõi trong thời gian ngắn; Strict xây dựng một kế hoạch đầy đủ mỗi lượt. Thử quay lại chế độ chỉ đọc nếu ý định hoặc kế hoạch vẫn không hợp lệ sau một lần sửa chữa; Dừng lại nghiêm ngặt trước các công cụ.", 'st.display.plan_before_act.try': "Hãy thử lập kế hoạch (mặc định)", diff --git a/src/firefox/src/ui/locales/zh.js b/src/firefox/src/ui/locales/zh.js index 51b051e10..fc4b93e87 100644 --- a/src/firefox/src/ui/locales/zh.js +++ b/src/firefox/src/ui/locales/zh.js @@ -3,6 +3,7 @@ import chromeWebStoreLocale from './chrome-web-store.mjs'; export default { ...chromeWebStoreLocale, + 'sp.streaming.fallback': '响应流已中断;正在以非流式方式重试本次 Ask。', 'sp.providers.no_setup_group': '无需配置', 'sp.providers.no_setup': '无需设置', 'sp.providers.active_group': '已启用的提供商', @@ -631,8 +632,8 @@ export default { 'st.display.clarify_timeout.instant': '立即', 'st.display.api_mutation_observer.label': 'API 变更观察器', 'st.display.api_mutation_observer.desc': '观察同标签页中的 XHR/fetch 请求 URL 和方法,以便 WebBrain 可以检测重复的界面操作并建议 API 快捷模式。默认关闭;仅在调查快捷行为或延迟时启用。', - 'st.display.openai_ask_streaming.label': '在 Ask 模式流式显示 OpenAI 回复', - 'st.display.openai_ask_streaming.desc': '在 Ask 模式中随到随显官方 OpenAI Responses 文本。工具调用会等待 response.completed;Act、Dev、计划、云端和 Continue 运行仍不使用流式传输。默认开启。', + 'st.display.openai_ask_streaming.label': "? Ask ????????", + 'st.display.openai_ask_streaming.desc': "? Ask ???????????????????????????Act?Dev??????? Continue ????????????????", 'st.display.plan_before_act.label': '在执行前规划', 'st.display.plan_before_act.desc': '操作和 Dev 模式在使用工具前始终执行结构化意图检查。尝试(默认)还会生成完整计划,但在简短跟进中可复用最近批准的计划;严格模式每轮都生成完整计划。如果意图或计划在一次修复后仍无效,尝试模式会切换为只读轮次;严格模式会在使用工具前停止。', 'st.display.plan_before_act.try': '尝试规划(默认)', diff --git a/src/firefox/src/ui/provider-icons.js b/src/firefox/src/ui/provider-icons.js index c097fa641..a40ac795c 100644 --- a/src/firefox/src/ui/provider-icons.js +++ b/src/firefox/src/ui/provider-icons.js @@ -5,6 +5,10 @@ * marks for brands Lobe does not ship). See icons/providers/SOURCES.md. * Unknown ids return empty so we never invent monograms. */ +import { + ADDITIONAL_PROVIDER_DEFAULTS, + ADDITIONAL_PROVIDER_IDS, +} from '../providers/provider-catalog.js'; export const PROVIDER_ICON_FILES = { webbrain_cloud: 'webbrain_cloud.png', @@ -34,6 +38,7 @@ export const PROVIDER_ICON_FILES = { huggingface: 'huggingface.svg', fireworks: 'fireworks.svg', z_ai: 'z_ai.svg', + ...Object.fromEntries(ADDITIONAL_PROVIDER_IDS.map((id) => [id, `${id}.svg`])), }; export function providerIconUrl(id) { @@ -97,6 +102,10 @@ export const PROVIDER_SHORT_LABELS = { huggingface: 'Hugging Face', fireworks: 'Fireworks', z_ai: 'z.ai GLM', + ...Object.fromEntries(ADDITIONAL_PROVIDER_IDS.map((id) => [ + id, + ADDITIONAL_PROVIDER_DEFAULTS[id].label, + ])), }; /** Hostname equals domain or is a subdomain of it (avoids substring spoofing). */ diff --git a/src/firefox/src/ui/settings.js b/src/firefox/src/ui/settings.js index c7d337600..d0e048d35 100644 --- a/src/firefox/src/ui/settings.js +++ b/src/firefox/src/ui/settings.js @@ -43,6 +43,7 @@ import { PROVIDER_SHORT_LABELS, sniffProviderIdFromBaseUrl, } from './provider-icons.js'; +import { ADDITIONAL_PROVIDER_UI } from '../providers/provider-catalog.js'; // Version shown in the subtitle. Kept here so it only needs one update per // release; the subtitle string itself is translated. @@ -2132,6 +2133,7 @@ function renderProviders() { fields: [ { key: 'apiKey', labelKey: 'st.provider.field.api_key', type: 'password', placeholder: 'API token' }, { key: 'accountId', label: 'Cloudflare Account ID', type: 'text', placeholder: '0123456789abcdef0123456789abcdef' }, + { key: 'gatewayId', label: 'AI Gateway ID (optional; @cf defaults to default)', type: 'text', placeholder: 'my-gateway' }, { key: 'model', labelKey: 'st.provider.field.model', type: 'text', placeholder: '@cf/zai-org/glm-5.2', suggestions: ['@cf/zai-org/glm-5.2'] }, { key: 'baseUrl', labelKey: 'st.provider.field.api_base_url', type: 'text', placeholder: 'https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/v1' }, @@ -2236,6 +2238,50 @@ function renderProviders() { }; // Filter pill row above the providers list. + // Additional providers share a predictable OpenAI-compatible settings + // shape. Provider-specific suggestions/placeholders stay in the catalog; + // UI-only metadata is never persisted with credentials. + for (const [id, meta] of Object.entries(ADDITIONAL_PROVIDER_UI)) { + const config = providersData[id] || {}; + const fields = [ + { + key: 'apiKey', + labelKey: 'st.provider.field.api_key', + type: 'password', + placeholder: meta.apiKeyPlaceholder || 'API key', + }, + ]; + if (id === 'azure-cognitive-services') { + fields.push({ key: 'resource', label: 'Azure resource name', type: 'text', placeholder: 'my-resource' }); + } + if (id === 'google-vertex' || id === 'google-vertex-anthropic') { + fields.push( + { key: 'project', label: 'Google Cloud project ID', type: 'text', placeholder: 'my-project' }, + { key: 'location', label: 'Google Cloud location', type: 'text', placeholder: id === 'google-vertex' ? 'us-central1' : 'us-east5' }, + ); + } + fields.push( + { + key: 'model', + labelKey: 'st.provider.field.model', + type: 'text', + placeholder: config.model || (id === 'azure-cognitive-services' ? 'deployed-model-name' : 'model-id'), + suggestions: meta.suggestions || [], + }, + { + key: 'baseUrl', + labelKey: 'st.provider.field.api_base_url', + type: 'text', + placeholder: config.baseUrl || 'https://provider.example/v1', + }, + CONTEXT_WINDOW_FIELD, + { key: 'supportsVision', labelKey: 'st.provider.field.supports_vision', type: 'checkbox' }, + ); + if (config.category === 'router' || config.category === 'local') fields.push(PROMPT_TIER_FIELD); + fields.push(...COST_ESTIMATE_FIELDS); + providerConfigs[id] = { fields }; + } + providersContainer.appendChild(renderProviderFilterBar()); let entries = Object.entries(providersData); diff --git a/src/firefox/src/ui/sidepanel.js b/src/firefox/src/ui/sidepanel.js index f0c34fc05..f471df32d 100644 --- a/src/firefox/src/ui/sidepanel.js +++ b/src/firefox/src/ui/sidepanel.js @@ -6517,6 +6517,9 @@ function handleAgentUpdateMessage(msg) { case 'warning': hideActivity(); + if (data?.code === 'ask_stream_fallback') { + showComposerToast(t('sp.streaming.fallback'), { duration: 6000 }); + } break; case 'run_complete': diff --git a/test/run.js b/test/run.js index 45201aed0..69c7e143d 100644 --- a/test/run.js +++ b/test/run.js @@ -529,6 +529,12 @@ const { ProviderManager: ProviderManagerCh } = await import( const { ProviderManager: ProviderManagerFx } = await import( 'file://' + path.join(ROOT, 'src/firefox/src/providers/manager.js').replace(/\\/g, '/') ); +const ProviderCatalogCh = await import( + 'file://' + path.join(ROOT, 'src/chrome/src/providers/provider-catalog.js').replace(/\\/g, '/') +); +const ProviderCatalogFx = await import( + 'file://' + path.join(ROOT, 'src/firefox/src/providers/provider-catalog.js').replace(/\\/g, '/') +); const { inferContextWindow: inferContextWindowCh, normalizeDetectedContextWindow: normalizeDetectedContextWindowCh, @@ -583,6 +589,12 @@ const { AzureOpenAIProvider: AzureOpenAIProviderCh } = await import( const { AzureOpenAIProvider: AzureOpenAIProviderFx } = await import( 'file://' + path.join(ROOT, 'src/firefox/src/providers/azure-openai.js').replace(/\\/g, '/') ); +const { VertexAnthropicProvider: VertexAnthropicProviderCh } = await import( + 'file://' + path.join(ROOT, 'src/chrome/src/providers/vertex-anthropic.js').replace(/\\/g, '/') +); +const { VertexAnthropicProvider: VertexAnthropicProviderFx } = await import( + 'file://' + path.join(ROOT, 'src/firefox/src/providers/vertex-anthropic.js').replace(/\\/g, '/') +); const ProviderCompatibilityCh = await import( 'file://' + path.join(ROOT, 'src/chrome/src/providers/provider-compatibility.js').replace(/\\/g, '/') ); @@ -25822,6 +25834,262 @@ test('_defaultConfigs: every entry carries an explicit category', () => { } }); +test('extended provider catalog is complete, mirrored, safe, and excluded-provider clean', async () => { + const expectedIds = ` + 302ai abacus aihubmix alibaba-coding-plan alibaba-coding-plan-cn + azure-cognitive-services bailing baseten berget cerebras chutes clarifai + cloudferro-sherlock cohere cortecs deepinfra digitalocean dinference drun + evroc fastrouter friendli google-vertex google-vertex-anthropic helicone + iflowcn inception inference io-net jiekou kilo kimi-for-coding + kuae-cloud-coding-plan llama lucidquery meganova minimax-cn-coding-plan + minimax-coding-plan moark modelscope morph nano-gpt nebius nova novita-ai + ollama-cloud opencode opencode-go ovhcloud perplexity perplexity-agent poe + privatemode-ai qihang-ai qiniu-ai requesty scaleway siliconflow + siliconflow-cn stackit stepfun submodel synthetic tencent-coding-plan + upstage v0 venice vercel vivgrid vultr wandb xiaomi zai-coding-plan zenmux + zhipuai zhipuai-coding-plan + `.trim().split(/\s+/); + const excluded = ['github-models', 'github-copilot', 'gitlab', 'sap-ai-core']; + + assert.equal(expectedIds.length, 76); + assert.deepEqual(ProviderCatalogCh.ADDITIONAL_PROVIDER_IDS, expectedIds); + assert.deepEqual(ProviderCatalogFx.ADDITIONAL_PROVIDER_IDS, expectedIds); + assert.deepEqual( + ProviderCatalogFx.ADDITIONAL_PROVIDER_DEFAULTS, + ProviderCatalogCh.ADDITIONAL_PROVIDER_DEFAULTS, + 'Chrome and Firefox provider catalogs must stay identical', + ); + + for (const [label, PM, prefix] of [ + ['chrome', ProviderManagerCh, 'src/chrome'], + ['firefox', ProviderManagerFx, 'src/firefox'], + ]) { + const defaults = new PM()._defaultConfigs(); + assert.equal(Object.keys(defaults).length, 103, `${label}: expected 27 original + 76 new providers`); + for (const id of expectedIds) { + const config = defaults[id]; + assert.ok(config, `${label}: missing ${id}`); + assert.equal(config.enabled, false, `${label}: ${id} must start disabled`); + assert.ok(config.label && config.type && config.category && config.baseUrl, `${label}: ${id} metadata incomplete`); + const expectedAskStreaming = !['alibaba-coding-plan', 'alibaba-coding-plan-cn'].includes(id); + assert.equal( + config.supportsAskStreaming, + expectedAskStreaming, + `${label}: ${id} Ask streaming capability mismatch`, + ); + assert.ok(config.model || id === 'azure-cognitive-services', `${label}: ${id} missing model`); + + const icon = path.join(ROOT, prefix, 'icons/providers', `${id}.svg`); + assert.equal(fs.existsSync(icon), true, `${label}: missing icon for ${id}`); + const svg = fs.readFileSync(icon, 'utf8'); + assert.match(svg, / file.endsWith('.js'))) { + const localeSource = fs.readFileSync(path.join(localeDir, localeFile), 'utf8'); + assert.match(localeSource, /'sp\.streaming\.fallback':/, `${label}: ${localeFile} missing localized Ask stream fallback`); + } + const sidepanel = fs.readFileSync(path.join(ROOT, prefix, 'src/ui/sidepanel.js'), 'utf8'); + assert.match( + sidepanel, + /data\?\.code === 'ask_stream_fallback'[\s\S]*showComposerToast\(t\('sp\.streaming\.fallback'\)/, + `${label}: stream fallback warning should be visible and localized`, + ); + } + + assert.equal(ProviderCatalogCh.ADDITIONAL_PROVIDER_DEFAULTS.morph.supportsTools, false); + assert.equal(ProviderCatalogCh.ADDITIONAL_PROVIDER_DEFAULTS.perplexity.supportsTools, false); + assert.equal(ProviderCatalogCh.ADDITIONAL_PROVIDER_DEFAULTS['perplexity-agent'].apiFormat, 'responses'); + assert.equal(ProviderCatalogCh.ADDITIONAL_PROVIDER_DEFAULTS['azure-cognitive-services'].model, ''); + assert.equal(ProviderCatalogCh.ADDITIONAL_PROVIDER_DEFAULTS['kimi-for-coding'].model, 'kimi-for-coding'); + assert.deepEqual( + ProviderCatalogCh.ADDITIONAL_PROVIDER_UI['kimi-for-coding'].suggestions, + ['kimi-for-coding', 'kimi-for-coding-highspeed', 'k3'], + ); +}); + +test('new provider auth, endpoint, protocol, and capability contracts are deterministic', () => { + for (const [label, OpenAIProvider, VertexProvider, PM] of [ + ['chrome', OpenAIProviderCh, VertexAnthropicProviderCh, ProviderManagerCh], + ['firefox', OpenAIProviderFx, VertexAnthropicProviderFx, ProviderManagerFx], + ]) { + const bearer = new OpenAIProvider({ providerName: 'deepinfra', apiKey: 'secret' }); + assert.equal(bearer._headers().Authorization, 'Bearer secret', `${label}: default auth should be bearer`); + + const vertex = new OpenAIProvider({ + providerName: 'google-vertex', + baseUrl: 'https://{vertex_endpoint}/v1/projects/{project}/locations/{location}/endpoints/openapi', + project: 'sample-project', + location: 'us-central1', + apiKey: 'google-key', + apiKeyHeader: 'x-goog-api-key', + }); + assert.equal( + vertex.baseUrl, + 'https://us-central1-aiplatform.googleapis.com/v1/projects/sample-project/locations/us-central1/endpoints/openapi', + `${label}: Vertex endpoint interpolation mismatch`, + ); + assert.equal(vertex._headers()['x-goog-api-key'], 'google-key'); + assert.equal(vertex._headers().Authorization, undefined); + + const globalVertex = new OpenAIProvider({ + providerName: 'google-vertex', + baseUrl: 'https://{vertex_endpoint}/v1/projects/{project}/locations/{location}/endpoints/openapi', + project: 'sample-project', + location: 'global', + apiKey: 'google-key', + apiKeyHeader: 'x-goog-api-key', + }); + assert.equal( + globalVertex.baseUrl, + 'https://aiplatform.googleapis.com/v1/projects/sample-project/locations/global/endpoints/openapi', + `${label}: Vertex global location must use the global endpoint host`, + ); + + const azure = new OpenAIProvider({ + providerName: 'azure-cognitive-services', + baseUrl: 'https://{resource}.openai.azure.com/openai/v1', + resource: 'sample-resource', + apiKey: 'azure-key', + apiKeyHeader: 'api-key', + }); + assert.equal(azure.baseUrl, 'https://sample-resource.openai.azure.com/openai/v1'); + assert.equal(azure._headers()['api-key'], 'azure-key'); + assert.equal(azure._headers().Authorization, undefined); + + const cloudflare = new OpenAIProvider({ + providerName: 'cloudflare', + baseUrl: 'https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/v1', + accountId: '0123456789abcdef0123456789abcdef', + gatewayId: 'my-gateway', + apiKey: 'cf-token', + }); + assert.match(cloudflare.baseUrl, /accounts\/0123456789abcdef0123456789abcdef\/ai\/v1$/); + assert.equal(cloudflare._headers()['cf-aig-gateway-id'], 'my-gateway'); + + const cloudflareDefaultGateway = new OpenAIProvider({ + providerName: 'cloudflare', + model: '@cf/moonshotai/kimi-k2.6', + }); + assert.equal( + cloudflareDefaultGateway._headers()['cf-aig-gateway-id'], + 'default', + `${label}: Workers AI models require a gateway header`, + ); + const cloudflareThirdParty = new OpenAIProvider({ + providerName: 'cloudflare', + model: 'anthropic/claude-sonnet-4', + }); + assert.equal( + cloudflareThirdParty._headers()['cf-aig-gateway-id'], + undefined, + `${label}: third-party models may use Cloudflare's implicit default gateway`, + ); + + const perplexityAgent = new OpenAIProvider({ + providerName: 'perplexity-agent', + baseUrl: 'https://api.perplexity.ai/v1', + apiFormat: 'responses', + model: 'xai/grok-4-1-fast-non-reasoning', + }); + assert.equal(perplexityAgent._usesResponsesApi(), true); + assert.equal(perplexityAgent._responsesUrl(), 'https://api.perplexity.ai/v1/responses'); + + const vertexAnthropic = new VertexProvider({ + project: 'sample-project', + location: 'us-east5', + apiKey: 'google-key', + model: 'claude-haiku-4-5@20251001', + }); + assert.match(vertexAnthropic._messagesUrl(false), /publishers\/anthropic\/models\/claude-haiku-4-5%4020251001:rawPredict$/); + assert.match(vertexAnthropic._messagesUrl(true), /:streamRawPredict$/); + assert.match(vertexAnthropic._messagesUrl(false), /^https:\/\/us-east5-aiplatform\.googleapis\.com\//); + assert.equal(vertexAnthropic._headers()['x-goog-api-key'], 'google-key'); + const vertexBody = vertexAnthropic._prepareRequestBody({ model: 'ignored', messages: [], max_tokens: 16 }, {}, false); + assert.equal(vertexBody.model, undefined); + assert.equal(vertexBody.anthropic_version, 'vertex-2023-10-16'); + assert.match( + new VertexProvider({ + project: 'sample-project', + location: 'global', + apiKey: 'google-key', + model: 'claude-haiku-4-5@20251001', + })._messagesUrl(false), + /^https:\/\/aiplatform\.googleapis\.com\/v1\/projects\/sample-project\/locations\/global\//, + `${label}: Vertex Anthropic global location must use the global endpoint`, + ); + for (const location of ['us', 'eu']) { + assert.match( + new VertexProvider({ + project: 'sample-project', + location, + apiKey: 'google-key', + model: 'claude-haiku-4-5@20251001', + })._messagesUrl(false), + new RegExp(`^https://aiplatform\\.${location}\\.rep\\.googleapis\\.com/v1/projects/sample-project/locations/${location}/`), + `${label}: Vertex Anthropic ${location} must use its multi-region endpoint`, + ); + } + + const defaults = new PM()._defaultConfigs(); + assert.equal(new PM()._createProvider('morph', defaults.morph).supportsTools, false); + assert.equal(new PM()._createProvider('perplexity', defaults.perplexity).supportsTools, false); + assert.equal(new PM()._createProvider('aws_bedrock', defaults.aws_bedrock).supportsAskStreaming, false); + } +}); + +test('Chat Completions streaming rejects premature EOF and accepts terminal completion', async () => { + const originalFetch = globalThis.fetch; + try { + for (const [label, Provider] of [ + ['chrome', OpenAIProviderCh], + ['firefox', OpenAIProviderFx], + ]) { + globalThis.fetch = async () => new Response( + 'data: {"choices":[{"delta":{"content":"partial"}}]}\n\n', + { status: 200, headers: { 'Content-Type': 'text/event-stream' } }, + ); + const truncated = new Provider({ + providerName: 'deepinfra', + baseUrl: 'https://api.deepinfra.com/v1/openai', + model: 'test-model', + supportsAskStreaming: true, + }); + await assert.rejects( + async () => { + for await (const _chunk of truncated.chatStream([{ role: 'user', content: 'hi' }])) {} + }, + (error) => error?.isAskStreamFallbackSafe === true, + `${label}: truncated stream should be fallback-safe`, + ); + + globalThis.fetch = async () => new Response( + 'data: {"choices":[{"delta":{"content":"done"},"finish_reason":"stop"}]}\n\n', + { status: 200, headers: { 'Content-Type': 'text/event-stream' } }, + ); + const complete = []; + for await (const chunk of truncated.chatStream([{ role: 'user', content: 'hi' }])) { + complete.push(chunk); + } + assert.deepEqual(complete, [ + { type: 'text', content: 'done' }, + { type: 'done', content: '' }, + ], `${label}: terminal finish_reason should complete the stream`); + } + } finally { + globalThis.fetch = originalFetch; + } +}); + test('_defaultConfigs: new cloud providers present and disabled by default', () => { // Don't enable cloud providers by default — they all require an API key. // Auto-enabling them would create dead entries in the UI. @@ -27546,6 +27814,73 @@ test('Ask stream aggregation exposes text live but withholds tool calls until re } }); +test('Ask streaming estimates and records usage when a provider omits token metadata', async () => { + for (const [label, AgentClass] of [['chrome', AgentCh], ['firefox', AgentFx]]) { + const messages = [{ role: 'user', content: 'Summarize this page.' }]; + const streamOptions = { + tools: [{ + type: 'function', + function: { + name: 'read_page', + description: 'Read the current page.', + parameters: { type: 'object', properties: {} }, + }, + }], + }; + + const successfulAgent = new AgentClass({}); + successfulAgent._checkCostAllowance = async () => null; + let successfulRecordedUsage = null; + successfulAgent._recordCostUsage = async (_provider, usage) => { + successfulRecordedUsage = usage; + return null; + }; + const successfulProvider = { + async *chatStream() { + yield { type: 'text', content: 'Estimated answer.' }; + yield { type: 'done' }; + }, + }; + const result = await successfulAgent._chatStreamWithCostAllowance( + successfulProvider, + messages, + streamOptions, + {}, + ); + assert.equal(result.usage?.estimated, true, `${label}: missing stream usage should be marked estimated`); + assert.ok(result.usage?.prompt_tokens > 0, `${label}: estimated prompt usage should include messages and tools`); + assert.ok(result.usage?.completion_tokens > 0, `${label}: estimated completion usage should include streamed text`); + assert.deepEqual(successfulRecordedUsage, result.usage, `${label}: estimated stream usage should reach cost accounting`); + + const interruptedAgent = new AgentClass({}); + interruptedAgent._checkCostAllowance = async () => null; + let interruptedRecordedUsage = null; + interruptedAgent._recordCostUsage = async (_provider, usage) => { + interruptedRecordedUsage = usage; + return null; + }; + const interruptedProvider = { + async *chatStream() { + yield { type: 'text', content: 'Billable partial output.' }; + const error = new Error('stream ended early'); + error.isAskStreamFallbackSafe = true; + throw error; + }, + }; + await assert.rejects( + interruptedAgent._chatStreamWithCostAllowance( + interruptedProvider, + messages, + streamOptions, + {}, + ), + /stream ended early/, + ); + assert.equal(interruptedRecordedUsage?.estimated, true, `${label}: interrupted billable output should be estimated`); + assert.ok(interruptedRecordedUsage?.total_tokens > 0, `${label}: interrupted stream usage should reach cost accounting`); + } +}); + test('interactive Ask streaming preserves attachments and persists only the completed assistant turn', async () => { for (const [index, [label, AgentClass]] of [['chrome', AgentCh], ['firefox', AgentFx]].entries()) { let streamedMessages = null; @@ -27553,6 +27888,7 @@ test('interactive Ask streaming preserves attachments and persists only the comp const responseItems = [{ type: 'message', role: 'assistant', content: [{ type: 'output_text', text: 'Image received.' }] }]; const provider = { supportsTools: false, + supportsAskStreaming: true, supportsVision: true, promptTier: 'full', contextWindow: 128000, @@ -27616,6 +27952,7 @@ test('Ask stream failure clears partial text and falls back once for the rest of const executed = []; const provider = { supportsTools: true, + supportsAskStreaming: true, supportsVision: false, promptTier: 'full', contextWindow: 128000, @@ -27678,7 +28015,11 @@ test('Ask stream failure clears partial text and falls back once for the rest of assert.equal(chatCalls, 2, `${label}: failed generation and its tool follow-up should use provider.chat()`); assert.deepEqual(executed, ['read_page'], `${label}: pre-completion streamed tool call must never execute`); assert.ok(updates.some(update => update.type === 'text' && update.data?.replace === true && update.data?.content === ''), `${label}: partial streamed text should be cleared`); - assert.equal(updates.filter(update => update.type === 'warning').length, 0, `${label}: safe fallback should be silent`); + assert.equal( + updates.filter(update => update.type === 'warning' && update.data?.code === 'ask_stream_fallback').length, + 1, + `${label}: localized fallback warning event should be emitted once`, + ); assert.equal(agent.conversations.get(tabId).some(message => message.role === 'assistant' && message.content === 'Partial answer'), false, `${label}: failed partial text must not persist`); } }); diff --git a/web/docs/providers/index.html b/web/docs/providers/index.html index 039d757c3..178b81339 100644 --- a/web/docs/providers/index.html +++ b/web/docs/providers/index.html @@ -19,10 +19,12 @@
-
The model behind the panel

Choose the setup that matches your patience, privacy, and budget.

WebBrain works with its built-in cloud option, direct cloud APIs, model routers, and local OpenAI-compatible servers. You only need one active provider.

+
The model behind the panel

Choose the setup that matches your patience, privacy, and budget.

WebBrain includes 103 provider cards spanning its built-in cloud option, direct cloud APIs, model routers, and local OpenAI-compatible servers. You only need one active provider.

The quick choice

Fewest steps

WebBrain Cloud

Built in, active by default, and includes a free daily allowance. No model server or API key setup.

Private & offline-capable

Local model

Use llama.cpp, Ollama, LM Studio, Jan, vLLM, SGLang, or LocalAI. Your model requests stay with the server you run.

Direct relationship

Cloud API

Bring a key for OpenAI, Anthropic, Gemini, Mistral, DeepSeek, xAI, Groq, and other supported providers.

Broad catalog

Router

Use one account to choose among many models. OpenRouter and Hugging Face are useful when you experiment often.

+

103 built-in provider cards

Settings includes 76 additional direct APIs and routers, including Azure AI Foundry, Vertex AI, Vertex Anthropic, Cerebras, Cohere, DeepInfra, Perplexity, Vercel AI Gateway, Venice, and many regional coding plans. Search by provider or model name instead of scrolling the whole list.

Most cards use an API key and OpenAI-compatible endpoint. Vertex cards use a Google Cloud project, location, and authorization key; the global location uses Google’s global endpoint, while Vertex Anthropic also supports the us and eu multi-region hosts. Cloudflare accepts an optional AI Gateway ID and automatically uses the default gateway for @cf/ models when the field is blank. Interactive Ask turns stream when the selected provider supports it and automatically retry once without streaming if the connection ends early. Provider-reported token usage is recorded directly; otherwise WebBrain records a conservative estimate so streaming cannot bypass cost limits.

GitHub provider entries are intentionally absent

GitHub itself is not going away, but GitHub Models retires July 30, 2026. GitHub Copilot requires a separate subscription/OAuth integration. GitLab Duo and SAP AI Core also require custom authentication and discovery not supported by the browser extension.

+

Configure a provider

Provider list with Local, Cloud and Router filters plus the active WebBrain Cloud card
Use filters to shorten the list. The active provider remains visible so you always know what the panel is using.
  1. Find the provider. Use Local, Cloud, Router, or the search field.
  2. Open its card. Non-active cards are collapsed to keep the list readable.
  3. Enter the values. Local servers usually need a URL and model name. Cloud providers also need an API key.
  4. Save. This stores the card’s current fields in the browser.
  5. Test Connection. Fix any reported URL, key, model, or server problem before continuing.
  6. Set Active. Only after the test succeeds. A saved provider is not necessarily the provider the side panel is using.

What the fields mean

FieldMeaningNew-user advice
Server / Base URLThe OpenAI-compatible root endpoint or provider API root.Use the exact value shown by your local app or provider. Do not paste a chat webpage URL.
API keyA credential sent to that provider.Local servers normally do not need one unless you enabled authentication.
ModelThe model identifier the server expects.Spelling and prefixes matter. “Model not found” usually means this field does not match the provider catalog.
Context windowHow much prompt, history, page content, and tool schema fits in one request.16k tokens is the usable target for reliable local runs. 8k can work with Compact; 4k is too small.
Supports visionWhether the selected local or open catalog model accepts images.Enable only when the exact served model can process image input.
Prompt tierHow large a prompt and normal browser-tool set WebBrain exposes.Start with Mid for local models. Use Compact for small contexts and Full for capable models.
Input / output costOptional price estimates per million tokens.Fill these when you want WebBrain’s cost allowances to estimate providers that do not report usage cost.
@@ -35,7 +37,7 @@
- + diff --git a/web/docs/zh/providers/index.html b/web/docs/zh/providers/index.html index 2b311201b..597a22924 100644 --- a/web/docs/zh/providers/index.html +++ b/web/docs/zh/providers/index.html @@ -12,14 +12,15 @@
-
侧边栏背后的模型

根据耐心、隐私需求与预算选择方案。

WebBrain 支持内置云服务、直接云 API、模型路由和本地 OpenAI 兼容服务器。你只需要一个活动提供商。

+
侧边栏背后的模型

根据耐心、隐私需求与预算选择方案。

WebBrain 内置 103 张提供商卡片,涵盖托管云服务、直接云 API、模型路由和本地 OpenAI 兼容服务器。你只需要一个活动提供商。

快速选择

步骤最少

WebBrain Cloud

内置且默认启用,包含每日免费额度,无需模型服务器或 API 密钥。

隐私与离线能力

本地模型

使用 llama.cpp、Ollama、LM Studio、Jan、vLLM、SGLang 或 LocalAI。

直接使用厂商

云 API

为 OpenAI、Anthropic、Gemini、Mistral、DeepSeek、xAI、Groq 等提供商填写自己的密钥。

模型目录丰富

模型路由

使用一个账户切换许多模型;适合经常试验的用户。

+

103 张内置提供商卡片

设置新增了 76 个直连 API 与路由器,包括 Azure AI Foundry、Vertex AI、Vertex Anthropic、Cerebras、Cohere、DeepInfra、Perplexity、Vercel AI Gateway、Venice 和多个区域性编程套餐。可以按提供商或模型名称搜索。

大多数卡片使用 API 密钥与 OpenAI 兼容端点。Vertex 卡片使用 Google Cloud 项目、区域和授权密钥;全局区域使用 Google 的全局端点,Vertex Anthropic 还支持 useu 多区域主机。Cloudflare 接受可选的 AI Gateway ID;对于 @cf/ 模型,留空时自动使用 default 网关。支持流式传输的提供商会在交互式 Ask 中实时显示回复,连接提前结束时自动以非流式方式重试一次。服务返回令牌用量时会直接记录;否则 WebBrain 记录保守估算,避免流式请求绕过成本限额。

有意不提供 GitHub 条目

GitHub 本身不会关闭,但 GitHub Models 将于 2026 年 7 月 30 日退役。GitHub Copilot 需要单独的订阅/OAuth 集成。GitLab Duo 和 SAP AI Core 也需要浏览器扩展不支持的专用认证与部署发现。

配置步骤

WebBrain 提供商设置英文界面
截图为英文界面;中文界面结构与控件位置相同。
  1. 找到提供商。使用“本地”“云端”“路由”或搜索框。
  2. 展开卡片并填写值。本地服务器通常需要地址和模型名;云提供商还需要 API 密钥。
  3. 保存。把当前字段写入浏览器。
  4. 测试连接。先修复地址、密钥、模型或服务器错误。
  5. 设为活动。只有测试成功后再切换。保存并不等于已经启用。

字段含义

字段含义建议
服务器 / Base URLOpenAI 兼容根端点或提供商 API 根地址。使用本地应用或提供商给出的精确值,不要粘贴聊天网页地址。
API 密钥发送给提供商用于认证的凭据。本地服务器通常不需要,除非你主动启用了认证。
模型服务器要求的模型标识符。大小写、前缀和拼写必须准确。
上下文窗口一次请求容纳提示、历史、网页内容和工具模式的容量。可靠本地运行建议至少 16k;8k 可配合 Compact;4k 太小。
支持视觉当前模型是否接受图像。只有确认所服务的精确模型支持图像时才开启。
提示层级WebBrain 暴露的提示长度和常规浏览器工具范围。本地模型从 Mid 开始;小上下文用 Compact,能力强的模型用 Full。

本地模型的额外环节

服务器常见 Base URLAPI 密钥
llama.cpphttp://localhost:8080通常不需要
Ollamahttp://localhost:11434/v1不需要
LM Studiohttp://localhost:1234/v1不需要
Janhttp://localhost:1337/v1可选
vLLMhttp://localhost:8000/v1可选
SGLanghttp://localhost:30000/v1可选
终端可用,不代表扩展一定可访问

连接被拒绝通常是服务器未启动或端口错误;CORS/Origin 错误需要允许浏览器扩展来源。Ollama 常用:OLLAMA_ORIGINS="chrome-extension://*,moz-extension://*" ollama serve

提示层级

Compact最短提示与最小工具面,适合约 8k 上下文的小型本地模型。
Mid包含常见浏览器任务、iframe、下载、计划任务和表单验证。推荐的本地起点。
Full增加 hover、拖放、框架与 Shadow DOM 等高级回退工具。

云提供商固定使用 Full;本地提供商默认 Mid;Compact 提供商不能使用 Dev 模式。

测试连接失败时

  1. Connection refused:启动本地服务器并确认端口。
  2. CORS/Origin:在服务器中允许 WebBrain 扩展来源。
  3. Unauthorized:确认密钥与 Base URL 属于同一提供商。
  4. Model not found:复制精确模型 ID,或使用 Load models。
  5. 超时:为大型 CPU 本地模型提高常规请求超时。
  6. 几轮后失败:确认真实上下文窗口,降低提示层级或扩大模型上下文。
-
+
From db5289563cb0807883e22c0d0252e30631e526ea Mon Sep 17 00:00:00 2001 From: Emre Sokullu Date: Thu, 23 Jul 2026 18:01:27 +0300 Subject: [PATCH 2/2] Fix evroc icon and add provider counts --- src/chrome/icons/providers/evroc.svg | 4 ++-- src/chrome/src/ui/settings.html | 21 +++++++++++++++++++++ src/chrome/src/ui/settings.js | 9 ++++++++- src/firefox/icons/providers/evroc.svg | 4 ++-- src/firefox/src/ui/settings.html | 21 +++++++++++++++++++++ src/firefox/src/ui/settings.js | 9 ++++++++- test/run.js | 21 +++++++++++++++++++++ 7 files changed, 83 insertions(+), 6 deletions(-) diff --git a/src/chrome/icons/providers/evroc.svg b/src/chrome/icons/providers/evroc.svg index 7597820a1..f65549485 100644 --- a/src/chrome/icons/providers/evroc.svg +++ b/src/chrome/icons/providers/evroc.svg @@ -1,3 +1,3 @@ - + - \ No newline at end of file + diff --git a/src/chrome/src/ui/settings.html b/src/chrome/src/ui/settings.html index 44a950a25..ed469a47f 100644 --- a/src/chrome/src/ui/settings.html +++ b/src/chrome/src/ui/settings.html @@ -435,6 +435,27 @@ color: var(--accent); } .provider-filter-pill.active:hover { color: var(--accent); } + .provider-filter-count { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 18px; + height: 18px; + padding: 0 5px; + border: 1px solid var(--border); + border-radius: 999px; + background: var(--bg3); + color: var(--text2); + box-sizing: border-box; + font-size: 10px; + font-variant-numeric: tabular-nums; + line-height: 1; + letter-spacing: 0; + } + .provider-filter-pill.active .provider-filter-count { + color: var(--accent); + border-color: currentColor; + } .provider-search { flex: 0 1 240px; min-width: 180px; diff --git a/src/chrome/src/ui/settings.js b/src/chrome/src/ui/settings.js index 54a2ffe00..f3740286c 100644 --- a/src/chrome/src/ui/settings.js +++ b/src/chrome/src/ui/settings.js @@ -2628,12 +2628,19 @@ function renderProviderFilterBar() { { key: 'cloud', labelKey: 'st.providers.filter.cloud' }, { key: 'router', labelKey: 'st.providers.filter.router' }, ]; + const filterCounts = Object.values(providersData).reduce((counts, config) => { + counts.all += 1; + const category = config.category || 'cloud'; + if (Object.hasOwn(counts, category) && category !== 'all') counts[category] += 1; + return counts; + }, { all: 0, local: 0, cloud: 0, router: 0 }); for (const f of filters) { const btn = document.createElement('button'); btn.type = 'button'; btn.className = `provider-filter-pill${providerFilter === f.key ? ' active' : ''}`; btn.dataset.filter = f.key; - btn.innerHTML = `${filterIcons[f.key] || ''}${escapeHtml(t(f.labelKey))}`; + btn.innerHTML = `${filterIcons[f.key] || ''}${escapeHtml(t(f.labelKey))}` + + `${filterCounts[f.key]}`; btn.addEventListener('click', async () => { if (providerFilter === f.key) return; // Snapshot whatever the user has typed but not yet saved BEFORE we diff --git a/src/firefox/icons/providers/evroc.svg b/src/firefox/icons/providers/evroc.svg index 7597820a1..f65549485 100644 --- a/src/firefox/icons/providers/evroc.svg +++ b/src/firefox/icons/providers/evroc.svg @@ -1,3 +1,3 @@ - + - \ No newline at end of file + diff --git a/src/firefox/src/ui/settings.html b/src/firefox/src/ui/settings.html index 8878e437a..b05ec8ccd 100644 --- a/src/firefox/src/ui/settings.html +++ b/src/firefox/src/ui/settings.html @@ -429,6 +429,27 @@ color: var(--accent); } .provider-filter-pill.active:hover { color: var(--accent); } + .provider-filter-count { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 18px; + height: 18px; + padding: 0 5px; + border: 1px solid var(--border); + border-radius: 999px; + background: var(--bg3); + color: var(--text2); + box-sizing: border-box; + font-size: 10px; + font-variant-numeric: tabular-nums; + line-height: 1; + letter-spacing: 0; + } + .provider-filter-pill.active .provider-filter-count { + color: var(--accent); + border-color: currentColor; + } .provider-search { flex: 0 1 240px; min-width: 180px; diff --git a/src/firefox/src/ui/settings.js b/src/firefox/src/ui/settings.js index bbc5cdccc..46629cd7d 100644 --- a/src/firefox/src/ui/settings.js +++ b/src/firefox/src/ui/settings.js @@ -2566,12 +2566,19 @@ function renderProviderFilterBar() { { key: 'cloud', labelKey: 'st.providers.filter.cloud' }, { key: 'router', labelKey: 'st.providers.filter.router' }, ]; + const filterCounts = Object.values(providersData).reduce((counts, config) => { + counts.all += 1; + const category = config.category || 'cloud'; + if (Object.hasOwn(counts, category) && category !== 'all') counts[category] += 1; + return counts; + }, { all: 0, local: 0, cloud: 0, router: 0 }); for (const f of filters) { const btn = document.createElement('button'); btn.type = 'button'; btn.className = `provider-filter-pill${providerFilter === f.key ? ' active' : ''}`; btn.dataset.filter = f.key; - btn.innerHTML = `${filterIcons[f.key] || ''}${escapeHtml(t(f.labelKey))}`; + btn.innerHTML = `${filterIcons[f.key] || ''}${escapeHtml(t(f.labelKey))}` + + `${filterCounts[f.key]}`; btn.addEventListener('click', async () => { if (providerFilter === f.key) return; // Snapshot whatever the user has typed but not yet saved BEFORE we diff --git a/test/run.js b/test/run.js index e2d847c99..d1ef00c13 100644 --- a/test/run.js +++ b/test/run.js @@ -25989,6 +25989,11 @@ test('extended provider catalog is complete, mirrored, safe, and excluded-provid assert.equal(fs.existsSync(icon), true, `${label}: missing icon for ${id}`); const svg = fs.readFileSync(icon, 'utf8'); assert.match(svg, /]*\bxmlns=["']http:\/\/www\.w3\.org\/2000\/svg["']/i, + `${label}: ${id} SVG root lacks the SVG namespace`, + ); assert.match(svg, /\bviewBox=/i, `${label}: ${id} icon lacks viewBox`); assert.doesNotMatch(svg, /\$\{filterCounts\[f\.key\]\}/, + `${label}: every provider filter must render its count pill`, + ); + const settingsHtml = fs.readFileSync(path.join(ROOT, prefix, 'src/ui/settings.html'), 'utf8'); + assert.match( + settingsHtml, + /\.provider-filter-count\s*\{[\s\S]*?border-radius:\s*999px;/, + `${label}: provider filter counts must use pill styling`, + ); const localeDir = path.join(ROOT, prefix, 'src/ui/locales'); for (const localeFile of fs.readdirSync(localeDir).filter(file => file.endsWith('.js'))) {