Commit Graph
117 Commits
Author SHA1 Message Date
Arnav Naval 38c6717fb7 [arnav] feat: enable SDK skill auto-discovery via directory layout migration
Skills previously lived as flat `<slug>.md` files injected directly into
the user prompt, which bypassed Claude Code CLI's native discovery entirely.
Switch to the CLI's expected `<slug>/SKILL.md` layout so the SDK can surface
each skill's frontmatter to the model and let it call `Skill(slug)` lazily
on its own — without having to eagerly inject every skill body every turn.
Key changes:
- One-shot startup migration moves existing flat files into the directory
  layout (idempotent, crash-safe, preserves existing dir if already migrated)
- `get_installed_slugs()` with module-level cache (keyed by SKILLS_DIR) so
  the per-turn allowlist query is effectively free on the hot path
- `_ensure_frontmatter()` stamps a valid YAML block on every write so the
  CLI listing never silently drops a skill with missing frontmatter
- `_resolve_sdk_skill_allowlist()` replaces the old `skills=[]` kill-switch:
  passes only user-installed slugs to the SDK, filtering out bundled Claude
  Code skills (/init, /review, etc.) by not including them, and dropping
  manually-attached skills that are already injected into the user message
- CRUD endpoints and tests updated to the new directory layout throughout
2026-05-10 17:56:23 -05:00
Arnav Naval 84d5e1fa60 [arnav] disable Claude Code's bundled plugin skills in agent sessions
Pass `skills=[]` to ClaudeAgentOptions so the SDK's built-in plugin
skills (/init, /review, /security-review, /simplify, /loop, /schedule,
/update-config, /keybindings-help, /fewer-permission-prompts,
/claude-api) are hidden from the model and rejected by the Skill tool.
These skills are inappropriate in OpenSwarm: half mutate ~/.claude
config files (settings.json, keybindings.json) that OpenSwarm doesn't
read, and the rest expose slash commands the backend never intercepts —
causing the model to falsely claim capabilities it can't actually use.
OpenSwarm's own skills system injects skill content directly into the
user prompt via _resolve_attached_skills, bypassing the Skill tool
entirely, so user-attached skills are unaffected.
Also adds a regression test that pins the `skills=[]` assignment so it
can't be silently dropped in a future refactor.
2026-05-09 10:36:15 -05:00
Arnav NavalandCursor 8e8696b858 [arnav] remove dead service-client and credentials helpers
Three submit_* helpers and one DEPRECATED env builder had no callers
outside their own tests — confirmed via dead-code scan + repo-wide
grep across backend/, frontend/, electron/, scripts/. Drops 50 LOC
with zero behavioral impact (full backend test suite still green at
1096 passed).

- backend/apps/service/client.py: drop submit_state, submit_session_close,
  submit_diagnostic. None were called in production; remaining wire shape
  (update_identity's submit("state", {"identity": ...})) is preserved.
- backend/apps/settings/credentials.py: drop get_agent_sdk_env. Was
  self-documented as DEPRECATED in favor of create_provider() /
  get_anthropic_client*; no callers anywhere.
- backend/tests/test_service.py: drop the two test_legacy_submit_*
  cases that were the only references keeping the helpers above the
  vulture threshold.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-06 19:09:56 -05:00
Arnav NavalandCursor 64dfd50d12 [arnav] remove dead code identified by audit
Each removal verified by checking actual production callers (frontend,
electron, internal HTTP, MCP-server subprocesses) — not just test
references. Symbols whose only callers were tests are removed along
with those tests.

Production removals (~390 LOC):

- backend/main.py
  - websocket_session: drop `agent:edit_message` WS branch. Frontend
    only ever uses HTTP `POST /api/agents/sessions/{id}/edit_message`
    (frontend/src/shared/state/agentsSlice.ts); nothing on the wire
    sends a WS message of this type.

- backend/apps/agents/agent_manager.py
  - AgentManager._build_connected_tools_context (~80 LOC): zero call
    sites in production; the connected-tools system-prompt context is
    built inline in _compose_system_prompt now.
  - AgentManager._approx_tokens / _summarize_message_block: pure
    helpers whose only callers were tests. The compaction path uses
    LLM-driven _maybe_compact instead.

- backend/apps/agents/browser_agent.py
  - clear_browser_history: only used by tests. _browser_history is
    pruned via the size cap inline.
  - MODEL_MAP constant: never read.

- backend/apps/agents/mcp_preflight.py
  - DISCOVERY_SCAFFOLDING (~25-line system-prompt block): defined but
    never appended anywhere. The header comment described an intended
    use that the codebase no longer has.

- backend/apps/agents/providers/registry.py
  - thinking_params_for, _is_9router_available, OPENROUTER_BASE_URL,
    get_context_window: zero callers in production. Thinking-params
    routing is done by the provider classes directly; 9Router presence
    is detected at request time; context-window numbers are stamped
    onto sessions from BUILTIN_MODELS at launch.

- backend/apps/agents/tools/{base,web}.py
  - BaseTool.get_schema (abstract) + WebSearchTool/WebFetchTool
    overrides: production code in backend/apps/web/web.py instantiates
    these tools and only calls .execute(); the JSON-schema lives in
    the HTTP wrapper, not on the tool class.

- backend/apps/outputs/outputs.py
  - _resolve_model + MODEL_MAP: tests-only.
  - load_output: docstring claimed it was a public helper for "other
    modules" but no module imported it.

- backend/apps/service/client.py
  - set_user_id, the _user_id module global, and the dead cache short-
    circuit in _get_user_id: setter was tests-only. _get_user_id now
    reads user_email directly from settings on every call.

- backend/apps/settings/credentials.py
  - get_provider_credentials: zero callers. The sibling get_agent_sdk_env
    is kept (it has the explicit "Legacy helpers" keep-comment).

Test updates:

- test_agent_manager_unit.py: drop _approx_tokens / _summarize_message_block
  cases (5 tests), update module docstring index.
- test_browser_agent_unit.py: drop clear_browser_history cases (2 tests)
  and the unused _Boom helper class in the repr-fallback test.
- test_outputs_unit.py: drop _resolve_model / load_output cases
  (4 tests), update docstring + import list.
- test_v2_invariants.py: drop get_context_window tests + get_schema
  assertions on web tools (kept name + BaseTool inheritance checks).
- test_service.py: rewrite the 4 set_user_id-driven tests to drive
  user_id through settings.user_email instead, so _get_user_id's live
  envelope-stamping path stays covered.

Verification:
- ruff --select F401,F811,F841 backend/  →  clean.
- pytest backend/tests/ → 1167 passed, 1 deselected (pre-existing
  sandbox git test, unrelated). No tests dropped silently — every
  deletion is paired with the corresponding test removal/rewrite.
- Dead-code scan re-run: dead WS events 1→0, Tier-2 high-confidence
  14→11 (residue is SDK-callback `context` params + Pydantic `cls`
  validators — both false positives vulture can't see through),
  vulture total 165→145.

Total diff: -565 / +34 LOC across 15 files.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-06 18:49:30 -05:00
Arnav NavalandCursor 9100e91652 [arnav] clean up unused imports and dead local variables
Auto-fixed 52 ruff F401 findings (unused imports) across 22 files
in backend/ and backend/tests/. Manually resolved 8 F841 unused
locals that ruff flagged as unsafe-fix:

- agent_manager.resume_session: drop dead hours_since_closed block.
- main.py mcp-meta + outputs-meta activate handlers: drop dead
  reason = body.get("reason") binding (server ignores the field).
- dashboards.seed_demo, tools_lib.m365_device_login: keep _load(...)
  call for its 404 side-effect, drop unused binding, add intent
  comment.
- outputs.auto_run_output: keep `import anthropic` as availability
  probe, mark with `# noqa: F401` and explanation.
- dead_code_scan._extract_ws_event_branches: drop vestigial
  ws_handler_lines set (never written or read).
- test_browser_agent_unit.test_hash_tool_call_falls_back_to_repr:
  drop the unused _Boom class+instance (the actual self-referential
  bait is bad_input/bad_result; _Boom was never passed to the
  function under test).

Result: 1184/1184 backend tests pass (1 deselected: pre-existing
sandbox-only git test). ruff --select F401,F811,F841 backend/ now
clean (was 60 findings).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-06 18:30:34 -05:00
Arnav Naval 5cc9f6f01a [arnav] remove 6 dead HTTP endpoints
Verified each had no production caller (frontend, electron, or
internal backend) — only test references kept them looking alive
to coverage tools. Drops ~140 LOC of route handlers + helpers.
- POST /api/outputs/vibe-code: never wired up; frontend has no
  vibe-code UI. Also drops VibeCodeRequest model and
  VIBE_CODE_SYSTEM_PROMPT.
- GET /api/service/cost-breakdown: frontend Usage page reads
  /usage-summary, which already returns by_model/by_provider.
- GET /api/service/status: zero callers; was placeholder.
- GET /api/service/spool/count: debug-only, no UI surface.
- GET /api/settings/default-system-prompt: frontend defines its
  own DEFAULT_SYSTEM_PROMPT in settingsSlice.ts and never fetches
  the backend constant.
- POST /api/browser/command: sole caller (browser_mcp_server.py
  subprocess) was deleted in 8286cc1; browser_agent.py now calls
  ws_manager.send_browser_command directly in-process.
Tests covering the removed endpoints are dropped along with the
now-unused mock-anthropic helpers in test_api_outputs.py.
2026-05-06 17:11:57 -05:00
Arnav Naval 2bd5478405 [arnav] Re-adds backend/apps/service/models.py
Also removes tests that covered code no longer present in the codebase:
- test_agent_loop.py, test_tools_unit.py — deleted (targets removed)
- test_mcp_servers_unit.py — deleted (targets removed)
- test_providers_anthropic_extra.py, test_providers_openai_compat.py,
  test_providers_registry.py — deleted (providers layer refactored away)
- test_api_outputs.py — drops vibe-code tests (endpoint removed)
- test_browser_agent_integration.py — drops run_browser_agents fanout
  tests (function removed)
- test_mcp_preflight.py — drops _call_classifier tests (internal removed)
2026-05-06 09:42:58 -05:00
Arnav NavalandCursor 9630ca718a remove Tier-0 dead code: dashboard_layout package and service/models stub
backend/apps/dashboard_layout/ was never mounted in main.py and had no
frontend/electron callers — its SubApp and endpoints were fully superseded
by backend/apps/dashboards/. backend/apps/service/models.py was an empty
placeholder with no importers. Also adds .dead-code-scan/ and the scan
script to .gitignore, and drops the stale dashboard_layout/ entry from
the README directory tree.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-05 21:35:41 -05:00
ciregenz c64bf65c66 [eric] session state additions + ui hook refinements 2026-05-05 17:05:54 -07:00
ciregenz 415ab70b53 [eric] unify telemetry surface, install_method, frontend trackEvent 2026-05-05 14:35:43 -07:00
ciregenz 49c649e3d9 [eric] single sync function for all state syncing 2026-05-05 12:11:07 -07:00
ciregenz b2015caca7 [eric] batch heartbeats locally before sending 2026-05-05 00:21:52 -07:00
ciregenz 59e20e11ea [eric] clean up remaining non-opaque references 2026-05-04 22:25:48 -07:00
ciregenz 3c42d8738f [eric] refactor internal service layer 2026-05-04 19:39:19 -07:00
ciregenz b7a1faee38 [eric] delete miscelaneous scrapped code 2026-05-04 19:15:42 -07:00
ciregenz 5df979a59a analytics: fix completion-rate, mock-cost, and tool-count accuracy bugs 2026-05-04 17:50:11 -07:00
ciregenz 8286cc1a5c [eric] delete ~3.6k lines of dead code (old unused agent runtime, ghost fields, orphan scripts). all 660 tests still pass, no functional
change.
2026-05-03 22:39:17 -07:00
ciregenz 5f5b932c53 [eric] tiny dead-code sweep — drop unused langchain pins from requirements.txt (saves ~5MB on packaged build) plus a few orphan exports left
over from past iterations (temp_state slice fields, clipboard timestamp getter, three never-imported lastSeq helpers).
2026-05-03 21:31:13 -07:00
ciregenz d14cc89300 [eric] tool labels read like a person — Plugged into Gmail, Saved a snapshot, varied phrasings per call; session/turn labels
in sentence case; activating an MCP mid-chat now actually works instead of the model guessing at made-up tool names. Also a bunch miscelaneous ui/ux tweaks, I cant be bothered :)
2026-05-03 20:44:32 -07:00
ciregenz ade79315a9 [eric] thinking pill shows full turn cost (input + output + subagent + tool work) with click-to-see input/output breakdown; reopening
completed chats no longer replays the typewriter (per-session lastSeq survives AgentChat remount so resume protocol stays at the high-water
  mark instead of last_seq=0)
2026-05-03 11:21:02 -07:00
ciregenz d310f9e031 [eric] thinking pill works on GPT/Gemini (clickable bubble with duration + token count + honest "provider does not expose
reasoning text" note instead of vanishing); friendlier MCP tool names (Gmail/Slack/etc with verb-derived actions); auto-collapse Anthropic
  thinking pill on turn end so the answer comes first; header timer matches per-turn pill (sums in ms, rounds once); thinking pill rolls 251s
  to 4m 11s; parallel tool count chips do not jitter as N grows; drop Gemini 2.5 from picker (Gemini 3 family only); aux-LLM calls route
  per-model so cheap-tier auxiliary calls do not 401 on cc/ subscription routes
2026-05-02 23:46:13 -07:00
ciregenz 691a92c2a1 [eric] dynamic turn labels in the thinking pill via cheap-tier aux LLM + cache pre-warm on dashboard mount for faster turn-1
TTFT
2026-04-30 12:31:48 -04:00
ciregenz 98349df9f1 [eric] faster replies + smarter chat: optimistic message bubbles, live thinking... pill, friendlier tool-call labels (Reading → Read),
compaction chip, native completion notifications, prompt-cache flip for ~70% cheaper/faster
2026-04-29 14:07:18 -04:00
ciregenz b7c93e2251 [eric] global ⌘K search + ⌘L clear chat + sticky notes on canvas + merge Chat into Ask + chat composer/dock sizing + spellcheck 2026-04-29 02:41:01 -04:00
ciregenz f755548b93 [eric] drop (Pro/Max) suffix from cc/ model labels — group header already disambiguates from OpenSwarm Pro proxy;
.gitattributes: split mcp-bundles vendored pattern into two
2026-04-29 00:46:17 -04:00
ciregenz 9be2d87f73 [eric] WS resilience: per-session seq + ring buffer + resume protocol so agent runs survive transient disconnects (wifi flap, sleep, NAT
drop) instead of flipping to completed. Adds heartbeat (25s ping/10s pong), reconnect with infinite jittered backoff, outbound queue gated
   on resume_ack, gap_detected fallback for long offlines, on-disk persistence of terminal events for post-restart recovery, and a
  reconnecting connection state decoupled from session.status. 1089 backend tests covering 500 randomized disconnect scenarios + concurrent
  broadcast races. Backend/WS handler does not cancel agent task on disconnect
2026-04-28 23:47:59 -04:00
ciregenz 5d69215739 [eric] phase 2+3: outputs gate, smart compaction, slash commands, preflight + auto-continue, bumped Anthropic SDK 2026-04-28 19:55:06 -04:00
ciregenz 30d581e9ec [eric] phase 1: MCP activation gate, context pill, friendly 429s, -api routes so API keys actually work 2026-04-28 19:01:07 -04:00
ciregenzandClaude Opus 4.7 f0ea0fd1bc [eric] 1.0.27 production push: fixes the weird "exec" icon next to OpenSwarm on fresh Macs, faster startup (~10s less from shipping a real Node binary instead of running Electron as Node), and Google Workspace + other uvx-based MCPs work again on machines without uv installed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:37:17 -07:00
ciregenz f4cded781b [eric] App Builder fixes: preview loads (auth-token threaded into iframe URL + sub-resource paths), agent keeps running when you switch tabs
(session+workspace persisted on the app), Settings default model/thinking now flow into App + Skill Builder drafts
2026-04-27 15:09:25 -07:00
ciregenz f8557e378f [eric] 1.0.26: ship Discord shim default + auto-migrate legacy + clean Google
reconnect
2026-04-26 18:12:45 -07:00
ciregenz c501b6340c [eric] OAuth + MCP polish: more reliable connect flow, Discord shim,
connected MCPs sort to top, Haiku-overflow warning, misc fixes, security risks fixes
2026-04-26 15:14:16 -07:00
ciregenz 94ea07dd0c [eric] make Windows install + boot way faster: splash window so it's not frozen on startup, swap MCP node_modules for tiny esbuild bundles
(138MB → 7MB), pre-compile python bytecode, parallelize Widevine, never silently quit
2026-04-25 03:05:08 -07:00
ciregenz 2379dd92be [eric] security: lock down the local websocket + http api with a per-install auth token 2026-04-25 02:26:13 -07:00
ciregenz f5cc3a36fb [eric] remove vendored 9router (now fetched from npm at build), remove Copilot, and fix subs + tools 2026-04-25 02:26:08 -07:00
Eric 744a14dc47 [eric] 1.0.26 windows-only: fix subscription OAuth + perf pass
Connecting→Connect mid-flow on Windows: 9router callback hardcoded
  localhost:8324 (dies when backend lands on 8325+)
2026-04-22 16:33:00 -07:00
Eric 4ce4dec33c [eric] windows polish + bump 1.0.25: publish-win.ps1 mirror of publish.sh + run.ps1 windows dev launcher, build-app-win.ps1 warns 8s if Mac latest-mac.yml missing in
v<version> release before -Publish, python-env cache skip via OPENSWARM_REBUILD_PYTHON, pip stderr wrapped to suppress PS5.1 NativeCommandError; analytics APP_VERSION
  auto-derived from electron/package.json (single source of truth); OnboardingModal renders Connected state for already-active providers; gitignore fix for backend/.venv.
  Bumps 1.0.25 - first version that ships Mac and Windows together.
2026-04-21 21:53:48 -07:00
Eric 9ff07443db [eric] windows shipping: electron-builder win+nsis + Azure Trusted Signing hook, build-app-win.ps1 / build-python-env-win.ps1 mirroring mac, release-windows.yml tag-triggered CI, icon.ico + .env.windows.example, .claude/ + .env.* gitignored. Runtime fixes: PYTHONUTF8=1 (cp1252 UnicodeDecode), python.exe / Lib\site-packages paths, PYTHONPATH path.delimiter, taskkill /T /F process tree, OAuth UA platform branch, sign-vmp postinstall via node wrapper. Backend: _resolve_command PATHEXT probing (fixes uvx not found), UV_PYTHON Windows path. Cross-env added to 9router+electron for NODE_ENV prefix on cmd. Onboarding: poll subscriptions/status while connect step is open, render Connected for active providers (was stuck on "Connect" after 30s OAuth poll timeout). 2026-04-21 18:15:49 -07:00
ciregenz 11b07bde28 [eric] production push 1.0.24: removed non-Claude MCP upfront-load warning (context-cost only, zero functionality impact), fixed fullscreen
+ webview popup dark-screen via new-window → exitFullscreen so parent stays interactive, ErrorSlime extracted to shared component and
  rendered on all chat error cards (Network / Servers maxed / Plan limit / Subscription), Network issue classifier tightened to real errno
  codes + retry CTA removed since edit_message-based replay was truncating successful tool history — copy now directs user to send-new-message
   once WS auto-reconnects
2026-04-21 15:11:56 -07:00
ciregenz b9f7698b0c [eric] default-model + thinking-mode settings overhaul: Settings dropdown mirrors the in-session picker (provider-grouped from
state.models.byProvider, disambiguates same-named models by · Provider), toolbar now honors the stored default_model instead of snapping to
  stale Redux initial 'sonnet' and re-syncs on every reopen so last-used picks don't leak, smart fallback per priority Anthropic > OpenAI >
  Gemini > OpenSwarm Pro > OpenSwarm with Snackbar warning when the user's default becomes unreachable, new Default thinking mode setting
  (Auto/Off/Low/Medium/High) added to AppSettings and threaded into AgentSession on launch, onboarding flow for user intuitive-ness slight tweaks
2026-04-20 14:56:09 -07:00
ciregenz 301b0f7707 [eric] auto-heal corrupt npx cache in MCP stdio discovery: on ERR_MODULE_NOT_FOUND pointing into ~/.npm/_npx/<hash>/, wipe
that dir and retry once — fixes Discord/YouTube failing with "MCP stdio process exited unexpectedly" after partial npx installs,
  per-browser auto-close: spawned browser cards now disappear on their own sub-agent's completion instead of lingering until the parent agent
  finishes, WebSocketManager agent:status matches by session.browser_id (spawned_by is the parent, so it never matched the finishing
  sub-agent), user-created/pre-selected browsers untouched
2026-04-20 01:20:20 -07:00
ciregenz b469648e05 [eric] production push 1.0.23 2026-04-17 02:58:12 -07:00
ciregenz bb57a2aa51 [eric] passkey-not-supported dialog: intercept WebAuthn in agent browsers and surface a modal instead of letting the page hang on the passkey verifying spinner,
shim injected from main via contents.executeJavaScript (bypasses Trusted Types CSP), webview preload force-attached in will-attach-webview
2026-04-16 15:20:29 -07:00
ciregenz 828dfdb18b [eric] OpenSwarm Pro lifecycle fixes: cancel-in-grace shows access-until-X with Resubscribe, distinct ended and reconnect states, app-launch /sync reconciles
with Stripe, auto-revert to own_key on revoke/expire, PostHog identify segments events by plan, browser agent + capacity UX: browser sub-agents inherit the parent's Anthropic
  pick properly, spawned browser cards auto-close on natural completion, OpenSwarm-servers-maxed card with Discord waitlist CTA, auto-clear local subscription state on cloud
  revoke/expire
2026-04-16 13:56:34 -07:00
ciregenz 7eb85a7127 [eric] subscription UI fixes: cards no longer flicker to the Starting-subscription-service spinner mid-task (is_running TTL cache + retry/poll on mount), show
Anthropic as its own picker group alongside OpenSwarm Pro when both are connected so users can pick per-request
2026-04-16 11:12:27 -07:00
ciregenz 1a68ccfc7b [eric] OpenSwarm Pro: new managed plan alongside BYO — deep-link activation from billing checkout, onboarding + Settings card with live usage, gradient OpenSwarm Pro group in
the model picker, inline error cards for rate-limit/connection failures, debugger startup fix
2026-04-15 23:05:02 -07:00
ciregenz 14e1d02bbb [eric] reasoning UI + thinking-level controls: collapsible 'Thought for Ns' bubble with shimmer, per-session thinking level (off/low/med/high/auto) on
reasoning-capable models, gate GitHub Copilot as 'Coming soon', delete Twitter/xbird integration, fix model-picker first-click + 200K context cap on Sonnet/Opus, revive
  arrow-key dashboard nav after typing/clicking/zooming
2026-04-15 12:47:34 -07:00
ciregenz bc2ca1f33a [eric] multi-model polish: updated model registry, Gemini thought-signature fix, collapsible model picker, UI fixes 2026-04-12 20:49:33 -07:00
ciregenz 4778cea80e [eric] multi-model subscription support: connect ChatGPT Plus, Gemini Advanced, and GitHub Copilot subscriptions via 9Router
- Add BUILTIN_MODELS for OpenAI (GPT-5.4/Mini/5.3-Codex), Google (Gemini 3 Pro/Flash, 2.5 Pro/Flash), and GitHub Copilot
  - Add resolve_model_id_for_sdk() and resolve_aux_model() to route prefixed model IDs (cx/, gc/, gh/) through 9Router translator
  - Add GET /agents/models endpoint returning available models based on live 9Router connection state
  - Enable ENABLE_TOOL_SEARCH=auto for all providers so non-Claude models get full tool access (23 built-in + all MCPs)
  - Add thinking block streaming support (ThinkingBlock in stream handler + AssistantMessage) for reasoning models
  - Fix Gemini 3 thought-signature errors: use skip_thought_signature_validator per Google docs
  - Fix WebSearch blocked_domains/allowed_domains empty-list rejection on Anthropic API
  - Fix browser_agent text_parts UnboundLocalError on non-Claude models
  - Fix auxiliary LLM calls (title gen, group meta, dashboard naming, view builder, browser agent) via resolve_aux_model
  - Add Codex OAuth callback listener on port 1455 for ChatGPT Plus subscription connect
  - Route Gemini OAuth through system browser since Google blocks embedded webviews
  - Override Electron popup user-agent for OAuth
  - Fix duplicate OAuth callback with idempotent completed_oauth tracking
  - Fix Settings modal tab routing and stale warning banner
  - Add API key inputs for OpenAI, Google, and OpenRouter
  - Add MCP warning banner when selecting non-Claude model with many tools
  - Force session fork on cross-provider model switch to prevent transcript corruption
  - Disable GitHub Copilot subscription card (9Router poll issue, marked preview)
  - Delete dead CopilotProvider import and unused CopilotAuthButton component
2026-04-12 12:06:36 -07:00
ciregenz 7bd0346d21 [eric] 1.0.22 production release 2026-04-10 15:36:30 -07:00