Repository navigation
feat(chat): native multi-provider backend (Gemini / Anthropic / OpenAI) - #260
Merged
Merged
Conversation
…one set Orcabot chat hard-required GEMINI_ORCABOT_KEY and 500'd if it was missing — which is always the case on desktop (no system key ships, and baking one in would be a leaked key). The handler already had a user-GEMINI_API_KEY fallback, but the top-of-function guard bailed before ever reaching it, so even a desktop user who had set their own key got a dead "Something went wrong". Backend (chat/handler.ts): - Drop the premature GEMINI_ORCABOT_KEY guard. Resolve the key as system key OR the user's decrypted GEMINI_API_KEY (the existing fallback), and only fail when NEITHER exists — with a distinct `E79230 / CHAT_NO_KEY` (400) the client can act on. Cloud behavior is unchanged (system key always present). Frontend (ChatPanel.tsx): - On the E79230 error, replace the generic notice with a clear message plus the inline AiProviderSetupCard (saves GEMINI_API_KEY to _global, exactly where the handler reads it), so the user can add a key and send again. A dismissal flag hides the card after setup; it re-shows if a fresh no-key error occurs. Net: on desktop, chat now works once the user adds their own Gemini key, and the no-key state guides them there instead of a dead-end error. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XBxVYcEidYfRm5Gf4j7nPL
Chat was hardwired to Gemini's wire format. Introduce a provider abstraction so the same agentic tool loop runs against whichever provider key the user has. New src/chat/providers/: - types.ts — canonical, provider-neutral ChatMsg / ChatToolDef / ChatChunk + ChatProvider interface (streamTurn(system, messages, tools)). - gemini.ts — wraps the existing (tested) gemini/client; system as priming pair; thoughtSignature round-tripped via CanonToolCall.meta; drops history calls lacking a signature (Gemini 3 requirement) plus their paired results. - anthropic.ts — Messages API: system param, tool_use/tool_result blocks, input_json_delta streaming accumulation. - openai.ts — Chat Completions: system message, tool_calls delta accumulation. - select.ts — decrypts the user's stored keys and picks a provider. handler.ts: build a canonical conversation + system prompt once, select a provider, run the loop against provider.streamTurn (append canonical assistant/tool turns between iterations). Tool-call IDs are carried canonically (real for Anthropic/OpenAI, synthesized for Gemini). Selection keeps cloud unchanged: with GEMINI_ORCABOT_KEY set, chat stays on Gemini (user's key if present, else system) — we do NOT silently spend a user's paid Anthropic/OpenAI key when free Gemini is available. Only on desktop (no system key) does it route to the user's Gemini → Anthropic → OpenAI key. Frontend: the no-key card copy now says "add a provider key (Claude, Gemini, or OpenAI)"; AiProviderSetupCard already collects all three. Models (cheap/fast, easily changed): gemini-3-flash, claude-haiku-4-5, gpt-4o-mini. Both sides typecheck clean. The Anthropic/OpenAI streaming + tool loops are NOT yet exercised against live APIs — need a real key to validate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XBxVYcEidYfRm5Gf4j7nPL
When chat hit the CHAT_NO_KEY error, the user's message stayed as a shown-but-
unanswered bubble; after adding a key they had to retype it. Now the setup
card's onDone re-sends the last user message. sendMessage gains a
{ skipUserEcho } option so the retry reuses the already-shown bubble instead of
duplicating it. Only fires when keys were actually saved (not on skip).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XBxVYcEidYfRm5Gf4j7nPL
…went wrong" An out-of-quota / bad-key / rate-limit provider error showed the same generic "Something went wrong — please try again", which for a BYO-key desktop user is a dead end (the OpenAI quota case looked like a bug until the logs were read). Classify provider errors in the handler (friendlyProviderError) into short, self-serviceable messages — "OpenAI: quota exceeded — check your plan and billing.", "Anthropic: API key rejected — check the key.", etc. — without leaking raw provider JSON, and render that message in ChatPanel instead of the hardcoded text. Unknown errors still fall back to the generic notice. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XBxVYcEidYfRm5Gf4j7nPL
…kers - P1: OpenAI streams send BOTH a finish_reason chunk and a [DONE] sentinel, and flushToolCalls() yielded from `pending` without clearing it — so every tool call fired twice (mutating tools run twice; duplicate call ids corrupt the next turn). Delete each entry as it's yielded so a second flush is a no-op. - P2: bump the required revision markers in ChatPanel.tsx (chat-v34) and useChat.ts (chat-v4) to match their changes, per frontend/CLAUDE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XBxVYcEidYfRm5Gf4j7nPL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Makes Orcabot chat work with any of Gemini / Anthropic / OpenAI, and turns the
no-key state into a guided setup instead of a dead-end error. Primary motivation:
desktop chat, where no system Gemini key ships and a user must bring their own.