78 lines
5.5 KiB
Markdown
78 lines
5.5 KiB
Markdown
## Context
|
|
|
|
The platform already has domain, DTO, validator, repository, service, and HTTP API foundations for AI provider resources. The route catalog previously deferred provider test/model actions, and `platform_web/pages/AiProvidersPage.tsx` is still a placeholder. The architecture requires AI provider credentials and base URLs to remain platform-owned, and plugin pages must never receive raw provider keys.
|
|
|
|
This change turns AI provider management into a usable first-party workflow across `platform/` and `platform_web/` while keeping the scope intentionally local: configuration validation, status management, and model inventory are platform metadata operations, not live external model calls.
|
|
|
|
## Goals / Non-Goals
|
|
|
|
**Goals:**
|
|
|
|
- Add backend AI provider management APIs for update, enable/disable, configuration test, and model listing.
|
|
- Keep all provider responses redacted to `apiKeyRef`; reject raw keys in create and update paths.
|
|
- Keep management behavior inside `service.Core` and named DTOs, with handlers acting as transport adapters.
|
|
- Implement a functional AI provider management page in `platform_web` with API client/types, create/edit form, status filters, model display, enable/disable, and test actions.
|
|
- Add backend and frontend tests for management behavior and secret redaction.
|
|
|
|
**Non-Goals:**
|
|
|
|
- No real OpenAI/Claude/local provider network calls.
|
|
- No secret vault implementation or raw secret storage.
|
|
- No plugin-facing AI invocation API.
|
|
- No AI-generated config diff/write dispatch.
|
|
- No authentication, RBAC, SQL persistence, run-side behavior, billing, cloud host sales, or agent-provider/cloud-provider workflows.
|
|
|
|
## Decisions
|
|
|
|
### Decision 1: Provider test is metadata validation
|
|
|
|
The test endpoint will validate stored provider metadata and report whether the provider is active, has a secret reference when required, includes a default model in its model list, and passes existing validator rules. It will not contact external AI services.
|
|
|
|
Alternative considered: performing a live chat/model request. Rejected because this change must not introduce external network behavior, raw key handling, or provider-specific clients.
|
|
|
|
### Decision 2: Status changes use a dedicated action route
|
|
|
|
Enable/disable behavior will use `POST /api/v1/ai-providers/{id}/status` with a named status request DTO. General update will edit provider metadata while preserving status unless the dedicated action changes it.
|
|
|
|
Alternative considered: overloading generic update with status changes. Rejected because explicit status actions are easier to audit and test.
|
|
|
|
### Decision 3: Update uses full provider metadata
|
|
|
|
The update request will accept the same safe fields as create plus provider metadata fields, with no raw key field. `apiKeyRef` remains a secret reference string and is validated the same way as create.
|
|
|
|
Alternative considered: partial patch semantics. Rejected for this stage because full update is deterministic, simpler to validate, and matches the existing in-memory repository implementation.
|
|
|
|
### Decision 4: Frontend page owns UI state but not contracts
|
|
|
|
`AiProvidersPage` will manage local loading/form selection state, while API DTOs and client functions remain in `platform_web/api`. The page will use API responses for persisted provider data and seed a local demo fallback only when the backend is unavailable in standalone frontend development.
|
|
|
|
Alternative considered: hard-coded page data only. Rejected because this would not exercise the platform API client or management workflow.
|
|
|
|
### Decision 5: UI stays operational and dense
|
|
|
|
The AI provider page will use a table, compact metrics, a form panel, filter controls, and action buttons. It will avoid marketing layout and will not display instructional copy or raw secrets.
|
|
|
|
Alternative considered: a large hero/empty-state page. Rejected because this is an operational console area used for repeated configuration work.
|
|
|
|
## Risks / Trade-offs
|
|
|
|
- [Risk] The test endpoint can only validate metadata, not live connectivity. Mitigation: return an explicit `mode` value and reserve live tests for a later provider invocation change.
|
|
- [Risk] Frontend fallback data could be mistaken for persisted data. Mitigation: mark fallback state as local-only in view state and prefer API data whenever the backend responds.
|
|
- [Risk] Full update requires clients to send all editable provider fields. Mitigation: centralize the request builder in the page and API client.
|
|
- [Risk] In-memory backend state remains process-local. Mitigation: retain service/router injection and leave persistence to a future storage change.
|
|
|
|
## Migration Plan
|
|
|
|
1. Add backend DTOs, service methods, handler routes, and route catalog updates for AI provider management.
|
|
2. Add backend service/API tests covering update, status, test/model responses, duplicate/missing resources, and raw key rejection.
|
|
3. Add frontend API types/client methods, replace the placeholder AI provider page, and add rendering/client tests.
|
|
4. Run backend tests, frontend tests/build, structure check, browser walkthrough, and strict OpenSpec validation.
|
|
|
|
Rollback before dependent changes is removal of the new AI provider management endpoints/page and this OpenSpec change. After dependent plugin or frontend workflows consume these APIs, rollback must be handled through a new OpenSpec change.
|
|
|
|
## Open Questions
|
|
|
|
- Which persistence-backed secret reference provider should store `apiKeyRef` targets?
|
|
- Which later change should add live provider connectivity tests and model discovery calls?
|
|
- Which authorization policy will restrict who can create or disable providers?
|