diff options
| author | JJ Liebig <jonathan.liebig@gmail.com> | 2026-09-05 02:38:14 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-05 02:38:14 +0200 |
| commit | 7916be1656d8ee9c5882b52753cd47f5e58e3e7e (patch) | |
| tree | d54015e01ecff6566bad26034ada4e8cca3d3edf /src/app/api | |
| parent | 987651a760cdfe4cd9493388e8c16b8f99643a05 (diff) | |
fix: make Windows Codex prompt delay size-aware (#3552)
refs #3187
Diffstat (limited to 'src/app/api')
| -rw-r--r-- | src/app/api/agents.rs | 39 |
1 files changed, 38 insertions, 1 deletions
diff --git a/src/app/api/agents.rs b/src/app/api/agents.rs index 3e4e83a8..cf3e5fa6 100644 --- a/src/app/api/agents.rs +++ b/src/app/api/agents.rs @@ -12,6 +12,18 @@ use super::responses::{encode_error, encode_error_body, encode_success}; const AGENT_PROMPT_SUBMIT_DELAY: Duration = Duration::from_millis(300); +fn agent_prompt_submit_delay(agent: crate::detect::Agent, prompt_bytes: usize) -> Duration { + #[cfg(windows)] + if agent == crate::detect::Agent::Codex { + // Codex consumes Windows paste bursts at about 4 bytes/ms, then suppresses Enter briefly. + // ponytail: best-effort ConPTY timing; remove when Codex exposes a paste-complete boundary. + return Duration::from_millis(600 + prompt_bytes as u64 / 4); + } + #[cfg(not(windows))] + let _ = (agent, prompt_bytes); + AGENT_PROMPT_SUBMIT_DELAY +} + impl App { pub(super) fn handle_agent_list(&mut self, id: String) -> String { encode_success( @@ -72,6 +84,9 @@ impl App { std::thread::spawn(move || { let response = match completion.recv() { Ok(Ok(())) => encode_success(id, ResponseResult::AgentPrompted { agent }), + Ok(Err(err)) if err.kind() == std::io::ErrorKind::TimedOut => { + encode_error(id, "timeout", err.to_string()) + } Ok(Err(err)) => encode_error(id, "agent_prompt_failed", err.to_string()), Err(_) => encode_error(id, "agent_prompt_failed", "pty actor closed"), }; @@ -149,6 +164,14 @@ impl App { ), )); } + let submit_delay = agent_prompt_submit_delay(expected_agent, params.text.len()); + #[cfg(windows)] + let submit_deadline = params + .wait + .as_ref() + .and_then(|wait| wait.submission_deadline); + #[cfg(not(windows))] + let submit_deadline = None; if expected_agent == crate::detect::Agent::GithubCopilot { // Copilot ignores synthetic Enter after focus loss until it receives focus gained. let focus = match crate::ghostty::encode_focus(crate::ghostty::FocusEvent::Gained) { @@ -170,7 +193,8 @@ impl App { .queue_user_input_submission( Bytes::from(text), Bytes::from(enter), - AGENT_PROMPT_SUBMIT_DELAY, + submit_delay, + submit_deadline, ) .map_err(|err| encode_error(id.clone(), "agent_prompt_failed", err.to_string()))?; Ok((id, agent, completion)) @@ -400,6 +424,19 @@ mod tests { .expect("agent prompt responds after submission") } + #[test] + fn prompt_delay_only_scales_for_windows_codex() { + let codex_delay = agent_prompt_submit_delay(Agent::Codex, 4_096); + #[cfg(windows)] + assert_eq!(codex_delay, Duration::from_millis(1_624)); + #[cfg(not(windows))] + assert_eq!(codex_delay, AGENT_PROMPT_SUBMIT_DELAY); + assert_eq!( + agent_prompt_submit_delay(Agent::OpenCode, 4_096), + AGENT_PROMPT_SUBMIT_DELAY + ); + } + #[tokio::test] async fn agent_prompt_sends_text_then_delays_enter() { let mut app = app_with_agent(); |
