* fix(kimi): resolve Kimi Code API 403 errors and User-Agent restrictions
Kimi Code subscription keys require a whitelisted coding-agent User-Agent to avoid access_terminated_error 403s. This adds User-Agent probing and caching for Kimi Code endpoints.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(kimi): omit temperature for kimi-for-coding API calls
Kimi Code rejects any non-default temperature with HTTP 400, which broke deep research probes and low-temp LLM rounds.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat: Add ChatGPT Subscription support and related features
- Introduced a new provider option for ChatGPT Subscription in the endpoint selection UI.
- Implemented OAuth flow for ChatGPT Subscription sign-in, including polling for authorization status.
- Updated admin interface to handle ChatGPT Subscription, including disabling API key input and providing user guidance.
- Enhanced cost tracking logic to differentiate between subscription and non-subscription endpoints.
- Added new slash commands for managing skills, including listing, searching, and invoking skills.
- Implemented caching for skill catalog to optimize performance.
- Updated tests to cover new ChatGPT Subscription functionality and ensure proper endpoint probing.
- Refactored existing code to accommodate new features and improve maintainability.
* refactor: share provider device-flow setup
- reuse one device-flow backend for Copilot and ChatGPT Subscription
- add one frontend device-flow helper for Settings and /setup
- put GitHub Copilot back into Add Models, now as a dropdown option
- make provider selection just select; clicking Add starts sign-in
- stop ChatGPT Subscription setup from opening auth tabs automatically
- make /setup copilot and /setup chatgpt-subscription work from chat
- show ChatGPT Subscription in the /setup suggestions
- show the real error message when setup fails
- add focused tests for the shared flow and setup UI
* feat(chatgpt-subscription): harden credential lifecycle and streamline auth UX
Backend:
- Resolve runtime bearer for provider-auth endpoints at probe time via a
shared _resolve_probe_key() that delegates to resolve_endpoint_runtime,
applied across all probe/refresh call sites.
- Skip live completion probes and health pings for discovery-only providers
(centralized behind _is_discovery_only_provider) — the Codex/Responses API
has no such endpoints, so status is derived from cached models.
- Never persist the short lived ChatGPT bearer to the plaintext sessions
table; proactively clear any stale bearer left by an earlier code path.
- Revoke orphaned ProviderAuthSession credentials when the last endpoint
backing them is deleted (_delete_orphaned_provider_auth), surfaced via
cleared_provider_auth in the delete response.
Frontend (admin.js):
- Auto-start the device-auth flow on provider selection so the authorization
panel (code + Authorize) shows immediately instead of behind a "Sign in" click.
- Remove the redundant top button for device auth providers, move retry
into the panel via an inline "Try again".
- Drop the self-evident hint text and add an execCommand clipboard fallback so
Copy works in non-secure (HTTP/LAN) contexts.
* fix: harden chatgpt subscription provider
* chore: remove PR media from branch
* Fix chatgpt subscription recovery and token handling
---------
Co-authored-by: 5p00kyy <admin@5p00ky.dev>
- Add OpenCode Zen (https://opencode.ai/zen/v1) and Go (https://opencode.ai/zen/go/v1)
- Add provider detection via _host_match() in llm_core.py
- Add curated model list entries in model_routes.py
- Add webhook provider URLs
- Add provider icon (providers.js) and dropdown options (index.html)
- Add auto-detection patterns and setup URLs (slashCommands.js)
- Whitelist opencode.ai in URL validation (admin.js)
- Rebased on main to fix merge conflicts with _HOST_TO_CURATED refactor
Co-authored-by: M57 <hy4ri@users.noreply.github.com>
Validate only token-supplied direct base_url values for API-token chat requests, while keeping admin-configured endpoints available for local/LAN providers.
Scope configured endpoint fallback selection to the API token owner, fail closed for unknown token owners, and preserve strict session ownership checks when resuming sessions from chat-scoped API tokens.
Add focused regression coverage for direct base_url SSRF rejection, configured endpoint fallback behavior, token-owner scoping, URL validation, and null-owner session/endpoint handling.
Follow-up to the Venice provider PR. Wire api.venice.ai into the three
host allowlists so Venice behaves like the other paid OpenAI-compatible
clouds:
- agent_loop: add api.venice.ai to _API_HOSTS so the agent sends native
OpenAI tool-call schemas (Venice supports function calling) instead of
degrading to fenced-block parsing.
- teacher_escalation: add api.venice.ai to _SOTA_HOSTS so the escalation
loop stays OFF for Venice (it's a paid top-tier API; no need to add
teacher-model latency).
- webhook_routes: add venice to KNOWN_PROVIDERS so the sync chat webhook
can auto-resolve base_url from provider=venice.
Tests: tests/test_venice_hosts.py pins tool-host matching + SOTA
classification for Venice; py_compile on touched modules.
Co-authored-by: Cursor <cursoragent@cursor.com>
The sync-chat endpoint's Case 3 fallback selected a ModelEndpoint with an
unscoped `query(ModelEndpoint).filter(is_enabled == True).first()` and then
used that row's decrypted `api_key` for the LLM call. ModelEndpoint is a
per-user resource (owner non-null = private to that user), so a chat-scoped
API token for user A that sent no session and no api_key could fall back onto
user B's PRIVATE endpoint — spending B's API key/quota and reaching whatever
internal base_url B configured. This is the same multi-tenant owner-scoping
class already fixed for the session gate on this very endpoint
(_caller_owns_session) and for companion/models.
Scope the fallback to the token owner's own rows plus legacy null-owner
(shared) rows via the existing owner_filter helper, matching
routes/model_routes.py and companion/routes.py. A null/empty owner stays a
no-op, preserving single-user/legacy behaviour.
Add regression tests pinning the scoped fallback (cross-owner, shared-only,
no-visible-row, disabled-owned, and the legacy null-owner no-op).
POST /api/v1/chat (the n8n/Make/Activepieces sync-chat endpoint) verified
session ownership with `_tok_user and _sess_owner and _sess_owner != _tok_user`.
The `_sess_owner and` clause skipped the check entirely whenever the session's
owner was null — so any chat-scoped API token (e.g. a token minted for a paired
mobile device) could pass a legacy/migrated null-owner session id, inject a
message into that session, and read back its conversation history plus reuse
the owner's endpoint credentials.
This is the same `if owner and owner != user` null-owner-bypass pattern that
was already hardened in the gallery, calendar, and notes routes (see
test_null_owner_gates.py) and in session_routes._verify_session_owner. Make
this gate strict and fail closed too: require a resolvable caller and an exact
owner match, mirroring _verify_session_owner. Extract the decision into
_caller_owns_session() and pin it with regression tests.