feat(background): runner PTY B8 + boucle sink fermée + refactor point-2
Livre le lot backend B8 des tâches de fond : - infrastructure : runner de commandes concret (CommandBackgroundRunner) sur le port BackgroundTaskRunner, tail borné (bounded_tail/BoundedTail), éclatement du module background_task en sous-modules (mod/runner/tail, sink extrait de l'ancien background_task.rs). - application : nouveau module background exposant les cas d'usage SpawnBackgroundCommand, CancelBackgroundTask, RetryBackgroundTask et le port BackgroundCommandArchive. - domain : refactor point-2 de l'arbitrage Architect — sortie du trait BackgroundCommandArchive de la couche domaine vers application. - app-tauri : câblage runtime (commands, dto, state, lib) des commandes spawn/cancel/retry et de la boucle de complétion sink fermée en composition root. Build workspace + tests application/infrastructure verts (QA). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -13,7 +13,8 @@ use std::sync::{Arc, Mutex};
|
||||
|
||||
use application::{
|
||||
AgentResumer, AgentWakeService, AppError, AssignSkillToAgent, AttachLiveAgent,
|
||||
ChangeAgentProfile, CheckEmbedderSuggestion, CloseProject, CloseTab, CloseTerminal,
|
||||
BackgroundCommandArchive, CancelBackgroundTask, ChangeAgentProfile, CheckEmbedderSuggestion,
|
||||
CloseProject, CloseTab, CloseTerminal, RetryBackgroundTask, SpawnBackgroundCommand,
|
||||
ConfigureProfiles, ContextGuardUseCases, CreateAgentFromScratch, CreateAgentFromTemplate,
|
||||
CreateLayout, CreateMemory, CreateProject, CreateSkill, CreateTemplate, DeleteAgent,
|
||||
DeleteEmbedderProfile, DeleteLayout, DeleteMemory, DeleteProfile, DeleteSkill, DeleteTemplate,
|
||||
@ -39,7 +40,8 @@ use application::{
|
||||
use async_trait::async_trait;
|
||||
use domain::ports::{
|
||||
AgentContextStore, AgentRuntime, AgentSession, AgentSessionFactory, AgentWakePort,
|
||||
BackgroundTaskPortError, BackgroundTaskStore, Clock, Embedder, EmbedderEnvInspector,
|
||||
BackgroundTaskPortError, BackgroundTaskRunner, BackgroundTaskStore,
|
||||
Clock, Embedder, EmbedderEnvInspector,
|
||||
EmbedderProfileStore, EmbedderPromptStore, EventBus, FileSystem, GitPort, IdGenerator,
|
||||
MemoryRecall, MemoryStore, PermissionStore, ProcessSpawner, ProfileStore, ProjectStore,
|
||||
PtyPort, ScheduledTask, Scheduler, SkillStore, TemplateStore, WakeError, WakeReason,
|
||||
@ -57,8 +59,9 @@ use serde_json::{json, Map, Value};
|
||||
use uuid::Uuid;
|
||||
|
||||
use infrastructure::{
|
||||
embedder_from_profile, AdaptiveMemoryRecall, BackgroundTaskReadyToDeliver,
|
||||
ClaudePermissionProjector, ClaudeTranscriptInspector, CliAgentRuntime,
|
||||
embedder_from_profile, AdaptiveMemoryRecall, BackgroundCompletionSink,
|
||||
BackgroundTaskReadyToDeliver, ClaudePermissionProjector, ClaudeTranscriptInspector,
|
||||
CliAgentRuntime, CommandBackgroundRunner,
|
||||
CodexPermissionProjector, EmbedderEnvProbe, FsBackgroundTaskStore, FsConversationLog,
|
||||
FsEmbedderProfileStore, FsEmbedderPromptStore, FsHandoffStore, FsLiveStateStore, FsMemoryStore,
|
||||
FsOrchestratorWatcher, FsPermissionStore, FsProfileStore, FsProjectStore,
|
||||
@ -795,6 +798,15 @@ pub struct AppState {
|
||||
// --- Windows (L10) ---
|
||||
/// Detach a tab into a new OS window (persists the workspace topology).
|
||||
pub move_tab: Arc<MoveTabToNewWindow>,
|
||||
// --- Background tasks (B8) ---
|
||||
/// Spawn a command-backed first-class background task.
|
||||
pub spawn_background_command: Arc<SpawnBackgroundCommand>,
|
||||
/// Cancel a running background task.
|
||||
pub cancel_background_task: Arc<CancelBackgroundTask>,
|
||||
/// Retry a terminal command task under a fresh task id.
|
||||
pub retry_background_task: Arc<RetryBackgroundTask>,
|
||||
/// Store handle used by `list_background_tasks` to read the task read-model.
|
||||
pub background_task_store: Arc<dyn BackgroundTaskStore>,
|
||||
// --- Templates & sync (L7) ---
|
||||
/// Create a template in the global store.
|
||||
pub create_template: Arc<CreateTemplate>,
|
||||
@ -1541,6 +1553,49 @@ impl AppState {
|
||||
let background_tasks_port = Arc::clone(&background_tasks) as Arc<dyn BackgroundTaskStore>;
|
||||
let (background_ready_tx, mut background_ready_rx) =
|
||||
tokio::sync::mpsc::unbounded_channel::<BackgroundTaskReadyToDeliver>();
|
||||
|
||||
// --- B8 : runner de commandes + fermeture de la boucle du sink ---
|
||||
// Le runner concret exécute les tâches command-backed sur le `PtyPort` composé
|
||||
// (local ici ; SSH/WSL via `RemoteHost` quand ils atterriront — Liskov). Il
|
||||
// émet UNE complétion par tâche ; le sink (single-writer) persiste l'état
|
||||
// terminal AVANT de signaler la livraison (persist-avant-signal), puis le pont
|
||||
// ready→inbox ci-dessous réveille l'agent propriétaire.
|
||||
let background_runner = Arc::new(CommandBackgroundRunner::new(
|
||||
Arc::clone(&pty_port),
|
||||
Arc::clone(&clock) as Arc<dyn Clock>,
|
||||
));
|
||||
let background_runner_port =
|
||||
Arc::clone(&background_runner) as Arc<dyn BackgroundTaskRunner>;
|
||||
{
|
||||
let sink = Arc::new(BackgroundCompletionSink::new(
|
||||
Arc::clone(&background_tasks_port),
|
||||
background_ready_tx.clone(),
|
||||
));
|
||||
let runner = Arc::clone(&background_runner_port);
|
||||
// `start_from_runner` exige un runtime Tokio ambiant (`Handle::current`) :
|
||||
// on l'appelle donc DANS la tâche async. Le `JoinHandle` du drain est gardé
|
||||
// vivant en l'attendant (il ne se termine qu'à la fermeture du flux de
|
||||
// complétions), ce qui maintient sink + runner en vie pour la session.
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let drain = sink.start_from_runner(runner);
|
||||
let _ = drain.await;
|
||||
});
|
||||
}
|
||||
let spawn_background_command = Arc::new(SpawnBackgroundCommand::new(
|
||||
Arc::clone(&background_tasks_port),
|
||||
Arc::clone(&background_runner_port),
|
||||
Arc::clone(&clock) as Arc<dyn Clock>,
|
||||
Arc::clone(&ids) as Arc<dyn IdGenerator>,
|
||||
));
|
||||
let cancel_background_task = Arc::new(CancelBackgroundTask::new(
|
||||
Arc::clone(&background_tasks_port),
|
||||
Arc::clone(&background_runner_port),
|
||||
));
|
||||
let retry_background_task = Arc::new(RetryBackgroundTask::new(
|
||||
Arc::clone(&background_tasks_port),
|
||||
Arc::clone(&background_runner) as Arc<dyn BackgroundCommandArchive>,
|
||||
Arc::clone(&spawn_background_command),
|
||||
));
|
||||
let background_wake = Arc::new(AgentWakeService::new(
|
||||
Arc::clone(&mediated_inbox) as Arc<dyn AgentInbox>,
|
||||
Arc::clone(&input_mediator),
|
||||
@ -1977,6 +2032,10 @@ impl AppState {
|
||||
fs_port: Arc::clone(&fs_port),
|
||||
home_dir,
|
||||
move_tab,
|
||||
spawn_background_command,
|
||||
cancel_background_task,
|
||||
retry_background_task,
|
||||
background_task_store: Arc::clone(&background_tasks_port),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user