fix(runtime): isolate agent state by project (#101)
This commit is contained in:
@ -13,7 +13,7 @@ use std::sync::Mutex;
|
||||
use async_trait::async_trait;
|
||||
|
||||
use application::{drain_with_readiness, drain_with_readiness_outcome, send_blocking, TurnOutcome};
|
||||
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};
|
||||
@ -24,6 +24,10 @@ fn aid(n: u128) -> AgentId {
|
||||
AgentId::from_uuid(Uuid::from_u128(n))
|
||||
}
|
||||
|
||||
fn key(n: u128) -> RuntimeAgentKey {
|
||||
RuntimeAgentKey::new(ProjectId::from_uuid(Uuid::nil()), aid(n))
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Fake AgentSession : `send` rejoue une liste fixe d'événements.
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -57,17 +61,17 @@ struct RecordingMediator {
|
||||
calls: Mutex<Vec<&'static str>>,
|
||||
}
|
||||
impl InputMediator for RecordingMediator {
|
||||
fn enqueue(&self, _agent: AgentId, _ticket: Ticket) -> PendingReply {
|
||||
fn enqueue(&self, _agent: RuntimeAgentKey, _ticket: Ticket) -> PendingReply {
|
||||
PendingReply::new(Box::pin(std::future::pending()))
|
||||
}
|
||||
fn preempt(&self, _agent: AgentId) {}
|
||||
fn mark_idle(&self, _agent: AgentId) {
|
||||
fn preempt(&self, _agent: RuntimeAgentKey) {}
|
||||
fn mark_idle(&self, _agent: RuntimeAgentKey) {
|
||||
self.calls.lock().unwrap().push("idle");
|
||||
}
|
||||
fn mark_alive(&self, _agent: AgentId) {
|
||||
fn mark_alive(&self, _agent: RuntimeAgentKey) {
|
||||
self.calls.lock().unwrap().push("alive");
|
||||
}
|
||||
fn busy_state(&self, _agent: AgentId) -> AgentBusyState {
|
||||
fn busy_state(&self, _agent: RuntimeAgentKey) -> AgentBusyState {
|
||||
AgentBusyState::Idle
|
||||
}
|
||||
}
|
||||
@ -86,7 +90,7 @@ async fn outcome_rate_limited_some_without_final_is_graceful() {
|
||||
}],
|
||||
};
|
||||
let mediator = RecordingMediator::default();
|
||||
let out = drain_with_readiness_outcome(&session, "go", None, &mediator, aid(1))
|
||||
let out = drain_with_readiness_outcome(&session, "go", None, &mediator, key(1))
|
||||
.await
|
||||
.expect("un tour limité est une fin gracieuse, pas une erreur");
|
||||
assert_eq!(
|
||||
@ -109,7 +113,7 @@ async fn outcome_rate_limited_none_without_final_is_graceful() {
|
||||
events: vec![ReplyEvent::RateLimited { resets_at_ms: None }],
|
||||
};
|
||||
let mediator = RecordingMediator::default();
|
||||
let out = drain_with_readiness_outcome(&session, "go", None, &mediator, aid(1))
|
||||
let out = drain_with_readiness_outcome(&session, "go", None, &mediator, key(1))
|
||||
.await
|
||||
.expect("fin gracieuse");
|
||||
assert_eq!(out, TurnOutcome::RateLimited { resets_at_ms: None });
|
||||
@ -131,7 +135,7 @@ async fn outcome_rate_limited_then_final_is_completed() {
|
||||
],
|
||||
};
|
||||
let mediator = RecordingMediator::default();
|
||||
let out = drain_with_readiness_outcome(&session, "go", None, &mediator, aid(1))
|
||||
let out = drain_with_readiness_outcome(&session, "go", None, &mediator, key(1))
|
||||
.await
|
||||
.expect("ok");
|
||||
assert_eq!(out, TurnOutcome::Completed("fini".to_owned()));
|
||||
@ -147,7 +151,7 @@ async fn outcome_truncated_stream_without_final_or_ratelimit_is_io_error() {
|
||||
events: vec![ReplyEvent::TextDelta { text: "a".into() }],
|
||||
};
|
||||
let mediator = RecordingMediator::default();
|
||||
let err = drain_with_readiness_outcome(&session, "go", None, &mediator, aid(1))
|
||||
let err = drain_with_readiness_outcome(&session, "go", None, &mediator, key(1))
|
||||
.await
|
||||
.expect_err("flux tronqué sans limite ⇒ erreur");
|
||||
assert!(matches!(err, AgentSessionError::Io(_)), "vu: {err:?}");
|
||||
@ -167,7 +171,7 @@ async fn drain_with_readiness_rate_limited_is_io_error() {
|
||||
}],
|
||||
};
|
||||
let mediator = RecordingMediator::default();
|
||||
let err = drain_with_readiness(&session, "go", None, &mediator, aid(1))
|
||||
let err = drain_with_readiness(&session, "go", None, &mediator, key(1))
|
||||
.await
|
||||
.expect_err("limite ⇒ Io sur la signature historique");
|
||||
assert!(matches!(err, AgentSessionError::Io(_)), "vu: {err:?}");
|
||||
@ -197,7 +201,7 @@ async fn drain_with_readiness_nominal_still_completes() {
|
||||
],
|
||||
};
|
||||
let mediator = RecordingMediator::default();
|
||||
let content = drain_with_readiness(&session, "go", None, &mediator, aid(1))
|
||||
let content = drain_with_readiness(&session, "go", None, &mediator, key(1))
|
||||
.await
|
||||
.expect("ok");
|
||||
assert_eq!(content, "fini");
|
||||
|
||||
Reference in New Issue
Block a user