feat(ui): profils locaux/LAN OpenAI-compatible dans le first-run et les terminaux (#14)

Câble la surface frontend des profils IA locaux/LAN OpenAI-compatible,
en parité avec l'adapter backend additif (aab4bca).

- domain: types de profil OpenAI-compatible
- first-run: édition/validation du profil dans le FirstRunWizard
- adapters/mock: mock de profil pour les tests
- terminals: rendu des round-trips et erreurs endpoint (role=alert)

Validé QA (frontend GO): typecheck exit 0, vitest 59 fichiers / 566 tests,
0 echec ; couverture timeouts round-trip + erreur endpoint role=alert
prouvees ; pas de regression sur les tests de bail headless.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 22:34:50 +02:00
parent aab4bcafb6
commit d89380cdf0
9 changed files with 656 additions and 10 deletions

View File

@ -626,6 +626,42 @@ export type ContextInjection =
/** The four injection strategy discriminants. */
export type InjectionStrategy = ContextInjection["strategy"];
/**
* Structured-execution adapter of a profile (mirror of the backend
* `StructuredAdapter`, camelCase wire format). Absent (`structuredAdapter`
* omitted) ⇒ the profile is a plain TUI/PTY agent (historical behaviour);
* present ⇒ the profile is selectable as a structured AI agent:
* - `claude` / `codex`: driven by a spawned CLI binary,
* - `openAiCompatible`: driven by IdeA's native HTTP adapter against an
* OpenAI-compatible chat server (Ollama, llama.cpp, a LAN runtime) — see
* {@link HttpChatConfig}.
*/
export type StructuredAdapter = "claude" | "codex" | "openAiCompatible";
/**
* HTTP configuration of an OpenAI-compatible chat server (mirror of the backend
* `HttpChatConfig`, camelCase wire format). Carried by a profile whose
* {@link StructuredAdapter} is `openAiCompatible`.
*
* Transparent by design: secrets are never stored here — `apiKeyEnv` is the
* *name* of an environment variable, never the key itself (the backend resolves
* it at call time).
*/
export interface HttpChatConfig {
/** Root or `/chat/completions` endpoint of the HTTP server (http/https). */
endpoint: string;
/** Model name sent in the `/chat/completions` payload. */
model: string;
/** Name of the env var holding the API key (optional). Never the key. */
apiKeyEnv?: string;
/** Per-turn request timeout, in milliseconds. */
requestTimeoutMs?: number;
/** Connection timeout, in milliseconds. */
connectTimeoutMs?: number;
/** Tool-calling re-loop guard for one turn (defaults to ~16 backend-side). */
maxToolIterations?: number;
}
/**
* A declarative AI-CLI profile (mirror of the backend `AgentProfile`). `id` is a
* UUID string; `detect` is the optional detection command line.
@ -641,6 +677,19 @@ export interface AgentProfile {
/** Optional CLI flags for agent-session continuity: `assignFlag` to bind a
* conversation id at launch, `resumeFlag` to resume an existing conversation. */
session?: { assignFlag?: string; resumeFlag: string };
/**
* Structured-execution adapter (mirror of the backend `structured_adapter`,
* `skip_serializing_if = Option::is_none`). Absent ⇒ plain TUI/PTY profile;
* present ⇒ selectable structured AI agent. Additive: existing Claude/Codex
* profiles are unaffected.
*/
structuredAdapter?: StructuredAdapter;
/**
* HTTP config for a `openAiCompatible` structured adapter (mirror of the
* backend `chat_http`, `skip_serializing_if = Option::is_none`). Absent for
* every historical profile and every non-HTTP adapter.
*/
chatHttp?: HttpChatConfig;
}
/** Availability of a candidate profile after detection (mirror of the DTO). */