Expose instruction sources (AGENTS.md) via app server (#17506)

Addresses #17498

Problem: The TUI derived /status instruction source paths from the local
client environment, which could show stale <none> output or incorrect
paths when connected to a remote app server.

Solution: Add an app-server v2 instructionSources snapshot to thread
start/resume/fork responses, default it to an empty list when older
servers omit it, and render TUI /status from that server-provided
session data.

Additional context: The app-server field is intentionally named
instructionSources rather than AGENTS.md-specific terminology because
the loaded instruction sources can include global instructions, project
AGENTS.md files, AGENTS.override.md, user-defined instruction files, and
future dynamic sources.
This commit is contained in:
Eric Traut authored and GitHub committed 2026-04-12 15:50:12 -07:00
1 parent 470510174b
commit 46ab9974dc
23 files changed
+302 -69

No files matched your search

+13
View File
@@ -132,6 +132,7 @@ pub(crate) struct ThreadSessionState {
pub(crate) approvals_reviewer: codex_protocol::config_types::ApprovalsReviewer,
pub(crate) sandbox_policy: SandboxPolicy,
pub(crate) cwd: PathBuf,
pub(crate) instruction_source_paths: Vec<PathBuf>,
pub(crate) reasoning_effort: Option<codex_protocol::openai_models::ReasoningEffort>,
pub(crate) history_log_id: u64,
pub(crate) history_entry_count: u64,
@@ -993,6 +994,7 @@ async fn thread_session_state_from_thread_start_response(
response.approvals_reviewer.to_core(),
response.sandbox.to_core(),
response.cwd.clone(),
response.instruction_sources.clone(),
response.reasoning_effort,
config,
)
@@ -1015,6 +1017,7 @@ async fn thread_session_state_from_thread_resume_response(
response.approvals_reviewer.to_core(),
response.sandbox.to_core(),
response.cwd.clone(),
response.instruction_sources.clone(),
response.reasoning_effort,
config,
)
@@ -1037,6 +1040,7 @@ async fn thread_session_state_from_thread_fork_response(
response.approvals_reviewer.to_core(),
response.sandbox.to_core(),
response.cwd.clone(),
response.instruction_sources.clone(),
response.reasoning_effort,
config,
)
@@ -1078,6 +1082,7 @@ async fn thread_session_state_from_thread_response(
approvals_reviewer: codex_protocol::config_types::ApprovalsReviewer,
sandbox_policy: SandboxPolicy,
cwd: PathBuf,
instruction_source_paths: Vec<PathBuf>,
reasoning_effort: Option<codex_protocol::openai_models::ReasoningEffort>,
config: &Config,
) -> Result<ThreadSessionState, String> {
@@ -1102,6 +1107,7 @@ async fn thread_session_state_from_thread_response(
approvals_reviewer,
sandbox_policy,
cwd,
instruction_source_paths,
reasoning_effort,
history_log_id,
history_entry_count,
@@ -1326,6 +1332,7 @@ mod tests {
model_provider: "openai".to_string(),
service_tier: None,
cwd: PathBuf::from("/tmp/project"),
instruction_sources: vec![PathBuf::from("/tmp/project/AGENTS.md")],
approval_policy: codex_protocol::protocol::AskForApproval::Never.into(),
approvals_reviewer: codex_app_server_protocol::ApprovalsReviewer::User,
sandbox: codex_protocol::protocol::SandboxPolicy::new_read_only_policy().into(),
@@ -1336,6 +1343,10 @@ mod tests {
.await
.expect("resume response should map");
assert_eq!(started.session.forked_from_id, Some(forked_from_id));
assert_eq!(
started.session.instruction_source_paths,
response.instruction_sources
);
assert_eq!(started.turns.len(), 1);
assert_eq!(started.turns[0], response.thread.turns[0]);
}
@@ -1365,6 +1376,7 @@ mod tests {
codex_protocol::config_types::ApprovalsReviewer::User,
SandboxPolicy::new_read_only_policy(),
PathBuf::from("/tmp/project"),
Vec::new(),
/*reasoning_effort*/ None,
&config,
)
@@ -1394,6 +1406,7 @@ mod tests {
codex_protocol::config_types::ApprovalsReviewer::User,
SandboxPolicy::new_read_only_policy(),
PathBuf::from("/tmp/project"),
Vec::new(),
/*reasoning_effort*/ None,
&config,
)