feat(backend): modèle unifié streaming/progress/events provider-agnostic + pont app-tauri — foundation #156 (QA verte)

This commit is contained in:
2026-08-06 13:13:17 +02:00
parent 40fa551f32
commit 918116664c
14 changed files with 630 additions and 59 deletions

View File

@ -84,7 +84,8 @@ impl ReadinessPolicy {
/// n'a pas rendu son `Final`), mais porteur d'un signal exploitable par
/// l'application (planifier la reprise à `resets_at_ms`). L'heure de reset est
/// propagée telle quelle.
/// - [`ReplyEvent::TextDelta`] / [`ReplyEvent::Announcement`] /
/// - [`ReplyEvent::Progress`] /
/// [`ReplyEvent::TextDelta`] / [`ReplyEvent::Announcement`] /
/// [`ReplyEvent::Error`] /
/// [`ReplyEvent::ToolActivity`] /
/// [`ReplyEvent::Heartbeat`] ⇒ `None` : tous **non terminaux** (le flux
@ -96,7 +97,8 @@ impl ReadinessPolicy {
ReplyEvent::RateLimited { resets_at_ms } => Some(ReadinessSignal::RateLimited {
resets_at_ms: *resets_at_ms,
}),
ReplyEvent::TextDelta { .. }
ReplyEvent::Progress { .. }
| ReplyEvent::TextDelta { .. }
| ReplyEvent::Announcement { .. }
| ReplyEvent::Error { .. }
| ReplyEvent::ToolActivity { .. }
@ -108,6 +110,7 @@ impl ReadinessPolicy {
#[cfg(test)]
mod tests {
use super::*;
use crate::ports::{ReplyProgress, ReplyProgressKind, ReplyProgressSource, ReplyProgressStage};
#[test]
fn final_classifies_as_turn_ended() {
@ -122,6 +125,18 @@ mod tests {
#[test]
fn deltas_activities_and_heartbeats_are_non_terminal() {
assert_eq!(
ReadinessPolicy::classify(&ReplyEvent::Progress {
progress: ReplyProgress::new(
ReplyProgressSource::ProviderNative,
ReplyProgressKind::Turn,
ReplyProgressStage::Started,
"tour démarré",
)
}),
None,
"un progress provider est projetable avant Final mais ne termine JAMAIS le tour"
);
assert_eq!(
ReadinessPolicy::classify(&ReplyEvent::TextDelta { text: "x".into() }),
None