Un agent_message d'intention arrivant avant un tool (ex idea_ask_agent) n'est plus avalé comme faux candidat Final: tamponné puis reclassé en Announcement dès qu'un événement le détrône (helper event_supersedes_pending_final), sur le tap live comme sur le flux autoritatif. Les items reasoning/command n'émettent plus de ToolActivity de compatibilité en doublon du Progress canonique Completed -> supprime les doubles cartes tool/MCP à la source. Tests mod.rs alignés + nouveau cas agent_message_before_tool_becomes_announcement_before_tool_progress.
This commit is contained in:
@ -57,7 +57,8 @@ pub struct ParsedLine {
|
||||
/// c'est la réponse) ; si `item.type=="error"` ⇒ [`ReplyEvent::Error`] avec message
|
||||
/// extrait de `item.text`, `item.message`, `item.error.message`, `item.error`, puis
|
||||
/// des champs top-level `stderr`/`message`/`error.message`/`error` ; sinon
|
||||
/// (`reasoning`/`command`/autre) ⇒ [`ReplyEvent::ToolActivity`] (`label` = `item.type`).
|
||||
/// (`reasoning`/`command`/autre) ⇒ progression canonique `Completed` (`label` =
|
||||
/// `item.type`).
|
||||
/// - `{"type":"conversation.item.done","item":{…}}` est traité comme `item.completed`
|
||||
/// (Codex CLI ≥ 0.147).
|
||||
/// - `{"type":"turn.completed","usage":{…}}` ⇒ [`ReplyEvent::Heartbeat`] (le `Final`
|
||||
@ -150,7 +151,7 @@ pub fn parse_event(line: &str) -> Result<ParsedLine, AgentSessionError> {
|
||||
message: codex_error_message(&value, item),
|
||||
});
|
||||
}
|
||||
// reasoning / command / tout autre item ⇒ activité (label = type).
|
||||
// reasoning / command / tout autre item ⇒ progression canonique.
|
||||
Some(kind) => {
|
||||
let label = item_label(item).unwrap_or_else(|| kind.to_owned());
|
||||
events.push(ReplyEvent::Progress {
|
||||
@ -163,7 +164,6 @@ pub fn parse_event(line: &str) -> Result<ParsedLine, AgentSessionError> {
|
||||
.unwrap_or("item.completed"),
|
||||
),
|
||||
});
|
||||
events.push(ReplyEvent::ToolActivity { label });
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
@ -230,9 +230,6 @@ fn append_item_progress(
|
||||
events.push(ReplyEvent::Progress {
|
||||
progress: item_progress(&label, stage, native_event),
|
||||
});
|
||||
if stage == ReplyProgressStage::Started {
|
||||
events.push(ReplyEvent::ToolActivity { label });
|
||||
}
|
||||
}
|
||||
|
||||
fn item_type(item: &Value) -> Option<String> {
|
||||
@ -554,11 +551,25 @@ impl CodexExecSession {
|
||||
let (line_tap, parser_thread) = tap.map_or((None, None), |event_tap| {
|
||||
let (line_tx, line_rx) = std::sync::mpsc::channel::<String>();
|
||||
let parser = std::thread::spawn(move || {
|
||||
let mut pending_final: Option<String> = None;
|
||||
for line in line_rx {
|
||||
if let Ok(parsed) = parse_event(&line) {
|
||||
for event in parsed.events {
|
||||
if !matches!(event, ReplyEvent::Final { .. }) {
|
||||
let _ = event_tap.send(event);
|
||||
match event {
|
||||
ReplyEvent::Final { content } => {
|
||||
if let Some(text) = pending_final.replace(content) {
|
||||
let _ = event_tap.send(ReplyEvent::Announcement { text });
|
||||
}
|
||||
}
|
||||
other => {
|
||||
if event_supersedes_pending_final(&other) {
|
||||
if let Some(text) = pending_final.take() {
|
||||
let _ =
|
||||
event_tap.send(ReplyEvent::Announcement { text });
|
||||
}
|
||||
}
|
||||
let _ = event_tap.send(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -597,11 +608,22 @@ impl CodexExecSession {
|
||||
events.push(ReplyEvent::Announcement {
|
||||
text: last_final.take().expect("présent"),
|
||||
});
|
||||
} else {
|
||||
let _ = last_final.take();
|
||||
}
|
||||
}
|
||||
last_final = Some(content);
|
||||
}
|
||||
other => {
|
||||
if last_final.is_some() && event_supersedes_pending_final(&other) {
|
||||
if !has_tap {
|
||||
events.push(ReplyEvent::Announcement {
|
||||
text: last_final.take().expect("présent"),
|
||||
});
|
||||
} else {
|
||||
let _ = last_final.take();
|
||||
}
|
||||
}
|
||||
if !has_tap {
|
||||
events.push(other);
|
||||
}
|
||||
@ -621,3 +643,17 @@ impl CodexExecSession {
|
||||
Ok(Box::new(events.into_iter()))
|
||||
}
|
||||
}
|
||||
|
||||
fn event_supersedes_pending_final(event: &ReplyEvent) -> bool {
|
||||
!matches!(
|
||||
event,
|
||||
ReplyEvent::Heartbeat
|
||||
| ReplyEvent::RateLimited { .. }
|
||||
| ReplyEvent::Progress {
|
||||
progress: ReplyProgress {
|
||||
kind: ReplyProgressKind::Turn,
|
||||
..
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user