feat(memory): config embedders (LOT C2) + suggestion contextuelle (LOT C3) + contexte projet partagé

- LOT C2 (§14.5.3) : use cases de configuration des embedders déclaratifs
  (List/Save/Delete + DescribeEmbedderEngines : modèles ONNX recommandés,
  environnement local détecté, stratégies compilées). UI EmbedderSettings.
- LOT C3 (§14.5.5) : suggestion contextuelle best-effort à l'activation quand la
  mémoire dépasse le budget de recall sans embedder configuré (event
  EmbedderSuggested, anti-spam 1×/session, « ne plus demander »).
- Contexte projet partagé .ideai/CONTEXT.md (model-agnostic) injecté à tous les
  agents/profils au lancement, avant la persona. UI ProjectContextPanel.

Tests : backend workspace vert (0 échec) ; frontend 306/306.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 09:24:51 +02:00
parent 32398827fb
commit 785e9935fd
118 changed files with 5793 additions and 866 deletions

View File

@ -13,6 +13,8 @@ import type {
AgentDrift,
AgentProfile,
DomainEvent,
EmbedderEngines,
EmbedderProfile,
FirstRunState,
GitBranches,
GitCommit,
@ -78,6 +80,20 @@ export interface AgentGateway {
* launched a second time — one live session per agent).
*/
listLiveAgents(projectId: string): Promise<LiveAgent[]>;
/**
* Rebinds an already-live agent session to another visible layout cell without
* respawning the CLI process. Used when a background agent is opened in a cell,
* or when a live session is moved from a now-detached/closed cell.
*
* Backends that do not yet support agent-session rebinding may omit this
* method; the UI will show the session as running elsewhere but cannot attach
* it from a different cell.
*/
attachLiveAgent?(
projectId: string,
agentId: string,
nodeId: string,
): Promise<LiveAgent>;
/** Creates a new agent from scratch; returns the created agent. */
createAgent(projectId: string, input: CreateAgentInput): Promise<Agent>;
/** Reads an agent's `.md` context by agent id. */
@ -156,6 +172,11 @@ export interface LiveAgent {
agentId: string;
/** The node (layout leaf) hosting the agent's live session. */
nodeId: string;
/**
* The live PTY session id, when the backend exposes it. Required for opening
* a background/running agent in a new visible cell without respawning it.
*/
sessionId?: string;
}
/**
@ -253,6 +274,10 @@ export interface ProjectGateway {
openProject(projectId: string): Promise<Project>;
/** Closes a project by id. */
closeProject(projectId: string): Promise<void>;
/** Reads the shared project context stored at `.ideai/CONTEXT.md`. */
readProjectContext(projectId: string): Promise<string>;
/** Overwrites the shared project context stored at `.ideai/CONTEXT.md`. */
updateProjectContext(projectId: string, content: string): Promise<void>;
}
/** Layout: load the terminal grid tree and apply mutating operations (L4). */
@ -458,6 +483,29 @@ export interface ProfileGateway {
configureProfiles(profiles: AgentProfile[]): Promise<AgentProfile[]>;
}
/** Input for {@link EmbedderGateway.saveEmbedderProfile}. */
export interface SaveEmbedderProfileInput {
profile: EmbedderProfile;
}
/**
* Embedder configuration (L14 / lot C2). Drives the memory/embedder settings
* panel: lists the configured embedder profiles, the available engines (with
* build-time feature flags so unavailable strategies can be shown disabled),
* and persists / removes profiles. Changing the active embedder takes effect at
* the next app start. Mirrors the four backend embedder commands.
*/
export interface EmbedderGateway {
/** Lists the configured embedder profiles (transparent: no secrets). */
listEmbedderProfiles(): Promise<EmbedderProfile[]>;
/** Creates or replaces (by id) a single profile; returns the saved profile. */
saveEmbedderProfile(profile: EmbedderProfile): Promise<EmbedderProfile>;
/** Deletes an embedder profile by id. */
deleteEmbedderProfile(embedderId: string): Promise<void>;
/** Describes the available engines + build feature flags + detection. */
describeEmbedderEngines(): Promise<EmbedderEngines>;
}
/**
* The full set of gateways the app depends on, injected via the DI provider.
* The composition (real vs mock) is chosen in `app/`.
@ -474,4 +522,5 @@ export interface Gateways {
template: TemplateGateway;
skill: SkillGateway;
memory: MemoryGateway;
embedder: EmbedderGateway;
}