feat: Budget skill metadata and surface trimming as a warning (#18298)

Cap the model-visible skills section to a small share of the context
window, with a fallback character budget, and keep only as many implicit
skills as fit within that budget.

Emit a non-fatal warning when enabled skills are omitted, and add a new
app-server warning notification

Record thread-start skill metrics for total enabled skills, kept skills,
and whether truncation happened

---------

Co-authored-by: Matthew Zeng <mzeng@openai.com>
Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
authored and GitHub committed 2026-04-17 18:11:47 -07:00
1 parent a58a0f083d
commit 3f7222ec76
26 files changed
+883 -17

No files matched your search

@@ -421,6 +421,7 @@ fn server_notification_thread_target(
ServerNotification::ThreadRealtimeClosed(notification) => {
Some(notification.thread_id.as_str())
}
ServerNotification::Warning(notification) => notification.thread_id.as_deref(),
ServerNotification::SkillsChanged(_)
| ServerNotification::McpServerStatusUpdated(_)
| ServerNotification::McpServerOauthLoginCompleted(_)
@@ -1049,8 +1050,10 @@ fn app_server_codex_error_info_to_core(
#[cfg(test)]
mod tests {
use super::ServerNotificationThreadTarget;
use super::command_execution_started_event;
use super::server_notification_thread_events;
use super::server_notification_thread_target;
use super::thread_snapshot_events;
use super::turn_snapshot_events;
use codex_app_server_protocol::AgentMessageDeltaNotification;
@@ -1070,6 +1073,7 @@ mod tests {
use codex_app_server_protocol::TurnCompletedNotification;
use codex_app_server_protocol::TurnError;
use codex_app_server_protocol::TurnStatus;
use codex_app_server_protocol::WarningNotification;
use codex_protocol::ThreadId;
use codex_protocol::items::AgentMessageContent;
use codex_protocol::items::AgentMessageItem;
@@ -1664,4 +1668,17 @@ mod tests {
assert_eq!(raw_reasoning.text, "hidden chain");
assert!(matches!(events[3].msg, EventMsg::TurnComplete(_)));
}
#[test]
fn warning_notifications_route_to_threads_when_thread_id_is_present() {
let thread_id = ThreadId::new();
let notification = ServerNotification::Warning(WarningNotification {
thread_id: Some(thread_id.to_string()),
message: "warning".to_string(),
});
let target = server_notification_thread_target(&notification);
assert_eq!(target, ServerNotificationThreadTarget::Thread(thread_id));
}
}