Conversation
Implements OpenRouter as an embedding provider option, enabling access to multiple embedding models (OpenAI, Google Gemini, Qwen3, Mistral) through a single API key. Backend changes: - Add validate_openrouter_api_key() for API key validation (sk-or-v1- format) - Add OpenRouterErrorAdapter for error sanitization - Add openrouter to valid providers in llm_provider_service - Create openrouter_discovery_service with hardcoded model list - Create /api/openrouter/models endpoint for model discovery - Register OpenRouter router in FastAPI main app Frontend changes: - Create openrouterService.ts for model discovery API client - Add OpenRouter to RAGSettings.tsx provider options - Configure default models with provider prefix (openai/text-embedding-3-small) - Add OpenRouter to embedding-capable providers list Documentation: - Update .env.example with OPENROUTER_API_KEY documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Tests cover: - Model list validation (non-empty, valid types) - Provider prefix validation (all models have provider/) - Data validation (positive dimensions, non-negative pricing) - Provider validation (valid provider names) - Specific provider models (OpenAI, Qwen) - Model ID validation (requires prefix) All 11 tests passing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Warning Rate limit exceeded@leex279 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 22 minutes and 38 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
WalkthroughAdds OpenRouter embedding support: frontend UI and service, backend discovery service and API route, API key validation, provider error adapter, credential/provider wire-ups, and unit tests for discovery and model validation. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as Frontend UI
participant FrontendSvc as openrouterService
participant BackendAPI as /api/openrouter/models
participant DiscoverySvc as OpenRouterDiscoveryService
UI->>FrontendSvc: discoverModels()
activate FrontendSvc
FrontendSvc->>FrontendSvc: check sessionStorage cache (5m TTL)
alt cache hit
FrontendSvc-->>UI: return cached models
else cache miss
FrontendSvc->>BackendAPI: GET /api/openrouter/models
activate BackendAPI
BackendAPI->>DiscoverySvc: discover_embedding_models()
activate DiscoverySvc
DiscoverySvc-->>BackendAPI: return hardcoded model list
deactivate DiscoverySvc
BackendAPI-->>FrontendSvc: OpenRouterModelListResponse (with total_count)
deactivate BackendAPI
FrontendSvc->>FrontendSvc: cache response in sessionStorage (5m TTL)
FrontendSvc-->>UI: return models
end
deactivate FrontendSvc
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Changed grid-cols-3 to grid-cols-4 for embedding provider selection so all 4 embedding-capable providers (OpenAI, Google, OpenRouter, Ollama) fit on one line, matching the chat provider layout. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
archon-ui-main/src/services/openrouterService.ts (2)
26-26: Consider lazy initialization of baseUrl.The
baseUrlis initialized once at class instantiation. If the API URL can change at runtime (e.g., via environment variable changes or configuration updates), this could cause stale URL issues.Consider fetching the URL per-request:
- private baseUrl = getApiUrl(); + private getBaseUrl = () => getApiUrl();And update the fetch call on line 104:
- const response = await fetch(`${this.baseUrl}/api/openrouter/models`, { + const response = await fetch(`${this.getBaseUrl()}/api/openrouter/models`, {
96-125: LGTM with minor suggestion: Consider validating response structure.The API call correctly implements cache-first pattern and error handling. However,
response.json()on line 116 doesn't validate the returned structure matchesOpenRouterModelListResponse.Consider adding runtime validation:
const data = await response.json(); + + // Validate response structure + if (!data.embedding_models || !Array.isArray(data.embedding_models)) { + throw new Error("Invalid response structure from OpenRouter API"); + } // Cache the successful response this.cacheModels(data);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
.env.example(1 hunks)PRPs/openrouter-embeddings-support.md(1 hunks)archon-ui-main/src/components/settings/RAGSettings.tsx(3 hunks)archon-ui-main/src/services/openrouterService.ts(1 hunks)python/src/server/api_routes/openrouter_api.py(1 hunks)python/src/server/config/config.py(1 hunks)python/src/server/main.py(2 hunks)python/src/server/services/embeddings/provider_error_adapters.py(5 hunks)python/src/server/services/llm_provider_service.py(5 hunks)python/src/server/services/openrouter_discovery_service.py(1 hunks)python/tests/test_openrouter_discovery.py(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
python/src/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
python/src/**/*.py: On service startup, missing configuration, DB connection failures, auth/authorization failures, critical dependency outages, or invalid/corrupting data: fail fast and bubble errors
For batch processing, background tasks, WebSocket events, optional features, and external API calls: continue processing but log errors (with retries/backoff for APIs)
Never accept or persist corrupted data; skip failed items entirely (e.g., zero embeddings, null FKs, malformed JSON)
Error messages must include operation context, IDs/URLs, use specific exception types, preserve full stack traces (logging with exc_info=True), and avoid returning None/null—raise exceptions instead; for batches report success counts and detailed failures
Backend code targets Python 3.12 and adheres to a 120 character line length
Use Ruff for linting (errors, warnings, unused imports) in backend code
Use Mypy for static type checking in backend code
Files:
python/src/server/services/openrouter_discovery_service.pypython/src/server/services/embeddings/provider_error_adapters.pypython/src/server/config/config.pypython/src/server/main.pypython/src/server/api_routes/openrouter_api.pypython/src/server/services/llm_provider_service.py
archon-ui-main/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
archon-ui-main/src/**/*.{ts,tsx}: Frontend TypeScript must use strict mode with no implicit any
Use TanStack Query for all data fetching; avoid prop drilling
Use database values directly in the frontend; avoid mapping layers between BE and FE types
Files:
archon-ui-main/src/services/openrouterService.tsarchon-ui-main/src/components/settings/RAGSettings.tsx
🧠 Learnings (3)
📓 Common learnings
Learnt from: Chillbruhhh
Repo: coleam00/Archon PR: 736
File: archon-ui-main/src/components/settings/RAGSettings.tsx:17-19
Timestamp: 2025-09-25T16:36:48.527Z
Learning: OpenRouter does not provide embedding models - it only acts as a proxy/router for various LLM providers for chat completions, not embeddings. The EMBEDDING_CAPABLE_PROVIDERS array in RAGSettings.tsx correctly excludes 'openrouter'.
📚 Learning: 2025-09-25T16:36:48.527Z
Learnt from: Chillbruhhh
Repo: coleam00/Archon PR: 736
File: archon-ui-main/src/components/settings/RAGSettings.tsx:17-19
Timestamp: 2025-09-25T16:36:48.527Z
Learning: OpenRouter does not provide embedding models - it only acts as a proxy/router for various LLM providers for chat completions, not embeddings. The EMBEDDING_CAPABLE_PROVIDERS array in RAGSettings.tsx correctly excludes 'openrouter'.
Applied to files:
python/src/server/services/openrouter_discovery_service.pypython/src/server/services/embeddings/provider_error_adapters.pyarchon-ui-main/src/services/openrouterService.tsarchon-ui-main/src/components/settings/RAGSettings.tsxPRPs/openrouter-embeddings-support.md
📚 Learning: 2025-09-19T10:32:55.580Z
Learnt from: CR
Repo: coleam00/Archon PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-19T10:32:55.580Z
Learning: Applies to .env : Require SUPABASE_URL and SUPABASE_SERVICE_KEY in .env
Applied to files:
.env.example
🔇 Additional comments (19)
.env.example (1)
128-129: LGTM! Clear documentation for OpenRouter API key.The documentation format is consistent with other API key entries and provides helpful information about the key format and where to obtain it.
python/src/server/config/config.py (1)
69-79: LGTM! Validation follows established patterns.The
validate_openrouter_api_keyfunction correctly validates the OpenRouter API key format and provides clear error messages that include the URL for obtaining keys.archon-ui-main/src/components/settings/RAGSettings.tsx (2)
45-45: Provider-prefixed model ID is consistent with backend validation.Assuming OpenRouter embedding support is confirmed, the provider-prefixed model ID format (
openai/text-embedding-3-small) correctly aligns with the backend'sOpenRouterEmbeddingModelvalidation that requires provider prefixes.
18-18: The review comment is incorrect and should be disregarded.OpenRouter supports embeddings with a /v1/embeddings endpoint, contradicting the stored learning from September 2025. The stored learning's claim that "OpenRouter does not provide embedding models" is outdated. Embedding models are available, making the addition of 'openrouter' to EMBEDDING_CAPABLE_PROVIDERS correct and appropriate.
Likely an incorrect or invalid review comment.
python/src/server/main.py (1)
29-29: LGTM! Standard router registration pattern.The OpenRouter router import and registration follow the established pattern used for other API routers in the application.
Also applies to: 191-191
python/src/server/services/llm_provider_service.py (1)
658-659: LGTM! Provider prefix aligns with backend validation.The change to include the provider prefix (
openai/text-embedding-3-small) for OpenRouter is consistent with theOpenRouterEmbeddingModelvalidation that requires model IDs to contain provider prefixes. The comment clearly documents this requirement.python/src/server/api_routes/openrouter_api.py (1)
14-27: LGTM! Clean API endpoint implementation.The endpoint implementation is straightforward, properly typed with Pydantic response models, and follows FastAPI conventions. The async implementation is appropriate for the discovery service call.
python/tests/test_openrouter_discovery.py (1)
1-158: LGTM! Comprehensive test coverage for OpenRouter discovery.The test suite thoroughly validates:
- Model list structure and content
- Provider prefix requirements (critical for OpenRouter)
- Data type and range constraints (dimensions, pricing, context_length)
- Presence of expected models (OpenAI, Qwen)
- Model ID validation logic
The tests are well-documented and provide excellent coverage for the discovery service.
python/src/server/services/openrouter_discovery_service.py (1)
1-137: The stored learning is outdated; OpenRouter now supports embeddings. No issues found.OpenRouter exposes an embeddings API (POST /api/v1/embeddings), and model IDs use a provider-prefix format such as "openai/text-embedding-3-small"—which the implementation correctly follows. All providers and models listed in the code (OpenAI, Google, Qwen, Mistral) are supported through OpenRouter's embeddings endpoint.
The code's hardcoded approach is already flagged in its own docstring as a temporary solution pending an OpenRouter models endpoint. The service is not currently integrated into the codebase.
archon-ui-main/src/services/openrouterService.ts (3)
10-18: LGTM: Type definitions match backend models.The
OpenRouterEmbeddingModelinterface correctly mirrors the Python backend model with all required fields properly typed.
30-54: LGTM: Comprehensive error handling with good categorization.The error handling properly differentiates network errors, timeouts, and generic errors with user-friendly messages.
59-91: LGTM: Robust caching implementation with appropriate error handling.The caching logic correctly implements TTL checking and cleanup. Silent error handling for cache operations (lines 73-75, 88-90) is appropriate since cache failures shouldn't break functionality.
python/src/server/services/embeddings/provider_error_adapters.py (3)
114-139: LGTM: OpenRouterErrorAdapter follows established patterns.The adapter correctly implements sanitization for OpenRouter-specific patterns including
sk-or-v1-API keys, OpenRouter URLs, and Bearer tokens. The structure is consistent with existing adapters.
145-150: LGTM: OpenRouter adapter correctly registered in factory.The adapter is properly added to the
_adaptersdictionary following the existing pattern.
170-172: LGTM: Provider detection correctly prioritizes OpenRouter.The detection logic appropriately checks OpenRouter first to avoid false positives when model names contain "openai". The comment on line 170 clearly explains the reasoning.
PRPs/openrouter-embeddings-support.md (4)
1-75: LGTM: Comprehensive documentation with clear goals and success criteria.The PRP provides excellent context for the feature implementation with quantified benefits and clear success criteria.
253-557: LGTM: Detailed implementation blueprint with valuable gotchas.The implementation patterns and gotchas (especially around model name prefixes and base URLs) provide excellent guidance. The Pydantic validation ensuring provider prefixes (lines 274-280) is a critical safeguard.
599-794: LGTM: Thorough validation strategy with practical anti-patterns.The multi-level validation approach and anti-patterns section (lines 782-793) provide excellent guidance for avoiding common mistakes. The manual testing checklist aligns well with the PR's test plan.
90-94: Verify OpenRouter embeddings API exists.The documentation references OpenRouter's embeddings API documentation, but per learnings from September 2025, OpenRouter was documented as NOT supporting embeddings—only chat completions.
This inconsistency was flagged at the start of the review. Please confirm that OpenRouter has added embeddings support since September 2025 before proceeding with this PR.
Added 'openrouter' to embedding_capable_providers set in credential_service.py to prevent it from being rejected and falling back to OpenAI. Fixes: 'Invalid embedding provider openrouter doesn't support embeddings' error 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1. Lazy initialization of baseUrl via getBaseUrl() method - Allows API URL to be updated at runtime without stale URL issues 2. Runtime validation of API response structure - Validates embedding_models array exists before caching - Prevents invalid responses from being cached Addresses CodeRabbit nitpick comments on PR #852 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
archon-ui-main/src/services/openrouterService.ts (1)
118-121: Consider more comprehensive response validation.The current validation only checks that
embedding_modelsexists and is an array. Consider validating:
- Individual model structure (required fields like
id,provider,dimensions, etc.)- The
total_countfield matchesembedding_models.length- Basic sanity checks (e.g., positive dimensions, valid provider names)
This would catch malformed responses early and provide better error messages.
Example validation:
// Validate response structure if (!data.embedding_models || !Array.isArray(data.embedding_models)) { throw new Error("Invalid response structure from OpenRouter API"); } if (typeof data.total_count !== "number" || data.total_count < 0) { throw new Error("Invalid total_count in response"); } // Validate at least one model has required fields if (data.embedding_models.length > 0) { const model = data.embedding_models[0]; if (!model.id || !model.provider || typeof model.dimensions !== "number") { throw new Error("Invalid model structure in response"); } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
archon-ui-main/src/services/openrouterService.ts(1 hunks)python/src/server/services/credential_service.py(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
archon-ui-main/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
archon-ui-main/src/**/*.{ts,tsx}: Frontend TypeScript must use strict mode with no implicit any
Use TanStack Query for all data fetching; avoid prop drilling
Use database values directly in the frontend; avoid mapping layers between BE and FE types
Files:
archon-ui-main/src/services/openrouterService.ts
python/src/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
python/src/**/*.py: On service startup, missing configuration, DB connection failures, auth/authorization failures, critical dependency outages, or invalid/corrupting data: fail fast and bubble errors
For batch processing, background tasks, WebSocket events, optional features, and external API calls: continue processing but log errors (with retries/backoff for APIs)
Never accept or persist corrupted data; skip failed items entirely (e.g., zero embeddings, null FKs, malformed JSON)
Error messages must include operation context, IDs/URLs, use specific exception types, preserve full stack traces (logging with exc_info=True), and avoid returning None/null—raise exceptions instead; for batches report success counts and detailed failures
Backend code targets Python 3.12 and adheres to a 120 character line length
Use Ruff for linting (errors, warnings, unused imports) in backend code
Use Mypy for static type checking in backend code
Files:
python/src/server/services/credential_service.py
🧠 Learnings (2)
📓 Common learnings
Learnt from: Chillbruhhh
Repo: coleam00/Archon PR: 736
File: archon-ui-main/src/components/settings/RAGSettings.tsx:17-19
Timestamp: 2025-09-25T16:36:48.527Z
Learning: OpenRouter does not provide embedding models - it only acts as a proxy/router for various LLM providers for chat completions, not embeddings. The EMBEDDING_CAPABLE_PROVIDERS array in RAGSettings.tsx correctly excludes 'openrouter'.
📚 Learning: 2025-09-25T16:36:48.527Z
Learnt from: Chillbruhhh
Repo: coleam00/Archon PR: 736
File: archon-ui-main/src/components/settings/RAGSettings.tsx:17-19
Timestamp: 2025-09-25T16:36:48.527Z
Learning: OpenRouter does not provide embedding models - it only acts as a proxy/router for various LLM providers for chat completions, not embeddings. The EMBEDDING_CAPABLE_PROVIDERS array in RAGSettings.tsx correctly excludes 'openrouter'.
Applied to files:
archon-ui-main/src/services/openrouterService.tspython/src/server/services/credential_service.py
🧬 Code graph analysis (1)
archon-ui-main/src/services/openrouterService.ts (2)
python/src/server/services/openrouter_discovery_service.py (2)
OpenRouterEmbeddingModel(10-27)OpenRouterModelListResponse(30-34)archon-ui-main/src/config/api.ts (1)
getApiUrl(9-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Backend Tests (Python + pytest)
🔇 Additional comments (5)
archon-ui-main/src/services/openrouterService.ts (4)
10-23: LGTM!The type definitions correctly match the Python backend models from
openrouter_discovery_service.py. The interface structure ensures type safety for the API responses.
30-54: LGTM!The error handling provides good categorization of network, timeout, and general errors with contextual messages. The type-safe handling of
unknownerror types is appropriate.
81-91: LGTM!The cache storage implementation is clean and appropriately fails silently on errors, which is correct behavior for a non-critical caching layer.
135-145: LGTM!The cache clearing method and singleton export follow standard patterns. Silent error handling in cache operations is appropriate for non-critical functionality.
python/src/server/services/credential_service.py (1)
446-446: OpenRouter embeddings support confirmed — no issues found.OpenRouter added embeddings endpoints with a POST /api/v1/embeddings endpoint and TypeScript SDK support for embeddings.generate (docs updated Nov 2025). The September 2025 learning is now outdated. Adding
"openrouter"to the embedding-capable providers set is correct and valid.
Implemented comprehensive validation to prevent crashes from corrupted cache: - Created isCacheEntry() type guard to validate cache structure - Parse JSON into unknown type (TypeScript strict mode compliant) - Validate timestamp is number and data has OpenRouterModelListResponse shape - Validate each model has all required fields with correct types - Remove corrupted cache entries to avoid repeated failures - No 'any' types used, full strict mode compliance Prevents crashes from malformed cache data while maintaining type safety. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Enhanced validation to catch malformed responses early: - Validate total_count is non-negative number - Verify total_count matches embedding_models.length - Validate first model has required fields (id, provider, dimensions) - Check dimensions are positive numbers - Validate provider names are from expected set - Provide specific error messages for each validation failure Prevents caching invalid data and provides better debugging information. Addresses CodeRabbit nitpick comment on PR #852 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
When will this get merged into the |
|
@spencerthayer thanks for reminding. I asked in the team if someone has time to review it soon, so we can merge. If you tested test PR yourself, would be great to get your feedback here. |
Add per-project environment variable management as a first-class config primitive. Env vars defined in .archon/config.yaml or stored in DB via Web UI are merged into Options.env on Claude SDK calls. Three env var sources merge in priority order (later wins): 1. process.env — global, from ~/.archon/.env via dotenv 2. .archon/config.yaml env: section — file-based per-project 3. DB remote_agent_codebase_env_vars table — Web UI per-project Changes: - Add remote_agent_codebase_env_vars table (PG migration + SQLite schema) - Add DB CRUD module (packages/core/src/db/env-vars.ts) - Extend IWorkflowStore with getCodebaseEnvVars method - Add env field to RepoConfig, MergedConfig, WorkflowConfig, WorkflowAssistantOptions, AssistantRequestOptions - Merge DB env vars in executor after config load - Inject env vars into Claude subprocess via Options.env - Add 3 API routes (GET/PUT/DELETE /api/codebases/:id/env) - Add EnvVarsPanel to Settings page with masked value display Fixes #852
) Add per-project environment variable management as a first-class config primitive. Env vars defined in .archon/config.yaml or stored in DB via Web UI are merged into Options.env on Claude SDK calls. Three env var sources merge in priority order (later wins): 1. process.env — global, from ~/.archon/.env via dotenv 2. .archon/config.yaml env: section — file-based per-project 3. DB remote_agent_codebase_env_vars table — Web UI per-project Changes: - Add remote_agent_codebase_env_vars table (PG migration + SQLite schema) - Add DB CRUD module (packages/core/src/db/env-vars.ts) - Extend IWorkflowStore with getCodebaseEnvVars method - Add env field to RepoConfig, MergedConfig, WorkflowConfig, WorkflowAssistantOptions, AssistantRequestOptions - Merge DB env vars in executor after config load - Inject env vars into Claude subprocess via Options.env - Add 3 API routes (GET/PUT/DELETE /api/codebases/:id/env) - Add EnvVarsPanel to Settings page with masked value display Fixes coleam00#852
…gration (#12) * Remove Docusaurus documentation system Remove the standalone Docusaurus documentation website to simplify the project structure and reduce maintenance overhead. Changes: - Delete /docs directory (480MB freed) containing all Docusaurus files - Remove docker-compose.docs.yml (optional docs service) - Remove ARCHON_DOCS_PORT from .env.example - Update .github/workflows/release-notes.yml (remove docs section) - Update .github/test-release-notes.sh (remove docs section) Preserved: - Project documents feature (archon-ui-main/src/features/projects/documents/) - Backend document service (python/src/server/services/projects/document_service.py) - Project documents API endpoints (/api/projects/{id}/docs) Benefits: - Eliminates redundancy (content duplicated in /PRPs/ai_docs/) - Reduces complexity (removes 480MB dependencies and configuration) - Simplifies deployment (eliminates optional Docker service on port 3838) - Lowers maintenance burden (single documentation source) All validation tests passed: ✓ File system validation ✓ Backend imports verification ✓ Docker Compose integration testing ✓ CI/CD workflow validation ✓ Project documents API still functional 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add OpenRouter embeddings support Implements OpenRouter as an embedding provider option, enabling access to multiple embedding models (OpenAI, Google Gemini, Qwen3, Mistral) through a single API key. Backend changes: - Add validate_openrouter_api_key() for API key validation (sk-or-v1- format) - Add OpenRouterErrorAdapter for error sanitization - Add openrouter to valid providers in llm_provider_service - Create openrouter_discovery_service with hardcoded model list - Create /api/openrouter/models endpoint for model discovery - Register OpenRouter router in FastAPI main app Frontend changes: - Create openrouterService.ts for model discovery API client - Add OpenRouter to RAGSettings.tsx provider options - Configure default models with provider prefix (openai/text-embedding-3-small) - Add OpenRouter to embedding-capable providers list Documentation: - Update .env.example with OPENROUTER_API_KEY documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add unit tests for OpenRouter model discovery Tests cover: - Model list validation (non-empty, valid types) - Provider prefix validation (all models have provider/) - Data validation (positive dimensions, non-negative pricing) - Provider validation (valid provider names) - Specific provider models (OpenAI, Qwen) - Model ID validation (requires prefix) All 11 tests passing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix embedding provider grid to fit all providers in one line Changed grid-cols-3 to grid-cols-4 for embedding provider selection so all 4 embedding-capable providers (OpenAI, Google, OpenRouter, Ollama) fit on one line, matching the chat provider layout. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix credential_service to recognize OpenRouter as embedding provider Added 'openrouter' to embedding_capable_providers set in credential_service.py to prevent it from being rejected and falling back to OpenAI. Fixes: 'Invalid embedding provider openrouter doesn't support embeddings' error 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Address CodeRabbit review: Improve openrouterService robustness 1. Lazy initialization of baseUrl via getBaseUrl() method - Allows API URL to be updated at runtime without stale URL issues 2. Runtime validation of API response structure - Validates embedding_models array exists before caching - Prevents invalid responses from being cached Addresses CodeRabbit nitpick comments on PR coleam00#852 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Delete PRPs/openrouter-embeddings-support.md * Add robust cache validation with type guards in openrouterService Implemented comprehensive validation to prevent crashes from corrupted cache: - Created isCacheEntry() type guard to validate cache structure - Parse JSON into unknown type (TypeScript strict mode compliant) - Validate timestamp is number and data has OpenRouterModelListResponse shape - Validate each model has all required fields with correct types - Remove corrupted cache entries to avoid repeated failures - No 'any' types used, full strict mode compliance Prevents crashes from malformed cache data while maintaining type safety. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add comprehensive API response validation in discoverModels Enhanced validation to catch malformed responses early: - Validate total_count is non-negative number - Verify total_count matches embedding_models.length - Validate first model has required fields (id, provider, dimensions) - Check dimensions are positive numbers - Validate provider names are from expected set - Provide specific error messages for each validation failure Prevents caching invalid data and provides better debugging information. Addresses CodeRabbit nitpick comment on PR coleam00#852 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Update README for Supabase service role key instructions (coleam00#836) * chore(security): add CODEOWNERS and Dependabot configuration Adds repository security files: - CODEOWNERS for PR review routing - dependabot.yml for automated security updates 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(hardened): Add nested submodule integrations for standalone operation - Add .gitmodules with 7 nested integrations: - PMOVES-Agent-Zero (agent orchestration) - PMOVES-BoTZ (MCP tools) - PMOVES-HiRAG (knowledge retrieval) - PMOVES-Deep-Serch (deep research) - docling (document processing) - PMOVES-BotZ-gateway (MCP gateway) - PMOVES-tensorzero (TensorZero client) - Fix PydanticAI Agent initialization (remove invalid result_type parameter) Enables Archon to run standalone with PMOVES.AI service connections. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(pmoves): add Claude Code MCP adapter for PMOVES.AI integration New module: python/pmoves_mcp/ - claude_code_adapter.py: Async MCP adapter for Claude Code CLI - __init__.py: Module exports Features: - Execute TAC slash commands via Agent Zero's MCP interface - ClaudeCodeMCPAdapter with async httpx client - CommandResult dataclass for structured responses - ARCHON_MCP_TOOLS registration for Archon integration Available commands through adapter: - /search:hirag, /search:supaserch, /search:deepresearch - /health:check-all, /health:metrics - /agents:status, /agents:mcp-query - /deploy:smoke-test, /deploy:services, /deploy:up - /botz:init, /botz:profile, /botz:mcp, /botz:secrets 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Restore fail-fast behavior for API key validation in upload - Remove HTTPException catch that was allowing uploads to proceed with invalid credentials - Aligns with beta guidelines: authentication failures should halt execution - Addresses code review feedback from PR #1 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore(deps): Update uv.lock with dependency revisions - Bump revision from 1 to 3 - Add upload-time fields for PyPI packages - Sync with latest uv dependency resolution 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(observability): add Prometheus metrics endpoint Add /metrics endpoint for Prometheus scraping with: - HTTP request counter (by method, endpoint, status) - HTTP request duration histogram - Knowledge operations counter - MCP commands execution counter 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(search): Add Hi-RAG v2 semantic expansion to keyword extraction - Add optional Hi-RAG v2 integration for knowledge-aware keyword discovery - Enable semantic keyword expansion via PMOVES knowledge graph - Add hirag_url parameter to KeywordExtractor for knowledge graph queries - Improves search relevance with ontology-driven term expansion 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(pmoves-ai): Add PMOVES.AI integration patterns (#3) * feat(pmoves-ai): Add PMOVES.AI integration patterns - Add CHIT secrets manifest (chit/secrets_manifest_v2.yaml) - Add tier-based environment loading (env.shared, env.tier-agent.sh) - Add health check module (pmoves_health/) - Add NATS service announcer (pmoves_announcer/) - Add service registry client (pmoves_registry/) - Add Docker Compose YAML anchors (docker-compose.pmoves.yml) - Add integration documentation (PMOVES.AI_INTEGRATION.md) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(integration): Apply Phase 1 critical bug fixes - Fix deprecated datetime.utcnow() → datetime.now(timezone.utc) - Fix YAML environment merge (list → map for proper merging) - Fix health check decorator accumulation bug - Fix health endpoint status codes (return 503 when unhealthy) - Remove APP/UI tiers (stick to 6-tier architecture) - Fix resource leaks in NATS connections (try/finally) * fix(security): Remove hardcoded credential defaults - Neo4j: Remove neo4j:neo4j default credentials - MinIO: Remove minioadmin:minioadmin default credentials - ClickHouse: Remove tensorzero:tensorzero default credentials - Fix typo: export_CACHE_TTL → export CACHE_TTL Empty defaults now require explicit configuration for production use. * refactor(code-quality): Phase 3 & 4 improvements Phase 3: Code Quality - Add pmoves_common shared types module (ServiceTier, HealthStatus) - Update ServiceTier imports with fallback to shared module - Remove duplicate ServiceTier enum definitions Phase 4: Documentation - Add comprehensive module docstrings to all integration modules - Create .coderabbit.yaml for automated PR reviews - Enable reviews on feat/* and fix/* branches - Set docstring coverage target to 80% This reduces code duplication and improves type consistency across the PMOVES.AI ecosystem. --------- Co-authored-by: POWERFULMOVES <POWERFULMOVES@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * chore: Add GitHub Actions workflows and update submodule SHAs - Add CI/CD workflows: ci.yml, claude-fix.yml, claude-review.yml, release-notes.yml - Update submodule references to latest commits 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(pr): Address CodeRabbit review issues - Fix dependabot.yml: Point pip to /python, npm to /archon-ui-main - Add branch = main to docling submodule in .gitmodules - Add prometheus-client>=0.20.0 to all dependency group 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: Sync main to hardened - MCP adapter, CODEOWNERS, nested submodules, persona service Syncs 4 commits from main to PMOVES.AI-Edition-Hardened: - Claude Code MCP adapter for PMOVES.AI integration - CODEOWNERS configuration (security) - Nested submodule integrations for standalone operation - Persona service and API routes for agent creation Includes CodeRabbit review fixes: - Fixed route ordering (/thread-types before /{persona_id}) - Added proper error handling and validation - Removed Git conflict markers - Fixed .coderabbit.yaml configuration 🤖 Generated with Claude Code * docs: add PMOVES.AI skill hints context tags Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore(submodules): update nested PMOVES-HiRAG submodule pointer * security: update PBKDF2 iterations to 600,000 * fix: correct indentation in state_reconciliation.py if-block * fix(env): strip export syntax and add NATS auth to env.shared defaults - Remove `export` prefix from all variables (incompatible with Docker env_file) - Update NATS_URL default to include pmoves credentials - Update usage comment to reflect Docker Compose env_file pattern Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs(claude): add CHIT-aware integration context (#9) Co-authored-by: Shaela Bello <slbello@uncg.edu> * fix(auth): align NATS default URLs with credentialed runtime (#10) Co-authored-by: Shaela Bello <slbello@uncg.edu> * chore(submodules): sync HiRAG and BotZ gateway pointers (#11) Co-authored-by: Shaela Bello <slbello@uncg.edu> * fix(security): add USER directive to archon-ui Dockerfile Run as non-root user (uid 65532) to satisfy BuildKit audit and defense-in-depth container hardening requirements. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(github): add GitHub App token minting and client Implements GitHub App integration for agent work orders with: - Token minting with JWT RS256 signing (10-min lifetime) - Installation token exchange via GitHub API - Token caching with 50-minute expiry window - GitHubClient with App token + gh CLI fallback - Full test coverage for token minting and PR operations Environment variables required: - GH_APP_ID: GitHub App numeric ID - GH_APP_SEC: PEM private key (handles double-escaped env values) - GH_APP_INSTALLATION_ID: Installation ID for org access Key features: - mint_installation_token(): Creates short-lived JWT + exchanges for token - get_installation_token(): Cached token retrieval with force_refresh option - clear_token_cache(): Manual cache invalidation - GitHubClient.list_pull_requests(): API-first with CLI fallback - Graceful degradation when credentials unavailable Security considerations: - PEM keys stored in env.tier-agent (plaintext - production hardening needed) - No persistent token storage (in-memory cache only) - Short-lived tokens (JWT <10min, installation tokens = 1 hour) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(submodules): promote nested submodule pointers (HiRAG, BotZ-gateway) - external/PMOVES-HiRAG: 89d4abf→e904b12 (CHIT + geometry bus context, PR #4) - pmoves_multi_agent_pro_pack/PMOVES-BotZ-gateway: 40e1e33→2565022 (log sanitizer, PR #4) Both commits are merged on their respective origin/main branches. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(submodules): recover nested wipes + promote BoTZ skill pointers - Recovered 3 wiped nested subs: Deep-Serch (88 files), tensorzero (2906 files), docling (839 files) — same wipe pattern as Phase 5 - Recovered 6 wiped sub-sub-subs inside nested BoTZ copy - Promoted 7 skill repo pointer advances in nested BoTZ copy Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: leex279 <thomas@thirty3.de> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: sean-eskerium <sean@eskerium.com> Co-authored-by: Jason Pickens <jasonpickensnz@gmail.com> Co-authored-by: POWERFULMOVES <POWERFULMOVES@users.noreply.github.com> Co-authored-by: PMOVES.AI <claude@pmoves.ai> Co-authored-by: Shaela Bello <slbello@uncg.edu>
) Add per-project environment variable management as a first-class config primitive. Env vars defined in .archon/config.yaml or stored in DB via Web UI are merged into Options.env on Claude SDK calls. Three env var sources merge in priority order (later wins): 1. process.env — global, from ~/.archon/.env via dotenv 2. .archon/config.yaml env: section — file-based per-project 3. DB remote_agent_codebase_env_vars table — Web UI per-project Changes: - Add remote_agent_codebase_env_vars table (PG migration + SQLite schema) - Add DB CRUD module (packages/core/src/db/env-vars.ts) - Extend IWorkflowStore with getCodebaseEnvVars method - Add env field to RepoConfig, MergedConfig, WorkflowConfig, WorkflowAssistantOptions, AssistantRequestOptions - Merge DB env vars in executor after config load - Inject env vars into Claude subprocess via Options.env - Add 3 API routes (GET/PUT/DELETE /api/codebases/:id/env) - Add EnvVarsPanel to Settings page with masked value display Fixes coleam00#852
Summary
Closes #851
This PR adds OpenRouter as a first-class embedding provider, enabling users to access multiple embedding models (OpenAI, Google Gemini, Qwen3, Mistral) through a single unified API.
Backend Changes
validate_openrouter_api_key()to config.py (validatessk-or-v1-format)OpenRouterErrorAdapterfor API key sanitization in error messagesopenrouteras valid provider inllm_provider_service.pyopenrouter_discovery_service.pywith hardcoded model metadata/api/openrouter/modelsendpoint for model discovery.env.examplewith OPENROUTER_API_KEY documentationFrontend Changes
openrouterService.tswith session storage caching (5-minute TTL)EMBEDDING_CAPABLE_PROVIDERSin RAGSettingsopenai/text-embedding-3-small)Testing
Benefits
Implementation Details
openai/text-embedding-3-large)sk-or-v1-*patterns from logsTest Plan
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Improvements