mirror of
https://github.com/openai/codex.git
synced 2026-11-03 08:22:30 +00:00
Fix missing resume hint on zero-token exits (#16987)
Addresses #16421 Problem: Resumed interactive sessions exited before new token usage skipped all footer lines, hiding the `codex resume` continuation command. It's not clear whether this was an intentional design choice, but I think it's reasonable to expect this message under these circumstances. Solution: Compose token usage and resume hints independently so resumable sessions still print the continuation command with zero usage.
This commit is contained in:
1 parent
cd591dc457
commit
2b9bf5d3d4
2 files changed
+25
-18
No files matched your search
@@ -438,15 +438,14 @@ fn format_exit_messages(exit_info: AppExitInfo, color_enabled: bool) -> Vec<Stri
|
|||||||
..
|
..
|
||||||
} = exit_info;
|
} = exit_info;
|
||||||
|
|
||||||
if token_usage.is_zero() {
|
let mut lines = Vec::new();
|
||||||
return Vec::new();
|
if !token_usage.is_zero() {
|
||||||
|
lines.push(format!(
|
||||||
|
"{}",
|
||||||
|
codex_protocol::protocol::FinalOutput::from(token_usage)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut lines = vec![format!(
|
|
||||||
"{}",
|
|
||||||
codex_protocol::protocol::FinalOutput::from(token_usage)
|
|
||||||
)];
|
|
||||||
|
|
||||||
if let Some(resume_cmd) =
|
if let Some(resume_cmd) =
|
||||||
codex_core::util::resume_command(thread_name.as_deref(), conversation_id)
|
codex_core::util::resume_command(thread_name.as_deref(), conversation_id)
|
||||||
{
|
{
|
||||||
|
|||||||
+19
-11
@@ -316,12 +316,13 @@ fn session_summary(
|
|||||||
thread_id: Option<ThreadId>,
|
thread_id: Option<ThreadId>,
|
||||||
thread_name: Option<String>,
|
thread_name: Option<String>,
|
||||||
) -> Option<SessionSummary> {
|
) -> Option<SessionSummary> {
|
||||||
if token_usage.is_zero() {
|
let usage_line = (!token_usage.is_zero()).then(|| FinalOutput::from(token_usage).to_string());
|
||||||
|
let resume_command = codex_core::util::resume_command(thread_name.as_deref(), thread_id);
|
||||||
|
|
||||||
|
if usage_line.is_none() && resume_command.is_none() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let usage_line = FinalOutput::from(token_usage).to_string();
|
|
||||||
let resume_command = codex_core::util::resume_command(thread_name.as_deref(), thread_id);
|
|
||||||
Some(SessionSummary {
|
Some(SessionSummary {
|
||||||
usage_line,
|
usage_line,
|
||||||
resume_command,
|
resume_command,
|
||||||
@@ -486,7 +487,7 @@ fn emit_system_bwrap_warning(app_event_tx: &AppEventSender, config: &Config) {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
struct SessionSummary {
|
struct SessionSummary {
|
||||||
usage_line: String,
|
usage_line: Option<String>,
|
||||||
resume_command: Option<String>,
|
resume_command: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3301,7 +3302,10 @@ impl App {
|
|||||||
"Failed to attach to fresh app-server thread: {err}"
|
"Failed to attach to fresh app-server thread: {err}"
|
||||||
));
|
));
|
||||||
} else if let Some(summary) = summary {
|
} else if let Some(summary) = summary {
|
||||||
let mut lines: Vec<Line<'static>> = vec![summary.usage_line.clone().into()];
|
let mut lines: Vec<Line<'static>> = Vec::new();
|
||||||
|
if let Some(usage_line) = summary.usage_line {
|
||||||
|
lines.push(usage_line.into());
|
||||||
|
}
|
||||||
if let Some(command) = summary.resume_command {
|
if let Some(command) = summary.resume_command {
|
||||||
let spans = vec!["To continue this session, run ".into(), command.cyan()];
|
let spans = vec!["To continue this session, run ".into(), command.cyan()];
|
||||||
lines.push(spans.into());
|
lines.push(spans.into());
|
||||||
@@ -4114,8 +4118,10 @@ impl App {
|
|||||||
{
|
{
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
if let Some(summary) = summary {
|
if let Some(summary) = summary {
|
||||||
let mut lines: Vec<Line<'static>> =
|
let mut lines: Vec<Line<'static>> = Vec::new();
|
||||||
vec![summary.usage_line.clone().into()];
|
if let Some(usage_line) = summary.usage_line {
|
||||||
|
lines.push(usage_line.into());
|
||||||
|
}
|
||||||
if let Some(command) = summary.resume_command {
|
if let Some(command) = summary.resume_command {
|
||||||
let spans = vec![
|
let spans = vec![
|
||||||
"To continue this session, run ".into(),
|
"To continue this session, run ".into(),
|
||||||
@@ -4174,8 +4180,10 @@ impl App {
|
|||||||
{
|
{
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
if let Some(summary) = summary {
|
if let Some(summary) = summary {
|
||||||
let mut lines: Vec<Line<'static>> =
|
let mut lines: Vec<Line<'static>> = Vec::new();
|
||||||
vec![summary.usage_line.clone().into()];
|
if let Some(usage_line) = summary.usage_line {
|
||||||
|
lines.push(usage_line.into());
|
||||||
|
}
|
||||||
if let Some(command) = summary.resume_command {
|
if let Some(command) = summary.resume_command {
|
||||||
let spans = vec![
|
let spans = vec![
|
||||||
"To continue this session, run ".into(),
|
"To continue this session, run ".into(),
|
||||||
@@ -10897,7 +10905,7 @@ guardian_approval = true
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn session_summary_skip_zero_usage() {
|
async fn session_summary_skips_when_no_usage_or_resume_hint() {
|
||||||
assert!(
|
assert!(
|
||||||
session_summary(
|
session_summary(
|
||||||
TokenUsage::default(),
|
TokenUsage::default(),
|
||||||
@@ -10922,7 +10930,7 @@ guardian_approval = true
|
|||||||
session_summary(usage, Some(conversation), /*thread_name*/ None).expect("summary");
|
session_summary(usage, Some(conversation), /*thread_name*/ None).expect("summary");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
summary.usage_line,
|
summary.usage_line,
|
||||||
"Token usage: total=12 input=10 output=2"
|
Some("Token usage: total=12 input=10 output=2".to_string())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
summary.resume_command,
|
summary.resume_command,
|
||||||
|
|||||||
Reference in new issue
Block a user