fix(session): final de secours fabriqué depuis les deltas quand Claude ferme sans ligne result — #239
append_text_fallback_final accumule les TextDelta et produit un Final uniqne en fin de flux si aucun Final/Error/RateLimited n'a été émis et que le texte est non vide. Un long message utilisateur sur un autre projet (GameTime) ne conclut plus a tort « La réponse du modèle n'a pas pu être finalisée. ». Le test qui pinnait l'absence de Final devient la régression #239.
This commit is contained in:
@ -1513,11 +1513,10 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// LIMITE/ÉCART (à arbitrer) : un flux SANS `Final` ne provoque PAS d'erreur au
|
||||
/// niveau de l'adapter — `send()` renvoie Ok avec uniquement des deltas et AUCUN
|
||||
/// `Final`. Le §17.9 D2 mentionne « flux sans Final ⇒ Io » ; l'adapter actuel ne
|
||||
/// l'applique pas (c'est `send_blocking` côté application, lot D1, qui transforme
|
||||
/// l'absence de Final en Timeout). Ce test PINNE le comportement réel observé.
|
||||
/// Régression #239 : Claude peut fermer proprement après des blocs `assistant`
|
||||
/// textuels sans ligne `result`. Ces deltas sont une réponse modèle exploitable :
|
||||
/// l'adapter doit donc fabriquer un `Final` de secours, au lieu de laisser la
|
||||
/// surface chat conclure à tort « réponse non finalisée ».
|
||||
#[tokio::test]
|
||||
async fn stream_without_final_is_silently_ok_at_adapter_level() {
|
||||
let fake = FakeCli::printing(&[
|
||||
@ -1533,11 +1532,18 @@ mod tests {
|
||||
None,
|
||||
);
|
||||
let events: Vec<_> = s.send("x").await.expect("send ok").collect();
|
||||
let finals = events
|
||||
let finals: Vec<_> = events
|
||||
.iter()
|
||||
.filter(|e| matches!(e, ReplyEvent::Final { .. }))
|
||||
.count();
|
||||
assert_eq!(finals, 0, "comportement actuel: aucun Final fabriqué");
|
||||
.filter_map(|e| match e {
|
||||
ReplyEvent::Final { content } => Some(content.as_str()),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
assert_eq!(
|
||||
finals,
|
||||
vec!["a"],
|
||||
"Claude text-only streams must yield one fallback Final"
|
||||
);
|
||||
// L'id de conversation est tout de même capté (init lu).
|
||||
assert_eq!(s.conversation_id().as_deref(), Some("c"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user