fix(runtime): isolate agent state by project (#101)
This commit is contained in:
@ -23,7 +23,7 @@ use std::time::Duration;
|
||||
use async_trait::async_trait;
|
||||
|
||||
use application::drain_with_readiness;
|
||||
use domain::ids::AgentId;
|
||||
use domain::ids::{AgentId, ProjectId, RuntimeAgentKey};
|
||||
use domain::input::{AgentBusyState, InputMediator};
|
||||
use domain::mailbox::{PendingReply, Ticket};
|
||||
use domain::ports::{AgentSession, AgentSessionError, ReplyEvent, ReplyStream};
|
||||
@ -38,6 +38,10 @@ fn aid(n: u128) -> AgentId {
|
||||
AgentId::from_uuid(Uuid::from_u128(n))
|
||||
}
|
||||
|
||||
fn key(agent: AgentId) -> RuntimeAgentKey {
|
||||
RuntimeAgentKey::new(ProjectId::from_uuid(Uuid::nil()), agent)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Fake AgentSession scriptable (mono-usage), repris de send_blocking_d1.rs
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -121,17 +125,20 @@ impl RecordingMediator {
|
||||
}
|
||||
|
||||
impl InputMediator for RecordingMediator {
|
||||
fn enqueue(&self, _agent: AgentId, _ticket: Ticket) -> PendingReply {
|
||||
fn enqueue(&self, _agent: RuntimeAgentKey, _ticket: Ticket) -> PendingReply {
|
||||
// Jamais utilisé par drain_with_readiness ; un future qui ne résout pas.
|
||||
PendingReply::new(Box::pin(std::future::pending()))
|
||||
}
|
||||
fn preempt(&self, agent: AgentId) {
|
||||
self.calls.lock().unwrap().push((agent, "preempt"));
|
||||
fn preempt(&self, agent: RuntimeAgentKey) {
|
||||
self.calls.lock().unwrap().push((agent.agent_id, "preempt"));
|
||||
}
|
||||
fn mark_idle(&self, agent: AgentId) {
|
||||
self.calls.lock().unwrap().push((agent, "mark_idle"));
|
||||
fn mark_idle(&self, agent: RuntimeAgentKey) {
|
||||
self.calls
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push((agent.agent_id, "mark_idle"));
|
||||
}
|
||||
fn busy_state(&self, _agent: AgentId) -> AgentBusyState {
|
||||
fn busy_state(&self, _agent: RuntimeAgentKey) -> AgentBusyState {
|
||||
AgentBusyState::Idle
|
||||
}
|
||||
}
|
||||
@ -169,7 +176,7 @@ async fn final_only_stream_unblocks_queue_via_mark_idle() {
|
||||
let session = ScriptedSession::new(Script::Stream(vec![final_("done")]));
|
||||
let mediator = RecordingMediator::new();
|
||||
|
||||
let out = drain_with_readiness(&session, "tâche", None, &mediator, agent).await;
|
||||
let out = drain_with_readiness(&session, "tâche", None, &mediator, key(agent)).await;
|
||||
|
||||
assert_eq!(out, Ok("done".to_owned()), "le Final rend bien son contenu");
|
||||
assert_eq!(
|
||||
@ -200,7 +207,7 @@ async fn intermediate_events_do_not_mark_idle_only_final_does() {
|
||||
]));
|
||||
let mediator = RecordingMediator::new();
|
||||
|
||||
let out = drain_with_readiness(&session, "x", None, &mediator, agent).await;
|
||||
let out = drain_with_readiness(&session, "x", None, &mediator, key(agent)).await;
|
||||
|
||||
assert_eq!(out, Ok("hello".to_owned()));
|
||||
assert_eq!(
|
||||
@ -227,7 +234,7 @@ async fn heartbeats_alone_never_mark_idle_before_final() {
|
||||
]));
|
||||
let mediator = RecordingMediator::new();
|
||||
|
||||
let out = drain_with_readiness(&session, "x", None, &mediator, agent).await;
|
||||
let out = drain_with_readiness(&session, "x", None, &mediator, key(agent)).await;
|
||||
assert_eq!(out, Ok("fini".to_owned()));
|
||||
assert_eq!(mediator.mark_idle_count(agent), 1);
|
||||
}
|
||||
@ -242,7 +249,7 @@ async fn stream_without_final_does_not_mark_idle_and_is_io_error() {
|
||||
let session = ScriptedSession::new(Script::Stream(vec![heartbeat(), delta("a"), tool("b")]));
|
||||
let mediator = RecordingMediator::new();
|
||||
|
||||
let out = drain_with_readiness(&session, "x", None, &mediator, agent).await;
|
||||
let out = drain_with_readiness(&session, "x", None, &mediator, key(agent)).await;
|
||||
assert!(
|
||||
matches!(out, Err(AgentSessionError::Io(_))),
|
||||
"flux épuisé sans Final ⇒ Io, obtenu {out:?}"
|
||||
@ -263,7 +270,7 @@ async fn send_error_is_propagated_and_no_mark_idle() {
|
||||
)));
|
||||
let mediator = RecordingMediator::new();
|
||||
|
||||
let out = drain_with_readiness(&session, "x", None, &mediator, agent).await;
|
||||
let out = drain_with_readiness(&session, "x", None, &mediator, key(agent)).await;
|
||||
assert_eq!(out, Err(AgentSessionError::Decode("bad json".to_owned())));
|
||||
assert_eq!(mediator.mark_idle_count(agent), 0);
|
||||
}
|
||||
@ -276,7 +283,7 @@ async fn mark_idle_targets_the_drained_agent_only() {
|
||||
let session = ScriptedSession::new(Script::Stream(vec![final_("ok")]));
|
||||
let mediator = RecordingMediator::new();
|
||||
|
||||
let _ = drain_with_readiness(&session, "x", None, &mediator, drained).await;
|
||||
let _ = drain_with_readiness(&session, "x", None, &mediator, key(drained)).await;
|
||||
assert_eq!(mediator.mark_idle_count(drained), 1);
|
||||
assert_eq!(
|
||||
mediator.mark_idle_count(other),
|
||||
@ -328,7 +335,7 @@ async fn timeout_returns_timeout_no_mark_idle_session_alive() {
|
||||
"x",
|
||||
Some(Duration::from_millis(20)),
|
||||
&mediator,
|
||||
agent,
|
||||
key(agent),
|
||||
)
|
||||
.await;
|
||||
assert_eq!(out, Err(AgentSessionError::Timeout));
|
||||
|
||||
Reference in New Issue
Block a user