Skip to content

core: refresh environment context before sampling#29073

Merged
sayan-oai merged 3 commits into
mainfrom
codex/step-context-environment-updates
Jun 22, 2026
Merged

core: refresh environment context before sampling#29073
sayan-oai merged 3 commits into
mainfrom
codex/step-context-environment-updates

Conversation

@sayan-oai

@sayan-oai sayan-oai commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Why

Nonblocking environment snapshots allow a turn to reach the model while a remote environment is still starting. The initial context can describe that environment as still loading, but nothing currently refreshes the model-visible environment context when startup finishes during the same turn.

This adds the first request-scoped reconciliation slice on top of #28683. It is gated by DeferredExecutor and intentionally updates only model-visible environment context; tools and other environment-derived state will migrate separately.

What

  • Add a minimal StepContext containing the environment snapshot captured before each sampling request.
  • Render attached environments with their resolved shell and starting environments with still loading.
  • Track the latest environment state recorded in model history and append a bounded update only when it changes.
  • Seed that baseline from full initial context so ready-at-start environments are not duplicated.
  • Clear the in-memory baseline when history is rewritten so replacement history can be refreshed safely.

Testing

  • just test -p codex-core deferred_executor
  • just test -p codex-core environment_context_baseline_deduplicates_until_history_is_replaced

The integration coverage verifies that a pending environment reaches the first request, the ready state reaches the next request, later requests do not duplicate it, and ready-at-start environments remain single-injected.

Live verification
  • Connected to a real remote executor with startup deliberately delayed and forced three sampling requests in one turn.
  • Inspected the raw model inputs: request 1 showed the remote environment as still loading, request 2 appended its ready shell and cwd, and request 3 contained no duplicate ready update.
  • With the feature disabled, startup waited for the delayed executor and the first request contained only the ready environment.
  • With a synchronously ready environment and the feature enabled, the first request contained one environment context with no duplicate.
  • Executed pwd and read a marker file through the remote process runner; the command exited successfully and returned the remote cwd and marker contents.

@sayan-oai
sayan-oai requested a review from a team as a code owner June 19, 2026 09:49

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ed79efe815

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}

fn environment_only(environments: Vec<EnvironmentContextEnvironment>) -> Option<Self> {
(!environments.is_empty()).then(|| {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle failed deferred environments

When a DeferredExecutor environment is still starting on one sampling request and then its resolution completes with an error before the next request, ThreadEnvironments::snapshot drops it from both turn_environments and starting; because an empty snapshot returns None here, record_step_environment_context_if_changed returns without appending a replacement or clearing the baseline. The prompt history therefore keeps the previous <shell>still loading</shell> environment context for later requests, misleading the model about an environment that is no longer available.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we havent really modeled failed state fully. can add if it seems logical to do now, or can follow up.

.await,
);
}
let initial_environment_context = if should_inject_full_context

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the environment baseline in sync with emitted diffs

When a steady-state turn changes the environment selection or cwd, build_settings_update_items already records an environment-context diff before sampling, but this baseline is only seeded on the full-context path. The next pre-sampling refresh in run_turn therefore compares against the previous baseline and appends another environment-only context for the same state, adding redundant model-visible messages and cache misses whenever environment context changes after the first turn.

AGENTS.md reference: AGENTS.md:L92-L98

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we get this for free once the proposed/upcoming StepContextItem lands and is the sole owner of environment context. thoughts?

Comment on lines +249 to +253
let step_context = StepContext {
environments: sess.services.turn_environments.snapshot().await,
};
sess.record_step_environment_context_if_changed(
turn_context.as_ref(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Don't advertise environments the turn cannot use

When an environment finishes starting during a turn, this live snapshot can append it to <environment_context>, but the tool router and handlers for that same turn are still built from the immutable turn_context.environments captured at turn creation (for example, resolve_tool_environment only searches that original list). In a turn that started before the remote environment was ready, the next model request can therefore see a ready environment ID that shell/request-permission tools either do not expose or reject as unknown, so the refreshed context can steer the model into unusable tool calls until the next turn rebuilds TurnContext.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

follow up

@sayan-oai sayan-oai changed the title [codex] refresh environment context before sampling core: refresh environment context before sampling Jun 19, 2026
Comment thread codex-rs/core/src/context/environment_context.rs
@sayan-oai
sayan-oai merged commit 22886f2 into main Jun 22, 2026
31 checks passed
@sayan-oai
sayan-oai deleted the codex/step-context-environment-updates branch June 22, 2026 15:47
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 22, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants