Skip to content

feat: add API provider selection UI (Claude, Kimi, GLM, Ollama, Custom)#163

Merged
leonvanzyl merged 6 commits intoAutoForgeAI:masterfrom
nioasoft:feat/api-provider-ui
Feb 6, 2026
Merged

feat: add API provider selection UI (Claude, Kimi, GLM, Ollama, Custom)#163
leonvanzyl merged 6 commits intoAutoForgeAI:masterfrom
nioasoft:feat/api-provider-ui

Conversation

@nioasoft
Copy link

@nioasoft nioasoft commented Feb 6, 2026

Summary

  • API Provider Selection: Users can switch between Claude, Kimi, GLM, Ollama, and Custom providers directly from the Settings modal
  • Auth Token Security: Tokens stored locally only in ~/.autoforge/registry.db (never returned by API, write-only schema)
  • Fix Stuck Features: Features no longer get permanently stuck in in_progress when agents crash or hit rate limits. Existing stuck features are also cleaned up on next agent start.

Changes

API Provider UI (13 files)

  • registry.py - API_PROVIDERS dict, get_effective_sdk_env() builds provider-specific env vars
  • server/schemas.py - Provider settings Pydantic models with write-only auth token
  • server/routers/settings.py - REST endpoints for provider settings (GET returns api_has_auth_token: bool, never the actual value)
  • server/services/process_manager.py - Merges get_effective_sdk_env() into subprocess env
  • server/services/{spec,expand,assistant}_chat_session.py - All chat sessions use provider settings
  • env_constants.py - Added ANTHROPIC_AUTH_TOKEN to env var list
  • ui/src/components/SettingsModal.tsx - Provider selector with dynamic fields per provider
  • ui/src/hooks/useProjects.ts, ui/src/lib/api.ts, ui/src/lib/types.ts - Frontend API integration
  • .env.example - Documentation for new env vars

Fix Stuck Features

  • server/services/process_manager.py - _cleanup_stale_features() resets in_progress features in 4 scenarios:
    1. On start - cleans up stuck features from previous crashes before launching new agent
    2. On stop - cleans up when user clicks Stop
    3. On crash - cleans up when process exits unexpectedly
    4. On healthcheck - cleans up when dead process is detected

Test plan

  • Switch providers in Settings modal - verify fields change per provider
  • Set auth token - verify it's stored but never returned in API response
  • Start agent with non-default provider - verify subprocess receives correct env vars
  • Start agent on project with stuck features - verify they reset to pending on start
  • Start agent, wait for feature in_progress, click Stop - verify feature resets to pending
  • Simulate crash (kill -9 <pid>) - verify stuck features are cleaned up on next healthcheck

🤖 Generated with Claude Code

nioasoft and others added 6 commits February 5, 2026 21:08
All 5 WebSocket endpoints (expand, spec, assistant, terminal, project)
were closing the connection before calling accept() when validation
failed. Starlette converts pre-accept close into an HTTP 403, giving
clients no meaningful error information.

Server changes:
- Move websocket.accept() before all validation checks in every WS handler
- Send JSON error message before closing so clients get actionable errors
- Fix validate_project_name usage (raises HTTPException, not returns bool)
- ConnectionManager.connect() no longer calls accept() (caller's job)

Client changes:
- All 3 WS hooks (useWebSocket, useExpandChat, useSpecChat) skip
  reconnection on 4xxx close codes (application errors won't self-resolve)
- Gate expand button, keyboard shortcut, and modal on hasSpec
- Add hasSpec to useEffect dependency array to prevent stale closure
- Update keyboard shortcuts help text for E key context

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All WebSocket endpoints now call websocket.accept() before any
validation checks. Previously, closing the connection before accepting
caused Starlette to return an opaque HTTP 403 instead of a meaningful
error message.

Changes:
- Server: Accept WebSocket first, then send JSON error + close with
  4xxx code if validation fails (expand, spec, assistant, terminal,
  main project WS)
- Server: ConnectionManager.connect() no longer calls accept() to
  avoid double-accept
- UI: Gate expand button and keyboard shortcut on hasSpec
- UI: Skip WebSocket reconnection on application error codes (4000-4999)
- UI: Update keyboard shortcuts help text

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rash

API Provider Selection:
- Add provider switcher in Settings modal (Claude, Kimi, GLM, Ollama, Custom)
- Auth tokens stored locally only (registry.db), never returned by API
- get_effective_sdk_env() builds provider-specific env vars for agent subprocess
- All chat sessions (spec, expand, assistant) use provider settings
- Backward compatible: defaults to Claude, env vars still work as override

Fix Stuck Features:
- Add _cleanup_stale_features() to process_manager.py
- Reset in_progress features when agent stops, crashes, or fails healthcheck
- Prevents features from being permanently stuck after rate limit crashes
- Uses separate SQLAlchemy engine to avoid session conflicts with subprocess

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The provider refactor moved env building to get_effective_sdk_env(),
making these imports unused. Fixes ruff F401 lint errors in CI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ensures features stuck from a previous crash are reset before
launching a new agent, not just on stop/crash going forward.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
assistant_chat.py and spec_creation.py imported is_valid_project_name
(returns bool) aliased as validate_project_name. When used as
`project_name = validate_project_name(project_name)`, the project name
was replaced with True, causing "Project not found in registry" errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@leonvanzyl leonvanzyl merged commit d15fd37 into AutoForgeAI:master Feb 6, 2026
2 checks passed
@leonvanzyl
Copy link
Collaborator

Thanks

leonvanzyl added a commit that referenced this pull request Feb 6, 2026
- Fix model selection regression: _get_settings_defaults() now checks
  api_model (set by new provider UI) before falling back to legacy
  model setting, ensuring Claude model selection works end-to-end
- Add input validation for provider settings: api_base_url must start
  with http:// or https:// (max 500 chars), api_auth_token max 500
  chars, api_model max 200 chars
- Fix terminal.py misleading import alias: replace
  is_valid_project_name aliased as validate_project_name with direct
  is_valid_project_name import across all 5 call sites

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants