feat(workstate): read-model live-state minimal des conversations/délégations (Lot A backend)
Introduit le module application `workstate` (modèle de read-model live + snapshots des conversations/délégations en cours) et l'expose via la couche terminal (exports mod/registry). Câble la surface Tauri : DTO, commande et state pour exposer le live-state au frontend (lib + state + commands), avec tests. QA verte. Réserve environnementale non bloquante : tests loopback socket Unix réels non exécutables en sandbox (UnixListener::bind PermissionDenied), alternatives avec skips vertes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -12,13 +12,13 @@ use application::{
|
||||
AppError, AssignSkillToAgentInput, ChangeAgentProfileInput, CloseProjectInput,
|
||||
CreateAgentInput, CreateLayoutInput, CreateMemoryInput, CreateSkillInput, DeleteAgentInput,
|
||||
DeleteEmbedderProfileInput, DeleteLayoutInput, DeleteMemoryInput, DeleteSkillInput,
|
||||
DeleteTemplateInput, DetectAgentDriftInput, GetMemoryInput, GitBranchesInput, GitCheckoutInput,
|
||||
GitCommitInput, GitGraphInput, GitInitInput, GitLogInput, GitStagePathInput, GitStatusInput,
|
||||
InspectConversationInput, LaunchAgentInput, ListAgentsInput, ListLayoutsInput,
|
||||
ListMemoriesInput, ListResumableAgentsInput, ListSkillsInput, LiveSessions, LoadLayoutInput,
|
||||
McpRuntime, MutateLayoutInput, OpenProjectInput, ReadAgentContextInput, ReadMemoryIndexInput,
|
||||
ReadProjectContextInput, RecallMemoryInput, ReconcileLayoutsInput, RenameLayoutInput,
|
||||
ResolveAgentPermissionsInput, ResolveMemoryLinksInput, SetActiveLayoutInput,
|
||||
DeleteTemplateInput, DetectAgentDriftInput, GetMemoryInput, GetProjectWorkStateInput,
|
||||
GitBranchesInput, GitCheckoutInput, GitCommitInput, GitGraphInput, GitInitInput, GitLogInput,
|
||||
GitStagePathInput, GitStatusInput, InspectConversationInput, LaunchAgentInput, ListAgentsInput,
|
||||
ListLayoutsInput, ListMemoriesInput, ListResumableAgentsInput, ListSkillsInput, LiveSessions,
|
||||
LoadLayoutInput, McpRuntime, MutateLayoutInput, OpenProjectInput, ReadAgentContextInput,
|
||||
ReadMemoryIndexInput, ReadProjectContextInput, RecallMemoryInput, ReconcileLayoutsInput,
|
||||
RenameLayoutInput, ResolveAgentPermissionsInput, ResolveMemoryLinksInput, SetActiveLayoutInput,
|
||||
SnapshotRunningAgentsInput, SyncAgentWithTemplateInput, UnassignSkillFromAgentInput,
|
||||
UpdateAgentContextInput, UpdateAgentPermissionsInput, UpdateMemoryInput,
|
||||
UpdateProjectContextInput, UpdateProjectPermissionsInput, UpdateSkillInput,
|
||||
@ -42,11 +42,11 @@ use crate::dto::{
|
||||
InterruptAgentRequestDto, LaunchAgentRequestDto, LayoutDto, LayoutOperationDto, ListLayoutsDto,
|
||||
LiveAgentListDto, MemoryDto, MemoryIndexDto, MemoryLinksDto, MemoryListDto,
|
||||
OpenTerminalRequestDto, ProfileDto, ProfileListDto, ProjectDto, ProjectListDto,
|
||||
ProjectPermissionsDto, ReadAgentContextResponseDto, ReattachChatDto, ReattachResultDto,
|
||||
RecallMemoryRequestDto, RenameLayoutRequestDto, ReplyChunk, ResizeTerminalRequestDto,
|
||||
ResolveAgentPermissionsRequestDto, ResumableAgentListDto, SaveEmbedderProfileRequestDto,
|
||||
SaveProfileRequestDto, SetActiveLayoutRequestDto, SkillDto, SkillListDto,
|
||||
SyncAgentWithTemplateRequestDto, SyncResultDto, TemplateDto, TemplateListDto,
|
||||
ProjectPermissionsDto, ProjectWorkStateDto, ReadAgentContextResponseDto, ReattachChatDto,
|
||||
ReattachResultDto, RecallMemoryRequestDto, RenameLayoutRequestDto, ReplyChunk,
|
||||
ResizeTerminalRequestDto, ResolveAgentPermissionsRequestDto, ResumableAgentListDto,
|
||||
SaveEmbedderProfileRequestDto, SaveProfileRequestDto, SetActiveLayoutRequestDto, SkillDto,
|
||||
SkillListDto, SyncAgentWithTemplateRequestDto, SyncResultDto, TemplateDto, TemplateListDto,
|
||||
TerminalClosedDto, TerminalSessionDto, UnassignSkillRequestDto, UpdateAgentContextRequestDto,
|
||||
UpdateAgentPermissionsRequestDto, UpdateMemoryRequestDto, UpdateProjectContextRequestDto,
|
||||
UpdateProjectPermissionsRequestDto, UpdateSkillRequestDto, UpdateTemplateRequestDto,
|
||||
@ -968,6 +968,25 @@ pub async fn list_agents(
|
||||
.map_err(ErrorDto::from)
|
||||
}
|
||||
|
||||
/// `get_project_work_state` — read-only live/busy state for manifest agents.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an [`ErrorDto`] (`INVALID` for a malformed id, `NOT_FOUND` if the
|
||||
/// project is unknown, `STORE` on manifest I/O failure).
|
||||
#[tauri::command]
|
||||
pub async fn get_project_work_state(
|
||||
project_id: String,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<ProjectWorkStateDto, ErrorDto> {
|
||||
let project = resolve_project(&project_id, &state).await?;
|
||||
state
|
||||
.get_project_work_state
|
||||
.execute(GetProjectWorkStateInput { project })
|
||||
.await
|
||||
.map(ProjectWorkStateDto::from)
|
||||
.map_err(ErrorDto::from)
|
||||
}
|
||||
|
||||
/// `list_live_agents` — list every agent that currently owns a live session
|
||||
/// (raw PTY **or** structured/chat) and the cell hosting each, so the UI can
|
||||
/// disable an agent already running in another cell (the "one live session per
|
||||
|
||||
@ -10,9 +10,9 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use application::{
|
||||
AppError, CreateProjectInput, CreateProjectOutput, GitGraphOutput, HealthInput, HealthReport,
|
||||
LayoutKind, ListProjectsOutput, OpenProjectOutput,
|
||||
LayoutKind, ListProjectsOutput, LiveSessionKind, OpenProjectOutput, ProjectWorkState,
|
||||
};
|
||||
use domain::{Project, ProjectId};
|
||||
use domain::{AgentBusyState, Project, ProjectId};
|
||||
|
||||
/// Request DTO for the `health` command.
|
||||
#[derive(Debug, Clone, Default, Deserialize)]
|
||||
@ -1472,6 +1472,83 @@ impl LiveAgentListDto {
|
||||
}
|
||||
}
|
||||
|
||||
/// Runtime family of a live work-state session.
|
||||
#[derive(Debug, Clone, Copy, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum LiveWorkSessionKindDto {
|
||||
/// Raw PTY-backed CLI session.
|
||||
Pty,
|
||||
/// Structured agent-session backend.
|
||||
Structured,
|
||||
}
|
||||
|
||||
impl From<LiveSessionKind> for LiveWorkSessionKindDto {
|
||||
fn from(kind: LiveSessionKind) -> Self {
|
||||
match kind {
|
||||
LiveSessionKind::Pty => Self::Pty,
|
||||
LiveSessionKind::Structured => Self::Structured,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Live session coordinates in the project work-state read model.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LiveWorkSessionDto {
|
||||
/// The layout node currently hosting the session view.
|
||||
pub node_id: String,
|
||||
/// The live session id.
|
||||
pub session_id: String,
|
||||
/// Runtime family that owns the session.
|
||||
pub kind: LiveWorkSessionKindDto,
|
||||
}
|
||||
|
||||
/// One manifest agent's current live/busy state.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentWorkStateDto {
|
||||
/// Agent id.
|
||||
pub agent_id: String,
|
||||
/// Agent display name.
|
||||
pub name: String,
|
||||
/// Runtime profile id assigned to the agent.
|
||||
pub profile_id: String,
|
||||
/// Live session, if any.
|
||||
pub live: Option<LiveWorkSessionDto>,
|
||||
/// Current mediated-input busy state.
|
||||
pub busy: AgentBusyState,
|
||||
}
|
||||
|
||||
/// Project-level read model for conversation/delegation UX.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ProjectWorkStateDto {
|
||||
/// Manifest agents in manifest order, enriched with live/busy state.
|
||||
pub agents: Vec<AgentWorkStateDto>,
|
||||
}
|
||||
|
||||
impl From<ProjectWorkState> for ProjectWorkStateDto {
|
||||
fn from(state: ProjectWorkState) -> Self {
|
||||
Self {
|
||||
agents: state
|
||||
.agents
|
||||
.into_iter()
|
||||
.map(|agent| AgentWorkStateDto {
|
||||
agent_id: agent.agent_id.to_string(),
|
||||
name: agent.name,
|
||||
profile_id: agent.profile_id.to_string(),
|
||||
live: agent.live.map(|live| LiveWorkSessionDto {
|
||||
node_id: live.node_id.to_string(),
|
||||
session_id: live.session_id.to_string(),
|
||||
kind: live.kind.into(),
|
||||
}),
|
||||
busy: agent.busy,
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Request DTO for `attach_live_agent`: bind an already-running agent session to
|
||||
/// a visible layout cell without spawning a new process.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
|
||||
@ -163,6 +163,7 @@ pub fn run() {
|
||||
commands::dismiss_embedder_suggestion,
|
||||
commands::create_agent,
|
||||
commands::list_agents,
|
||||
commands::get_project_work_state,
|
||||
commands::list_live_agents,
|
||||
commands::attach_live_agent,
|
||||
commands::read_agent_context,
|
||||
|
||||
@ -18,15 +18,15 @@ use application::{
|
||||
CreateSkill, CreateTemplate, DeleteAgent, DeleteEmbedderProfile, DeleteLayout, DeleteMemory,
|
||||
DeleteProfile, DeleteSkill, DeleteTemplate, DescribeEmbedderEngines, DetectAgentDrift,
|
||||
DetectProfiles, DismissEmbedderSuggestion, FirstRunState, GetMemory, GetProjectPermissions,
|
||||
GitBranches, GitCheckout, GitCommit, GitGraph, GitInit, GitLog, GitStage, GitStatus,
|
||||
GitUnstage, HealthUseCase, InspectConversation, LaunchAgent, LaunchAgentInput, ListAgents,
|
||||
ListAgentsInput, ListEmbedderProfiles, ListLayouts, ListMemories, ListProfiles, ListProjects,
|
||||
ListResumableAgents, ListSkills, ListTemplates, LiveAgentRegistry, LoadLayout, McpRuntime,
|
||||
MoveTabToNewWindow, MutateLayout, OnnxModelView, OpenProject, OpenTerminal,
|
||||
OrchestratorService, PermissionProjectorRegistry, ProposeContext, ReadAgentContext,
|
||||
ReadContext, ReadMemory, ReadMemoryIndex, ReadProjectContext, RecallMemory, ReconcileLayouts,
|
||||
RecordTurn, RecordTurnProvider, ReferenceProfiles, RenameLayout, ResizeTerminal,
|
||||
ResolveAgentPermissions, ResolveMemoryLinks, SaveEmbedderProfile, SaveProfile,
|
||||
GetProjectWorkState, GitBranches, GitCheckout, GitCommit, GitGraph, GitInit, GitLog, GitStage,
|
||||
GitStatus, GitUnstage, HealthUseCase, InspectConversation, LaunchAgent, LaunchAgentInput,
|
||||
ListAgents, ListAgentsInput, ListEmbedderProfiles, ListLayouts, ListMemories, ListProfiles,
|
||||
ListProjects, ListResumableAgents, ListSkills, ListTemplates, LiveAgentRegistry, LiveSessions,
|
||||
LoadLayout, McpRuntime, MoveTabToNewWindow, MutateLayout, OnnxModelView, OpenProject,
|
||||
OpenTerminal, OrchestratorService, PermissionProjectorRegistry, ProposeContext,
|
||||
ReadAgentContext, ReadContext, ReadMemory, ReadMemoryIndex, ReadProjectContext, RecallMemory,
|
||||
ReconcileLayouts, RecordTurn, RecordTurnProvider, ReferenceProfiles, RenameLayout,
|
||||
ResizeTerminal, ResolveAgentPermissions, ResolveMemoryLinks, SaveEmbedderProfile, SaveProfile,
|
||||
SessionLimitService, SetActiveLayout, SnapshotRunningAgents, StructuredSessions,
|
||||
SuggestedThisSession, SyncAgentWithTemplate, TerminalSessions, UnassignSkillFromAgent,
|
||||
UpdateAgentContext, UpdateAgentPermissions, UpdateMemory, UpdateProjectContext,
|
||||
@ -330,6 +330,8 @@ pub struct AppState {
|
||||
/// Read-only inventory of a project's resumable agent cells, for the reopen
|
||||
/// panel (§15.2).
|
||||
pub list_resumable_agents: Arc<ListResumableAgents>,
|
||||
/// Read-only live/busy state for the project's manifest agents.
|
||||
pub get_project_work_state: Arc<GetProjectWorkState>,
|
||||
/// Best-effort inspection of a conversation (last topic + token indicator)
|
||||
/// for the resume popup (T7). Optional/extensible: backed by a `Vec` of
|
||||
/// [`domain::ports::SessionInspector`]s; an empty/missing match yields empty
|
||||
@ -1021,6 +1023,15 @@ impl AppState {
|
||||
});
|
||||
}
|
||||
let input_mediator = Arc::clone(&mediated_inbox) as Arc<dyn domain::input::InputMediator>;
|
||||
let live_sessions = Arc::new(LiveSessions::new(
|
||||
Arc::clone(&terminal_sessions),
|
||||
Arc::clone(&structured_sessions),
|
||||
));
|
||||
let get_project_work_state = Arc::new(GetProjectWorkState::new(
|
||||
Arc::clone(&contexts_port),
|
||||
Arc::clone(&live_sessions),
|
||||
Arc::clone(&input_mediator),
|
||||
));
|
||||
|
||||
// --- Limites de session des agents (ARCHITECTURE §21, LS7) ---
|
||||
// Service pur-ports « détecter → planifier → reprendre » câblé sur l'existant :
|
||||
@ -1187,6 +1198,7 @@ impl AppState {
|
||||
launch_agent,
|
||||
change_agent_profile,
|
||||
list_resumable_agents,
|
||||
get_project_work_state,
|
||||
inspect_conversation,
|
||||
project_store,
|
||||
get_project_permissions,
|
||||
|
||||
Reference in New Issue
Block a user