fix(session-limit): émettre AgentRateLimited sur le chemin délégué (#7)
Sur le rendez-vous délégué (idea_ask_agent), quand la cible touchait sa limite de session, l'événement AgentRateLimited n'était pas émis : l'écart backend documenté (ticket #7/F2) laissait la surface UI sans signal de limite pour la cible déléguée. Le service orchestrateur relaie désormais la limite de la cible vers le service de limite de session, fermant l'écart en cohérence avec le chemin direct (#30). Couverture QA (sortie réelle) : orchestrator_service 63 passed, session_limit_service 15 passed, session_limit_t4 7 passed, cargo test -p application 0 failed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -20,8 +20,8 @@ pub(crate) use lifecycle::ReattachDecision;
|
||||
pub use session_limit::{AgentResumer, SessionLimitService, RESUME_PROMPT};
|
||||
pub use structured::{
|
||||
drain_reply_stream_with_readiness, drain_with_readiness,
|
||||
drain_with_readiness_and_announcements, drain_with_readiness_outcome, send_blocking,
|
||||
AnnouncementPublisher, TurnOutcome,
|
||||
drain_with_readiness_and_announcements, drain_with_readiness_and_announcements_outcome,
|
||||
drain_with_readiness_outcome, send_blocking, AnnouncementPublisher, TurnOutcome,
|
||||
};
|
||||
|
||||
pub use catalogue::{
|
||||
|
||||
@ -167,8 +167,35 @@ pub async fn drain_with_readiness_and_announcements(
|
||||
agent: AgentId,
|
||||
announcements: Option<AnnouncementPublisher>,
|
||||
) -> Result<String, AgentSessionError> {
|
||||
match drain_with_readiness_and_announcements_outcome(
|
||||
session,
|
||||
prompt,
|
||||
timeout,
|
||||
mediator,
|
||||
agent,
|
||||
announcements,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
TurnOutcome::Completed(content) => Ok(content),
|
||||
TurnOutcome::RateLimited { .. } => Err(AgentSessionError::Io(
|
||||
"le tour s'est clos en limite de session, sans contenu Final".to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Comme [`drain_with_readiness_and_announcements`], mais conserve l'issue riche
|
||||
/// [`TurnOutcome::RateLimited`] pour les appelants capables d'armer la reprise.
|
||||
pub async fn drain_with_readiness_and_announcements_outcome(
|
||||
session: &dyn AgentSession,
|
||||
prompt: &str,
|
||||
timeout: Option<Duration>,
|
||||
mediator: &dyn InputMediator,
|
||||
agent: AgentId,
|
||||
announcements: Option<AnnouncementPublisher>,
|
||||
) -> Result<TurnOutcome, AgentSessionError> {
|
||||
let Some(publisher) = announcements else {
|
||||
return drain_with_readiness(session, prompt, timeout, mediator, agent).await;
|
||||
return drain_with_readiness_outcome(session, prompt, timeout, mediator, agent).await;
|
||||
};
|
||||
|
||||
let (tap_tx, tap_rx) = std::sync::mpsc::channel();
|
||||
@ -188,7 +215,7 @@ pub async fn drain_with_readiness_and_announcements(
|
||||
let _ = live_pump.join();
|
||||
let stream = stream_result?;
|
||||
|
||||
match drain_stream_to_final(
|
||||
drain_stream_to_final(
|
||||
stream,
|
||||
|event| {
|
||||
if !matches!(event, ReplyEvent::Final { .. }) {
|
||||
@ -201,12 +228,7 @@ pub async fn drain_with_readiness_and_announcements(
|
||||
mediator.mark_idle(agent);
|
||||
}
|
||||
},
|
||||
)? {
|
||||
TurnOutcome::Completed(content) => Ok(content),
|
||||
TurnOutcome::RateLimited { .. } => Err(AgentSessionError::Io(
|
||||
"le tour s'est clos en limite de session, sans contenu Final".to_string(),
|
||||
)),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Draine un flux de réponse déjà ouvert, avec la même politique de readiness que
|
||||
|
||||
Reference in New Issue
Block a user