fix(runtime): isolation d'usage multi-projet #107
Implémentation du garde ModelServerProjectUseGuard pour séparer les retours des agents entre projets concurrents. - Garde RAII par LocalModelServerId partagé entre projets - Refus inter-projets concurrent via model_server_in_use - Partage intra-projet conservé avec refcount - Libération automatique à la fermeture/erreur de session Tests de validation: rejet projet distinct, compteur refs, libération retrait
This commit is contained in:
@ -13,6 +13,8 @@ use domain::conversation::ConversationId;
|
||||
use domain::ports::{AgentSession, PtyHandle};
|
||||
use domain::{AgentId, IssueRef, NodeId, ProjectId, SessionId, SessionKind, TerminalSession};
|
||||
|
||||
use crate::model_server::ModelServerProjectUseGuard;
|
||||
|
||||
/// Runtime family of a live agent session.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum LiveSessionKind {
|
||||
@ -38,11 +40,12 @@ pub struct LiveSessionSnapshot {
|
||||
}
|
||||
|
||||
/// A registered, live terminal: its PTY handle plus the domain snapshot.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
struct Entry {
|
||||
project_id: ProjectId,
|
||||
handle: PtyHandle,
|
||||
session: TerminalSession,
|
||||
_model_server_guard: Option<ModelServerProjectUseGuard>,
|
||||
}
|
||||
|
||||
/// Read-only liveness query over the agents that currently own a live PTY.
|
||||
@ -164,6 +167,18 @@ impl TerminalSessions {
|
||||
project_id: ProjectId,
|
||||
handle: PtyHandle,
|
||||
session: TerminalSession,
|
||||
) {
|
||||
self.insert_in_project_with_model_server_guard(project_id, handle, session, None);
|
||||
}
|
||||
|
||||
/// Inserts a freshly-opened session and retains a model-server usage guard
|
||||
/// until the session is removed.
|
||||
pub fn insert_in_project_with_model_server_guard(
|
||||
&self,
|
||||
project_id: ProjectId,
|
||||
handle: PtyHandle,
|
||||
session: TerminalSession,
|
||||
model_server_guard: Option<ModelServerProjectUseGuard>,
|
||||
) {
|
||||
if let Ok(mut map) = self.entries.lock() {
|
||||
map.insert(
|
||||
@ -172,6 +187,7 @@ impl TerminalSessions {
|
||||
project_id,
|
||||
handle,
|
||||
session,
|
||||
_model_server_guard: model_server_guard,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -388,6 +404,8 @@ struct StructuredEntry {
|
||||
agent_id: AgentId,
|
||||
/// La cellule (feuille de layout) qui héberge actuellement la vue.
|
||||
node_id: NodeId,
|
||||
/// Optional local-model-server usage guard retained for the live session.
|
||||
_model_server_guard: Option<ModelServerProjectUseGuard>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -446,6 +464,21 @@ impl StructuredSessions {
|
||||
session: Arc<dyn AgentSession>,
|
||||
agent_id: AgentId,
|
||||
node_id: NodeId,
|
||||
) {
|
||||
self.insert_in_project_with_model_server_guard(
|
||||
project_id, session, agent_id, node_id, None,
|
||||
);
|
||||
}
|
||||
|
||||
/// Enregistre une session structurée et retient un garde d'usage de serveur
|
||||
/// local jusqu'au retrait de la session.
|
||||
pub fn insert_in_project_with_model_server_guard(
|
||||
&self,
|
||||
project_id: ProjectId,
|
||||
session: Arc<dyn AgentSession>,
|
||||
agent_id: AgentId,
|
||||
node_id: NodeId,
|
||||
model_server_guard: Option<ModelServerProjectUseGuard>,
|
||||
) {
|
||||
if let Ok(mut map) = self.entries.lock() {
|
||||
let id = session.id();
|
||||
@ -456,6 +489,7 @@ impl StructuredSessions {
|
||||
session,
|
||||
agent_id,
|
||||
node_id,
|
||||
_model_server_guard: model_server_guard,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user