Skip to content

Commit cf1d070

Browse files
authored
feat: grab-bag of improvements to exec output (openai#1179)
Fixes: * Instantiate `EventProcessor` earlier in `lib.rs` so `print_config_summary()` can be an instance method of it and leverage its various `Style` fields to ensure it honors `with_ansi` properly. * After printing the config summary, print out user's prompt with the heading `User instructions:`. As noted in the comment, now that we can read the instructions via stdin as of openai#1178, it is helpful to the user to ensure they know what instructions were given to Codex. * Use same colors/bold/italic settings for headers as the TUI, making the output a bit easier to read.
1 parent ae743d5 commit cf1d070

File tree

2 files changed

+50
-35
lines changed

2 files changed

+50
-35
lines changed

codex-rs/exec/src/event_processor.rs

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use chrono::Utc;
21
use codex_common::elapsed::format_elapsed;
32
use codex_core::config::Config;
43
use codex_core::protocol::AgentMessageEvent;
@@ -37,11 +36,13 @@ pub(crate) struct EventProcessor {
3736
// using .style() with one of these fields. If you need a new style, add a
3837
// new field here.
3938
bold: Style,
39+
italic: Style,
4040
dimmed: Style,
4141

4242
magenta: Style,
4343
red: Style,
4444
green: Style,
45+
cyan: Style,
4546
}
4647

4748
impl EventProcessor {
@@ -55,21 +56,25 @@ impl EventProcessor {
5556
call_id_to_command,
5657
call_id_to_patch,
5758
bold: Style::new().bold(),
59+
italic: Style::new().italic(),
5860
dimmed: Style::new().dimmed(),
5961
magenta: Style::new().magenta(),
6062
red: Style::new().red(),
6163
green: Style::new().green(),
64+
cyan: Style::new().cyan(),
6265
call_id_to_tool_call,
6366
}
6467
} else {
6568
Self {
6669
call_id_to_command,
6770
call_id_to_patch,
6871
bold: Style::new(),
72+
italic: Style::new(),
6973
dimmed: Style::new(),
7074
magenta: Style::new(),
7175
red: Style::new(),
7276
green: Style::new(),
77+
cyan: Style::new(),
7378
call_id_to_tool_call,
7479
}
7580
}
@@ -94,43 +99,47 @@ struct PatchApplyBegin {
9499
auto_approved: bool,
95100
}
96101

102+
#[macro_export]
97103
macro_rules! ts_println {
98104
($($arg:tt)*) => {{
99-
let now = Utc::now();
105+
let now = chrono::Utc::now();
100106
let formatted = now.format("%Y-%m-%dT%H:%M:%S").to_string();
101107
print!("[{}] ", formatted);
102108
println!($($arg)*);
103109
}};
104110
}
105111

106-
/// Print a concise summary of the effective configuration that will be used
107-
/// for the session. This mirrors the information shown in the TUI welcome
108-
/// screen.
109-
pub(crate) fn print_config_summary(config: &Config, with_ansi: bool) {
110-
let bold = if with_ansi {
111-
Style::new().bold()
112-
} else {
113-
Style::new()
114-
};
115-
116-
ts_println!("OpenAI Codex (research preview)\n--------");
117-
118-
let entries = vec![
119-
("workdir", config.cwd.display().to_string()),
120-
("model", config.model.clone()),
121-
("provider", config.model_provider_id.clone()),
122-
("approval", format!("{:?}", config.approval_policy)),
123-
("sandbox", format!("{:?}", config.sandbox_policy)),
124-
];
125-
126-
for (key, value) in entries {
127-
println!("{} {}", format!("{key}: ").style(bold), value);
128-
}
112+
impl EventProcessor {
113+
/// Print a concise summary of the effective configuration that will be used
114+
/// for the session. This mirrors the information shown in the TUI welcome
115+
/// screen.
116+
pub(crate) fn print_config_summary(&mut self, config: &Config, prompt: &str) {
117+
ts_println!("OpenAI Codex (research preview)\n--------");
118+
119+
let entries = vec![
120+
("workdir", config.cwd.display().to_string()),
121+
("model", config.model.clone()),
122+
("provider", config.model_provider_id.clone()),
123+
("approval", format!("{:?}", config.approval_policy)),
124+
("sandbox", format!("{:?}", config.sandbox_policy)),
125+
];
126+
127+
for (key, value) in entries {
128+
println!("{} {}", format!("{key}: ").style(self.bold), value);
129+
}
129130

130-
println!("--------\n");
131-
}
131+
println!("--------");
132+
133+
// Echo the prompt that will be sent to the agent so it is visible in the
134+
// transcript/logs before any events come in. Note the prompt may have been
135+
// read from stdin, so it may not be visible in the terminal otherwise.
136+
ts_println!(
137+
"{}\n{}",
138+
"User instructions:".style(self.bold).style(self.cyan),
139+
prompt
140+
);
141+
}
132142

133-
impl EventProcessor {
134143
pub(crate) fn process_event(&mut self, event: Event) {
135144
let Event { id: _, msg } = event;
136145
match msg {
@@ -145,8 +154,10 @@ impl EventProcessor {
145154
// Ignore.
146155
}
147156
EventMsg::AgentMessage(AgentMessageEvent { message }) => {
148-
let prefix = "Agent message:".style(self.bold);
149-
ts_println!("{prefix} {message}");
157+
ts_println!(
158+
"{}\n{message}",
159+
"codex".style(self.bold).style(self.magenta)
160+
);
150161
}
151162
EventMsg::ExecCommandBegin(ExecCommandBeginEvent {
152163
call_id,
@@ -394,7 +405,11 @@ impl EventProcessor {
394405
// Should we exit?
395406
}
396407
EventMsg::AgentReasoning(agent_reasoning_event) => {
397-
println!("thinking: {}", agent_reasoning_event.text);
408+
ts_println!(
409+
"{}\n{}",
410+
"thinking".style(self.italic).style(self.magenta),
411+
agent_reasoning_event.text
412+
);
398413
}
399414
EventMsg::SessionConfigured(session_configured_event) => {
400415
let SessionConfiguredEvent {

codex-rs/exec/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use codex_core::protocol::SandboxPolicy;
2020
use codex_core::protocol::TaskCompleteEvent;
2121
use codex_core::util::is_inside_git_repo;
2222
use event_processor::EventProcessor;
23-
use event_processor::print_config_summary;
2423
use tracing::debug;
2524
use tracing::error;
2625
use tracing::info;
@@ -113,8 +112,10 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option<PathBuf>) -> any
113112
};
114113

115114
let config = Config::load_with_cli_overrides(cli_kv_overrides, overrides)?;
116-
// Print the effective configuration so users can see what Codex is using.
117-
print_config_summary(&config, stdout_with_ansi);
115+
let mut event_processor = EventProcessor::create_with_ansi(stdout_with_ansi);
116+
// Print the effective configuration and prompt so users can see what Codex
117+
// is using.
118+
event_processor.print_config_summary(&config, &prompt);
118119

119120
if !skip_git_repo_check && !is_inside_git_repo(&config) {
120121
eprintln!("Not inside a Git repo and --skip-git-repo-check was not specified.");
@@ -204,7 +205,6 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option<PathBuf>) -> any
204205
info!("Sent prompt with event ID: {initial_prompt_task_id}");
205206

206207
// Run the loop until the task is complete.
207-
let mut event_processor = EventProcessor::create_with_ansi(stdout_with_ansi);
208208
while let Some(event) = rx.recv().await {
209209
let (is_last_event, last_assistant_message) = match &event.msg {
210210
EventMsg::TaskComplete(TaskCompleteEvent { last_agent_message }) => {

0 commit comments

Comments
 (0)