mirror of
https://github.com/openai/codex.git
synced 2026-10-18 17:18:52 +00:00
Identify local background servers in /status (#46905)
## What changed Rename the `/status` connection row from `Remote` to `Server`. For local daemon connections, display `Local background server` instead of the socket address and version. Keep the address and version for remote connections, including explicitly configured Unix sockets. ## Testing Add a local background server snapshot and coverage distinguishing local daemon connections from remote Unix sockets. Update daemon startup and worktree tests to expect the new label. GitOrigin-RevId: 9460415fe1ec16d90f575917c1a4ce1bf19faaaf
This commit is contained in:
@@ -117,7 +117,7 @@ async fn daemon_startup(command: &str) -> Result<()> {
|
||||
let expected = if command == "start" {
|
||||
// The draft header is visible before the session's command composer is ready.
|
||||
steps.push_back(("GPT-5.6-Terra", b"/status\r"));
|
||||
"app-server-control.sock"
|
||||
"Server:Localbackgroundserver"
|
||||
} else if bedrock_onboarding {
|
||||
"UseAmazonBedrock"
|
||||
} else {
|
||||
@@ -177,7 +177,6 @@ async fn daemon_startup(command: &str) -> Result<()> {
|
||||
output.clear();
|
||||
} else if steps.is_empty() && text.contains(expected) {
|
||||
if command == "start" {
|
||||
ensure!(text.contains("unix://"));
|
||||
ensure!(home.path().join("app-server-daemon/daemon.pid").exists());
|
||||
} else if let Some(existing_daemon) = &existing_daemon {
|
||||
ensure!(fs::read(&pid_file)? == *existing_daemon);
|
||||
|
||||
@@ -498,7 +498,7 @@ trust_level = "trusted"
|
||||
if backend == "daemon" && !analytics && matches!(observed, Ok(Ok(_))) {
|
||||
session.writer_sender().send(b"/status\r".to_vec()).await?;
|
||||
tokio::time::timeout(Duration::from_secs(/*secs*/ 10), async {
|
||||
while !output.contains("app-server-control.sock") {
|
||||
while !output.contains("Local background server") {
|
||||
let bytes = stdout
|
||||
.recv()
|
||||
.await
|
||||
|
||||
@@ -82,6 +82,7 @@ async fn daemon_menu_is_read_only_and_confirmation_can_cancel_or_handoff() {
|
||||
app.chat_widget.remote_connection = Some(RemoteConnectionStatus {
|
||||
address: "local".into(),
|
||||
version: "v0.153.0".into(),
|
||||
is_local_daemon: true,
|
||||
});
|
||||
app.initialize_server_version_notice("0.154.0", Some("0.153.0"));
|
||||
let view = app.agents_overview_view(Vec::new(), /*selected_thread_id*/ None);
|
||||
@@ -213,6 +214,7 @@ async fn unavailable_daemon_menu_offers_guidance_without_update_actions() {
|
||||
app.chat_widget.remote_connection = Some(RemoteConnectionStatus {
|
||||
address: "ws://example.test:1234".into(),
|
||||
version: "v0.153.0".into(),
|
||||
is_local_daemon: false,
|
||||
});
|
||||
app.open_daemon_menu();
|
||||
insta::assert_snapshot!(
|
||||
|
||||
@@ -155,6 +155,7 @@ async fn misalignment_policy_failure_stops_the_thread_and_renders_once() {
|
||||
chat.remote_connection = Some(crate::status::remote_connection::RemoteConnectionStatus {
|
||||
address: "wss://remote.example.com".to_string(),
|
||||
version: "v1.0.0".to_string(),
|
||||
is_local_daemon: false,
|
||||
});
|
||||
chat.show_misalignment_policy_precaution();
|
||||
assert_chatwidget_snapshot!(
|
||||
|
||||
@@ -532,6 +532,7 @@ async fn status_command_requests_thread_usage_for_remote_connection_metadata() {
|
||||
chat.remote_connection = Some(crate::status::remote_connection::RemoteConnectionStatus {
|
||||
address: "wss://remote.example.com".to_string(),
|
||||
version: "v1.0.0".to_string(),
|
||||
is_local_daemon: false,
|
||||
});
|
||||
|
||||
chat.dispatch_command(SlashCommand::Status);
|
||||
|
||||
@@ -824,18 +824,20 @@ impl StatusHistoryCell {
|
||||
lines.push(Line::from(Vec::<Span<'static>>::new()));
|
||||
}
|
||||
if let Some(remote_connection) = self.remote_connection.as_ref() {
|
||||
let wrapped_remote = word_wrap_lines(
|
||||
[Line::from(vec![
|
||||
let value = if remote_connection.is_local_daemon {
|
||||
Line::from("Local background server")
|
||||
} else {
|
||||
Line::from(vec![
|
||||
Span::from(remote_connection.address.clone()),
|
||||
Span::from(" (").dim(),
|
||||
Span::from(remote_connection.version.clone()).dim(),
|
||||
Span::from(")").dim(),
|
||||
])],
|
||||
RtOptions::new(value_width.max(1)),
|
||||
);
|
||||
])
|
||||
};
|
||||
let wrapped_remote = word_wrap_lines([value], RtOptions::new(value_width.max(1)));
|
||||
let mut wrapped_remote = wrapped_remote.into_iter();
|
||||
if let Some(first) = wrapped_remote.next() {
|
||||
lines.push(formatter.line("Remote", first.spans));
|
||||
lines.push(formatter.line("Server", first.spans));
|
||||
lines.extend(wrapped_remote.map(|line| formatter.continuation(line.spans)));
|
||||
}
|
||||
lines.push(Line::from(Vec::<Span<'static>>::new()));
|
||||
|
||||
@@ -9,6 +9,7 @@ use url::Url;
|
||||
pub(crate) struct RemoteConnectionStatus {
|
||||
pub(crate) address: String,
|
||||
pub(crate) version: String,
|
||||
pub(crate) is_local_daemon: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@@ -40,7 +41,11 @@ pub(crate) fn remote_connection_status_value(
|
||||
let version = server_version
|
||||
.map(|version| format!("v{version}"))
|
||||
.unwrap_or_else(|| "unknown".to_string());
|
||||
Some(RemoteConnectionStatus { address, version })
|
||||
Some(RemoteConnectionStatus {
|
||||
address,
|
||||
version,
|
||||
is_local_daemon: matches!(app_server_target, AppServerTarget::LocalDaemon { .. }),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn server_version_notice(client: &str, server: Option<&str>) -> Option<String> {
|
||||
@@ -187,6 +192,7 @@ mod tests {
|
||||
Some(RemoteConnectionStatus {
|
||||
address: "ws://127.0.0.1:4500/".to_string(),
|
||||
version: "v1.2.3".to_string(),
|
||||
is_local_daemon: false,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -202,6 +208,20 @@ mod tests {
|
||||
Some(RemoteConnectionStatus {
|
||||
address: format!("unix://{}", socket_path.display()),
|
||||
version: "unknown".to_string(),
|
||||
is_local_daemon: true,
|
||||
})
|
||||
);
|
||||
let remote_socket_target = AppServerTarget::Remote {
|
||||
endpoint: RemoteAppServerEndpoint::UnixSocket {
|
||||
socket_path: socket_path.clone(),
|
||||
},
|
||||
};
|
||||
assert_eq!(
|
||||
remote_connection_status_value(&remote_socket_target, Some("1.2.3")),
|
||||
Some(RemoteConnectionStatus {
|
||||
address: format!("unix://{}", socket_path.display()),
|
||||
version: "v1.2.3".to_string(),
|
||||
is_local_daemon: false,
|
||||
})
|
||||
);
|
||||
Ok(())
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
---
|
||||
source: tui/src/status/tests.rs
|
||||
expression: sanitized
|
||||
---
|
||||
/status
|
||||
|
||||
╭─────────────────────────────────────────────────────────────────────────────╮
|
||||
│ >_ OpenAI Codex (v0.0.0) │
|
||||
│ │
|
||||
│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │
|
||||
│ information on rate limits and credits │
|
||||
│ │
|
||||
│ Server: Local background server │
|
||||
│ │
|
||||
│ Model: gpt-5.1-codex-max (reasoning medium, summaries auto) │
|
||||
│ Directory: [[workspace]] │
|
||||
│ Permissions: Custom (workspace with network access, Ask for approval) │
|
||||
│ Agents.md: <none> │
|
||||
│ │
|
||||
│ Token usage: 750 total (500 input + 250 output) │
|
||||
│ Context window: 100% left (750 used / 272K) │
|
||||
│ Limits: data not available yet │
|
||||
╰─────────────────────────────────────────────────────────────────────────────╯
|
||||
+1
-1
@@ -10,7 +10,7 @@ expression: sanitized
|
||||
│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │
|
||||
│ information on rate limits and credits │
|
||||
│ │
|
||||
│ Remote: unix:///tmp/codex-home/app-server-control/app-server- │
|
||||
│ Server: unix:///tmp/codex-home/app-server-control/app-server- │
|
||||
│ control.sock (v0.133.0) │
|
||||
│ │
|
||||
│ Model: gpt-5.1-codex-max (reasoning medium, summaries auto) │
|
||||
|
||||
@@ -1638,41 +1638,51 @@ async fn status_snapshot_uses_default_reasoning_when_config_empty() {
|
||||
.with_ymd_and_hms(2024, 2, 3, 4, 5, 6)
|
||||
.single()
|
||||
.expect("timestamp");
|
||||
let remote_connection = RemoteConnectionStatus {
|
||||
address: "unix:///tmp/codex-home/app-server-control/app-server-control.sock".to_string(),
|
||||
version: "v0.133.0".to_string(),
|
||||
};
|
||||
for (is_local_daemon, snapshot) in [
|
||||
(
|
||||
false,
|
||||
"status_snapshot_uses_default_reasoning_when_config_empty",
|
||||
),
|
||||
(true, "status_snapshot_local_background_server"),
|
||||
] {
|
||||
let remote_connection = RemoteConnectionStatus {
|
||||
address: "unix:///tmp/codex-home/app-server-control/app-server-control.sock"
|
||||
.to_string(),
|
||||
version: "v0.133.0".to_string(),
|
||||
is_local_daemon,
|
||||
};
|
||||
|
||||
let model_slug = get_model_offline_for_tests(config.model.as_deref());
|
||||
let token_info = token_info_for(&model_slug, &config, &usage);
|
||||
let (composite, _) = new_status_output_with_rate_limits_handle(
|
||||
&config,
|
||||
/*requires_openai_auth*/ true,
|
||||
/*model_provider_id*/ None,
|
||||
Some(&remote_connection),
|
||||
account_display.as_ref(),
|
||||
Some(&token_info),
|
||||
&usage,
|
||||
&None,
|
||||
/*thread_name*/ None,
|
||||
/*forked_from*/ None,
|
||||
&[],
|
||||
None,
|
||||
now,
|
||||
&model_slug,
|
||||
/*collaboration_mode*/ None,
|
||||
/*reasoning_effort_override*/ Some(Some(ReasoningEffort::Medium)),
|
||||
"<none>".to_string(),
|
||||
/*refreshing_rate_limits*/ false,
|
||||
);
|
||||
let mut rendered_lines = render_lines(&composite.display_lines(/*width*/ 80));
|
||||
if cfg!(windows) {
|
||||
for line in &mut rendered_lines {
|
||||
*line = line.replace('\\', "/");
|
||||
let model_slug = get_model_offline_for_tests(config.model.as_deref());
|
||||
let token_info = token_info_for(&model_slug, &config, &usage);
|
||||
let (composite, _) = new_status_output_with_rate_limits_handle(
|
||||
&config,
|
||||
/*requires_openai_auth*/ true,
|
||||
/*model_provider_id*/ None,
|
||||
Some(&remote_connection),
|
||||
account_display.as_ref(),
|
||||
Some(&token_info),
|
||||
&usage,
|
||||
&None,
|
||||
/*thread_name*/ None,
|
||||
/*forked_from*/ None,
|
||||
&[],
|
||||
None,
|
||||
now,
|
||||
&model_slug,
|
||||
/*collaboration_mode*/ None,
|
||||
/*reasoning_effort_override*/ Some(Some(ReasoningEffort::Medium)),
|
||||
"<none>".to_string(),
|
||||
/*refreshing_rate_limits*/ false,
|
||||
);
|
||||
let mut rendered_lines = render_lines(&composite.display_lines(/*width*/ 80));
|
||||
if cfg!(windows) {
|
||||
for line in &mut rendered_lines {
|
||||
*line = line.replace('\\', "/");
|
||||
}
|
||||
}
|
||||
let sanitized = sanitize_directory(rendered_lines).join("\n");
|
||||
assert_snapshot!(snapshot, sanitized);
|
||||
}
|
||||
let sanitized = sanitize_directory(rendered_lines).join("\n");
|
||||
assert_snapshot!(sanitized);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
Reference in New Issue
Block a user