mirror of
https://github.com/openai/codex.git
synced 2026-10-24 18:18:41 +00:00
Handle partial answers consistently across agent workflows (#51249)
## Why Partial answers contain answer fragments while a turn is still in progress. Treating them as final answers defers mailbox delivery and can count empty fragments as empty final responses; filtering them from forked histories and guardian transcripts loses answer content. ## What changed - Allow mailbox preemption after `partial_answer` messages and keep mailbox delivery open. - Preserve partial answers in forked agent histories and include them as protected assistant entries in guardian transcripts. - Exclude empty partial answers from empty-final-response accounting for goals. ## Testing Add regression coverage for partial-answer phases in live events, sampling continuations, follow-up requests, and forked child requests, plus mailbox preemption, goal accounting, and guardian transcript inclusion. GitOrigin-RevId: 208c8933e211b42b6c2d0bec6952527b8c9c120e
This commit is contained in:
@@ -172,7 +172,7 @@ impl GoalAccountingState {
|
||||
});
|
||||
turn.has_activity |= has_text || message.questions.is_some();
|
||||
turn.empty_final |=
|
||||
!has_text && !matches!(message.phase, Some(MessagePhase::Commentary));
|
||||
!has_text && matches!(message.phase, Some(MessagePhase::FinalAnswer) | None);
|
||||
}
|
||||
TurnItem::Reasoning(reasoning) => {
|
||||
turn.has_activity |= reasoning
|
||||
|
||||
@@ -76,6 +76,7 @@ fn empty_continuations_require_three_turns_without_activity_or_goal_changes() {
|
||||
("goal", 5),
|
||||
("reset", 6),
|
||||
("missing final", 6),
|
||||
("partial answer", 6),
|
||||
] {
|
||||
let state = GoalAccountingState::default();
|
||||
for turn in 1..=blocking_turn {
|
||||
@@ -87,7 +88,13 @@ fn empty_continuations_require_three_turns_without_activity_or_goal_changes() {
|
||||
};
|
||||
state.start_turn(&id, ModeKind::Default, &TokenUsage::default());
|
||||
state.mark_turn_goal_active(&id, goal_id);
|
||||
if !(turn == 3 && interruption == "missing final") {
|
||||
if turn == 3 && interruption == "partial answer" {
|
||||
let mut partial = empty_final.clone();
|
||||
if let TurnItem::AgentMessage(message) = &mut partial {
|
||||
message.phase = Some(MessagePhase::PartialAnswer);
|
||||
}
|
||||
state.record_item(&id, &partial);
|
||||
} else if !(turn == 3 && interruption == "missing final") {
|
||||
state.record_item(&id, &empty_final);
|
||||
}
|
||||
// Admission can finish after output arrives, but before turn-stop evaluation.
|
||||
|
||||
Reference in New Issue
Block a user