feat(persistence): P8b — écriture providers.json (resumable par provider)
Au lancement structuré, le resumable exposé par le moteur est rangé dans providers.json sous (id de paire, provider) — best-effort, n'altère jamais le lancement. - domaine : StructuredAdapter::provider_key() ⇒ "claude"/"codex" (clé stable par famille, lisible, indépendante de l'uuid d'instance) - application : port ProviderSessionProvider (root par appel) + with_provider_session_provider ; helper persist_provider_session dans launch_structured (skip si provider/adapter/id moteur absents ou set KO) - app-tauri : AppProviderSessionProvider (FsProviderSessionStore sur le root) - tests : 6 cas (nominal claude/codex, no-op sans provider/sans id moteur, best-effort, mapping provider_key) ; domain+application verts Lecture du store pour --resume = P8c. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -42,7 +42,7 @@ use domain::{DomainEvent, EmbedderProfile, Project, ProjectId};
|
||||
use infrastructure::{
|
||||
embedder_from_profile, AdaptiveMemoryRecall, ClaudeTranscriptInspector, CliAgentRuntime,
|
||||
EmbedderEnvProbe, FsConversationLog, FsEmbedderProfileStore, FsEmbedderPromptStore,
|
||||
FsHandoffStore, FsMemoryStore, HeuristicHandoffSummarizer,
|
||||
FsHandoffStore, FsMemoryStore, FsProviderSessionStore, HeuristicHandoffSummarizer,
|
||||
FsOrchestratorWatcher, FsProfileStore, FsProjectStore, FsSkillStore, FsTemplateStore,
|
||||
Git2Repository, IdeaiContextStore, InMemoryConversationRegistry, InMemoryMailbox,
|
||||
LocalFileSystem, LocalProcessSpawner, McpServer, MediatedInbox, SystemMillisClock,
|
||||
@ -101,6 +101,25 @@ impl application::HandoffProvider for AppHandoffProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/// Implémente [`ProviderSessionProvider`](application::ProviderSessionProvider) (lot
|
||||
/// P8b) en matérialisant un [`FsProviderSessionStore`] ciblant le **project root** du
|
||||
/// lancement en cours.
|
||||
///
|
||||
/// Jumeau stateless de [`AppHandoffProvider`] : [`LaunchAgent`] est unique pour tous
|
||||
/// les projets, alors que `providers.json` est **par project root**
|
||||
/// (`<root>/.ideai/conversations/providers.json`). On construit donc un store frais
|
||||
/// par lancement, ciblant le bon dossier. Sans état (zéro champ), partagé via `Arc`.
|
||||
struct AppProviderSessionProvider;
|
||||
|
||||
impl application::ProviderSessionProvider for AppProviderSessionProvider {
|
||||
fn provider_session_store_for(
|
||||
&self,
|
||||
root: &domain::project::ProjectPath,
|
||||
) -> Option<Arc<dyn domain::ProviderSessionStore>> {
|
||||
Some(Arc::new(FsProviderSessionStore::new(root)) as Arc<dyn domain::ProviderSessionStore>)
|
||||
}
|
||||
}
|
||||
|
||||
/// Everything the IPC layer needs at runtime, managed by Tauri.
|
||||
///
|
||||
/// Use cases are stored behind `Arc` so handlers clone cheaply. The concrete
|
||||
@ -627,7 +646,14 @@ impl AppState {
|
||||
// porte une conversation et qu'un handoff existe (`<root>/.ideai/conversations/`),
|
||||
// son résumé est réinjecté dans le convention file. Best-effort, additif :
|
||||
// un handoff absent/illisible ⇒ lancement normal sans section.
|
||||
.with_handoff_provider(Arc::new(AppHandoffProvider) as Arc<dyn application::HandoffProvider>),
|
||||
.with_handoff_provider(Arc::new(AppHandoffProvider) as Arc<dyn application::HandoffProvider>)
|
||||
// Resumable moteur par provider (lot P8b) : après un lancement structuré
|
||||
// exposant un id de session moteur, rangé sous la clé de paire dans
|
||||
// `<root>/.ideai/conversations/providers.json`. Best-effort, additif : une
|
||||
// écriture en échec / pas d'id moteur ⇒ lancement normal, aucune écriture.
|
||||
.with_provider_session_provider(
|
||||
Arc::new(AppProviderSessionProvider) as Arc<dyn application::ProviderSessionProvider>,
|
||||
),
|
||||
);
|
||||
|
||||
// Hot-swap an agent's runtime profile (§15.1). Reuses the shared context/
|
||||
|
||||
Reference in New Issue
Block a user