feat(persistence): P6b — câblage live du checkpoint conversationnel (best-effort)
ask_agent persiste désormais chaque paire dans son conversationId : tour Prompt à l'enqueue, tour Response au succès — best-effort (un échec de persistance ne dégrade jamais la délégation). - application : port RecordTurnProvider (matérialise un RecordTurn sur le bon project root — OrchestratorService est mono-instance multi-projets, le log est par root) ; wither with_record_turn(provider, Clock) ; helper record_turn_best_effort ; horodatage via domain::ports::Clock (pas d'horloge infra dans application) - app-tauri : AppRecordTurnProvider (Fs* sur le root du projet) câblé au composition root avec le SystemClock partagé - tests : 5 cas (paire Prompt→Response, fil A↔B vs User↔B, no-op sans provider, ask Ok même si record échoue) ; orchestrator_service 40, application + app-tauri verts Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -22,7 +22,8 @@ use application::{
|
||||
ListTemplates,
|
||||
LiveAgentRegistry, LoadLayout, MoveTabToNewWindow, MutateLayout, OnnxModelView, OpenProject,
|
||||
OpenTerminal, OrchestratorService, ReadAgentContext, ReadMemoryIndex, ReadProjectContext,
|
||||
RecallMemory, ReconcileLayouts, ReferenceProfiles, RenameLayout, ResizeTerminal,
|
||||
RecallMemory, ReconcileLayouts, RecordTurn, RecordTurnProvider, ReferenceProfiles,
|
||||
RenameLayout, ResizeTerminal,
|
||||
ResolveMemoryLinks,
|
||||
SaveEmbedderProfile, SaveProfile, SetActiveLayout, SnapshotRunningAgents, StructuredSessions,
|
||||
SuggestedThisSession,
|
||||
@ -40,7 +41,8 @@ use domain::{DomainEvent, EmbedderProfile, Project, ProjectId};
|
||||
|
||||
use infrastructure::{
|
||||
embedder_from_profile, AdaptiveMemoryRecall, ClaudeTranscriptInspector, CliAgentRuntime,
|
||||
EmbedderEnvProbe, FsEmbedderProfileStore, FsEmbedderPromptStore, FsMemoryStore,
|
||||
EmbedderEnvProbe, FsConversationLog, FsEmbedderProfileStore, FsEmbedderPromptStore,
|
||||
FsHandoffStore, FsMemoryStore, HeuristicHandoffSummarizer,
|
||||
FsOrchestratorWatcher, FsProfileStore, FsProjectStore, FsSkillStore, FsTemplateStore,
|
||||
Git2Repository, IdeaiContextStore, InMemoryConversationRegistry, InMemoryMailbox,
|
||||
LocalFileSystem, LocalProcessSpawner, McpServer, MediatedInbox, SystemMillisClock,
|
||||
@ -61,6 +63,25 @@ use interprocess::local_socket::traits::tokio::Listener as _;
|
||||
use interprocess::local_socket::{GenericFilePath, ListenerOptions, ToFsName};
|
||||
use tokio::io::{AsyncBufReadExt, BufReader};
|
||||
|
||||
/// Implémente [`RecordTurnProvider`] (lot P6b) en matérialisant un [`RecordTurn`]
|
||||
/// ciblant le **project root** du tour en cours.
|
||||
///
|
||||
/// L'[`OrchestratorService`] est unique pour tous les projets, alors que le log/handoff
|
||||
/// conversationnel est **par project root** (`<root>/.ideai/conversations/`). Les
|
||||
/// adapters `Fs*` fixent leur racine à la construction et ne sont que des jointures de
|
||||
/// chemin : on en construit donc un jeu frais par tour, ciblant le bon dossier. Sans
|
||||
/// état (zéro champ), partagé via un simple `Arc`.
|
||||
struct AppRecordTurnProvider;
|
||||
|
||||
impl RecordTurnProvider for AppRecordTurnProvider {
|
||||
fn record_turn_for(&self, root: &domain::project::ProjectPath) -> Option<Arc<RecordTurn>> {
|
||||
let log = Arc::new(FsConversationLog::new(root));
|
||||
let handoffs = Arc::new(FsHandoffStore::new(root));
|
||||
let summarizer = Arc::new(HeuristicHandoffSummarizer::new());
|
||||
Some(Arc::new(RecordTurn::new(log, handoffs, summarizer)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Everything the IPC layer needs at runtime, managed by Tauri.
|
||||
///
|
||||
/// Use cases are stored behind `Arc` so handlers clone cheaply. The concrete
|
||||
@ -785,6 +806,14 @@ impl AppState {
|
||||
// réelle ⇒ le pont MCP de la cible se spawne et `idea_reply` débloque le round-trip.
|
||||
.with_mcp_runtime_provider(
|
||||
Arc::new(AppMcpRuntimeProvider) as Arc<dyn application::McpRuntimeProvider>
|
||||
)
|
||||
// Persistance conversationnelle best-effort (lot P6b) : Prompt + Response de
|
||||
// chaque paire déléguée écrits dans `<root>/.ideai/conversations/<conv>` via
|
||||
// le provider per-root + l'horloge millis (port Clock) déjà câblée. Un échec
|
||||
// n'affecte jamais la délégation live.
|
||||
.with_record_turn(
|
||||
Arc::new(AppRecordTurnProvider) as Arc<dyn RecordTurnProvider>,
|
||||
Arc::clone(&clock) as Arc<dyn Clock>,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user