Compare commits

..

64 Commits

Author SHA1 Message Date
pash
21f259ced0 cleanup 2026-02-01 21:46:20 -08:00
pash
24f027b4ab minor comment change 2026-02-01 21:46:20 -08:00
pash
53056a4f8d context in headers 2026-02-01 21:46:20 -08:00
Dylan Hurd
d7bcca0de7 fix(core) Deduplicate prefix_rules before appending (#10309)
## Summary
We ideally shouldn't make it to this point in the first place, but if we
do try to append a rule that already exists, we shouldn't append the
same rule twice.

## Testing
- [x] Added unit test for this case
2026-02-01 21:45:29 -08:00
pakrym-oai
d989ad2ade Do not append items on override turn context (#10354) 2026-02-01 21:45:29 -08:00
Dylan Hurd
32ad28b660 fix(rules) Limit rules listed in conversation (#10351)
## Summary
We should probably warn users that they have a million rules, and help
clean them up. But for now, we should handle this unbounded case.

Limit rules listed in conversations, with shortest / broadest rules
first.

## Testing
- [x] Updated unit tests
2026-02-01 21:45:29 -08:00
Gav Verma
5a32ef8cd5 fix: System skills marker includes nested folders recursively (#10350)
Updated system skills bundled with Codex were not correctly replacing
the user's skills in their .system folder.

- Fix `.codex-system-skills.marker` not updating by hashing embedded
system skills recursively (nested dirs + file contents), so updates
trigger a reinstall.
- Added a build Cargo hook to rerun if there are changes in
`src/skills/assets/samples/*`, ensuring embedded skill updates rebuild
correctly under caching.
- Add a small unit test to ensure nested entries are included in the
fingerprint.
2026-02-01 21:45:29 -08:00
Charley Cunningham
d17ac501eb Bump thread updated_at on unarchive to refresh sidebar ordering (#10280)
## Summary
- Touch restored rollout files on `thread/unarchive` so `updatedAt`
reflects the unarchive time.
- Add a regression test to ensure unarchiving bumps `updated_at` from an
old mtime.

## Notes
This fixes the UX issue where unarchived old threads don’t reappear near
the top of recent threads.
2026-02-01 21:45:29 -08:00
Charley Cunningham
50cae2152c Improve plan mode interaction rules (#10329)
## Summary
- Replace the “Hard interaction rule” with a clearer “Response
constraints” section that enumerates the allowed exceptions for Plan
Mode replies.
- Remove the stray Phase 1 exception line about simple questions.
- Update plan content requirements to ask for a brief summary section
and generalize API/type wording.
2026-02-01 21:45:29 -08:00
Dylan Hurd
4be0d3f71a fix(config) config schema newline (#10323)
## Summary
Looks like we may have introduced a formatting issue in recent PRs.

## Testing
- [x] ran `just write-config-schema`
2026-02-01 21:45:29 -08:00
Gav Verma
33f8ea4ec2 Sync system skills from public repo for openai yaml changes (#10322)
Follow-up to https://github.com/openai/codex/pull/10320

Syncing additional changes from
https://github.com/openai/skills/tree/main/skills/.system
2026-02-01 21:45:29 -08:00
Gav Verma
560895eab7 Sync system skills from public repo (#10320)
Syncs the system skills included in Codex with the updates in
https://github.com/openai/skills/tree/main/skills/.system
2026-02-01 21:45:29 -08:00
Dylan Hurd
8a231bea77 chore(features) Personality => Stable (#10310)
## Summary
Bump `/personality` to stable

## Testing
 - [x] unit tests pass
2026-02-01 21:45:29 -08:00
Dylan Hurd
a894ef8eb0 chore(config) Rename config setting to personality (#10314)
## Summary
Let's make the setting name consistent with the SlashCommand!

## Testing
- [x] Updated tests
2026-02-01 21:45:29 -08:00
Anton Panasenko
8bdbbfa8d0 Add websocket telemetry metrics and labels (#10316)
Summary
- expose websocket telemetry hooks through the responses client so
request durations and event processing can be reported
- record websocket request/event metrics and emit runtime telemetry
events that the history UI now surfaces
- improve tests to cover websocket telemetry reporting and guard runtime
summary updates


<img width="824" height="79" alt="Screenshot 2026-01-31 at 5 28 12 PM"
src="https://github.com/user-attachments/assets/ea9a7965-d8b4-4e3c-a984-ef4fdc44c81d"
/>
2026-02-01 21:45:29 -08:00
xl-openai
b7a2e470bb Make skills prompt explicit about relative-path lookup (#10282)
Fix cases where the model tries to locate skill scripts from the cwd and
fails.
2026-02-01 21:45:29 -08:00
Gav Verma
5777eccddc feat: Support loading skills from .agents/skills (#10317)
This PR adds support for loading
[skills](https://developers.openai.com/codex/skills) from
`.agents/skills/`.
- Issue: https://github.com/agentskills/agentskills/issues/15
- Motivation: When skills live on the filesystem, sharing them across
agents is awkward and often ends up requiring symlinks/duplication. A
single location under `.agents/` makes it easier to share skills.
- Loading from `.codex/skills/` will remain but will be deprecated soon.
The change only applies to the [REPO
scope](https://developers.openai.com/codex/skills#where-to-save-skills).
- Documentation will be updated before this change is live.

Testing with skills in two locations of this repo:
<img width="960" height="152" alt="image"
src="https://github.com/user-attachments/assets/28975ff9-7363-46dd-ad40-f4c7bfdb8234"
/>

When starting Codex with CWD in `$repo_root` (should only pick up at
root):
<img width="513" height="143" alt="image"
src="https://github.com/user-attachments/assets/389e1ea7-020c-481e-bda0-ce58562db59f"
/>

When starting Codex with CWD in `$repo_root/codex-rs` (should pick up at
cwd and crawl up to root):
<img width="552" height="177" alt="image"
src="https://github.com/user-attachments/assets/a5beb8de-11b4-45ed-8660-80707c77006a"
/>
2026-02-01 21:45:29 -08:00
alexsong-oai
b83ab19bc8 feat: fire tracking events for skill invocation (#10120) 2026-02-01 21:45:29 -08:00
Ahmed Ibrahim
71613fdfdd enable plan mode (#10313)
# External (non-OpenAI) Pull Request Requirements

Before opening this Pull Request, please read the dedicated
"Contributing" markdown file or your PR may be closed:
https://github.com/openai/codex/blob/main/docs/contributing.md

If your PR conforms to our contribution guidelines, replace this text
with a detailed and high quality description of your changes.

Include a link to a bug report or enhancement request.
2026-02-01 21:45:29 -08:00
Dylan Hurd
bbc8af7a15 feat(core,tui,app-server) personality migration (#10307)
## Summary
Keep existing users on Pragmatic, to preserve behavior while new users
default to Friendly

## Testing
- [x] Tested locally
- [x] add integration tests
2026-02-01 21:45:29 -08:00
Dylan Hurd
c15a13a3ea chore(core) Default to friendly personality (#10305)
## Summary
Update default personality to friendly

## Testing
- [x] Unit tests pass
2026-02-01 21:45:28 -08:00
Ahmed Ibrahim
5a40f3bfd3 plan mode prompt (#10308)
# External (non-OpenAI) Pull Request Requirements

Before opening this Pull Request, please read the dedicated
"Contributing" markdown file or your PR may be closed:
https://github.com/openai/codex/blob/main/docs/contributing.md

If your PR conforms to our contribution guidelines, replace this text
with a detailed and high quality description of your changes.

Include a link to a bug report or enhancement request.
2026-02-01 21:45:28 -08:00
Dylan Hurd
33946d2612 chore(app-server) add personality update test (#10306)
## Summary
Add some additional validation to ensure app-server handles Personality
changes

## Testing
- [x] These are tests
2026-02-01 21:45:28 -08:00
Fouad Matin
e777444283 Fix npm README image link (#10303)
### Motivation
- The image referenced in the package README was 404ing on the npm
package page because it used a relative file path that doesn't resolve
on npm, so the splash image needs a GitHub-hosted URL to render
correctly.

### Description
- Update `README.md` to replace the relative image path
`./.github/codex-cli-splash.png` with the GitHub-hosted URL
`https://github.com/openai/codex/blob/main/.github/codex-cli-splash.png`.

### Testing
- No automated tests were run because this is a docs-only change and
does not affect code or test behavior.

------
[Codex
Task](https://chatgpt.com/codex/tasks/task_i_697e58dbce34832d87c7847779e8f4a5)
2026-02-01 21:45:28 -08:00
Dylan Hurd
666f82588a chore(features) remove Experimental tag from UTF8 (#10296)
## Summary
This has been default on for some time, it should now be the default.

## Testing
- [x] Existing tests pass
2026-02-01 21:45:28 -08:00
douglaz
73680a7b4b fix(nix): update flake for newer Rust toolchain requirements (#10302)
## Summary

- Add rust-overlay input to provide newer Rust versions (rama crates
require rustc 1.91.0+)
- Add devShells output with complete development environment
- Add missing git dependency hashes to codex-rs/default.nix

## Changes

**flake.nix:**
- Added `rust-overlay` input to get newer Rust toolchains
- Updated `packages` output to use `rust-bin.stable.latest.minimal` for
builds
- Added `devShells` output with:
  - Rust with `rust-src` and `rust-analyzer` extensions for IDE support
- Required build dependencies: `pkg-config`, `openssl`, `cmake`,
`libclang`
  - Environment variables: `PKG_CONFIG_PATH`, `LIBCLANG_PATH`

**codex-rs/default.nix:**
- Added missing `outputHashes` for git dependencies:
  - `nucleo-0.5.0`, `nucleo-matcher-0.3.1`
  - `runfiles-0.1.0`
  - `tokio-tungstenite-0.28.0`, `tungstenite-0.28.0`

## Test Plan

- [x] `nix develop` enters shell successfully
- [x] `nix develop -c rustc --version` shows 1.93.0
- [x] `nix develop -c cargo build` completes successfully
2026-02-01 21:45:28 -08:00
willwang-openai
4b9d4de64b display promo message in usage error (#10285)
If a promo message is attached to a rate limit response, then display it
in the error message.
2026-02-01 21:45:28 -08:00
Anton Panasenko
86f96cfa2f feat: show runtime metrics in console (#10278)
Summary of changes:

- Adds a new feature flag: runtime_metrics
  - Declared in core/src/features.rs
  - Added to core/config.schema.json
  - Wired into OTEL init in core/src/otel_init.rs

- Enables on-demand runtime metric snapshots in OTEL
  - Adds runtime_metrics: bool to otel/src/config.rs
  - Enables experimental custom reader features in otel/Cargo.toml
  - Adds snapshot/reset/summary APIs in:
    - otel/src/lib.rs
    - otel/src/metrics/client.rs
    - otel/src/metrics/config.rs
    - otel/src/metrics/error.rs

- Defines metric names and a runtime summary builder
  - New files:
    - otel/src/metrics/names.rs
    - otel/src/metrics/runtime_metrics.rs
  - Summarizes totals for:
    - Tool calls
    - API requests
    - SSE/streaming events

- Instruments metrics collection in OTEL manager
  - otel/src/traces/otel_manager.rs now records:
    - API call counts + durations
    - SSE event counts + durations (success/failure)
    - Tool call metrics now use shared constants

- Surfaces runtime metrics in the TUI
  - Resets runtime metrics at turn start in tui/src/chatwidget.rs
- Displays metrics in the final separator line in
tui/src/history_cell.rs

- Adds tests
  - New OTEL tests:
    - otel/tests/suite/snapshot.rs
    - otel/tests/suite/runtime_summary.rs
  - New TUI test:
- final_message_separator_includes_runtime_metrics in
tui/src/history_cell.rs

Scope:
- 19 files changed
- ~652 insertions, 38 deletions


<img width="922" height="169" alt="Screenshot 2026-01-30 at 4 11 34 PM"
src="https://github.com/user-attachments/assets/1efd754d-a16d-4564-83a5-f4442fd2f998"
/>
2026-02-01 21:45:28 -08:00
Dylan Hurd
66d4b8a950 feat(core) Smart approvals on (#10286)
## Summary
Turn on Smart Approvals by default

## Testing
 - [x] Updated unit tests
2026-02-01 21:45:28 -08:00
Ruyut
175feb3048 Fix minor typos in comments and documentation (#10287)
## Summary

I have read the contribution guidelines.  
All changes in this PR are limited to text corrections and do not modify
any business logic, runtime behavior, or user-facing functionality.

## Details

This PR fixes several minor typos, including:

- `create` -> `crate`
- `analagous` -> `analogous`
- `apply-patch` -> `apply_patch`
- `codecs` -> `codex`
- ` '/" ` -> ` '/' `
- `Respesent` -> `Represent`
2026-02-01 21:45:28 -08:00
gt-oai
4e508c4453 Turn on cloud requirements for business too (#10283)
Need to check "enterprise" and "business"
2026-02-01 21:45:28 -08:00
sayan-oai
c36be90c87 add missing fields to WebSearchAction and update app-server types (#10276)
- add `WebSearchAction` to app-server v2 types
- add `queries` to `WebSearchAction::Search` type

Updated tests.
2026-02-01 21:45:28 -08:00
gt-oai
e44766d3ac Add enforce_residency to requirements (#10263)
Add `enforce_residency` to requirements.toml and thread it through to a
header on `default_client`.
2026-02-01 21:45:28 -08:00
gt-oai
2fc5d026b8 Wire up cloud reqs in exec, app-server (#10241)
We're fetching cloud requirements in TUI in
https://github.com/openai/codex/pull/10167.

This adds the same fetching in exec and app-server binaries also.
2026-02-01 21:45:28 -08:00
Michael Bolin
d9543bf5f4 chore: implement Mul for TruncationPolicy (#10272)
Codex thought this was a good idea while working on
https://github.com/openai/codex/pull/10192.
2026-02-01 21:45:28 -08:00
Eric Traut
b3a4bae560 Validate CODEX_HOME before resolving (#10249)
Summary
- require `CODEX_HOME` to point to an existing directory before
canonicalizing and surface clear errors otherwise
- share the same helper logic in both `core` and `rmcp-client` and add
unit tests that cover missing, non-directory, valid, and default paths

This addresses #9222
2026-02-01 21:45:28 -08:00
Yuvraj Angad Singh
30db43f067 fix: update file search directory when session CWD changes (#9279)
## Summary

Fixes #9041

- Adds update_search_dir() method to FileSearchManager to allow updating
the search directory after initialization
- Calls this method when the session CWD changes: new session, resume,
or fork

## Problem

The FileSearchManager was created once with the initial search_dir and
never updated. When a user:

1. Starts Codex in a non-git directory (e.g., /tmp/random)
2. Resumes or forks a session from a different workspace
3. The @filename lookup still searched the original directory

This caused no matches to be returned even when files existed in the
current workspace.

## Solution

Update FileSearchManager.search_dir whenever the session working
directory changes:
- AppEvent::NewSession: Use current config CWD
- SessionSelection::Resume: Use resumed session CWD
- SessionSelection::Fork: Use forked session CWD

## Test plan

- [ ] Start Codex in /tmp/test-dir (non-git)
- [ ] Resume a session from a project with actual files
- [ ] Verify @filename returns matches from the resumed session
directory

---------

Co-authored-by: Eric Traut <etraut@openai.com>
2026-02-01 21:45:28 -08:00
sayan-oai
6c21aec303 fix: dont auto-enable web_search for azure (#10266)
seeing issues with azure after default-enabling web search: #10071,
#10257.

need to work with azure to fix api-side, for now turning off
default-enable of web_search for azure.

diff is big because i moved logic to reuse
2026-02-01 21:45:28 -08:00
Jeremy Rose
209335b780 file-search: multi-root walk (#10240)
Instead of a separate walker for each root in a multi-root walk, use a
single walker.
2026-02-01 21:45:28 -08:00
pakrym-oai
c563d2d9d1 Update announcement_tip.toml (#10267)
Extend the test for dev version
2026-02-01 21:45:27 -08:00
pakrym-oai
b5ff43f45f Hide /approvals from the slash-command list (#10265)
`/permissions` is the replacement. `/approvals` still available when
typing.
2026-02-01 21:45:27 -08:00
pakrym-oai
2b72cde474 Fix main (#10262) 2026-02-01 21:45:27 -08:00
Skylar Graika
df5207dcb3 core: prevent shell_snapshot from inheriting stdin (#9735)
Fixes #9559.

When `shell_snapshot` runs, it may execute user startup files (e.g.
`.bashrc`). If those files read from stdin (or if stdin is an
interactive TTY under job control), the snapshot subprocess can block or
receive `SIGTTIN` (as reported over SSH).

This change explicitly sets `stdin` to `Stdio::null()` for the snapshot
subprocess, so it can't read from the terminal.

Regression test added that would hang/timeout without this change.
Tests: `ulimit -n 4096 && cargo test -p codex-core`.

cc @dongdongbh @etraut-openai

---------

Co-authored-by: Skylar Graika <sgraika127@gmail.com>
2026-02-01 21:45:27 -08:00
pakrym-oai
60b73acf3c Update copy (#10256)
<img width="839" height="62" alt="image"
src="https://github.com/user-attachments/assets/ca987cdb-9e8c-403e-8856-a9b37baa7673"
/>
2026-02-01 21:45:27 -08:00
daniel-oai
d41cc94e04 Skip loading codex home as project layer (#10207)
Summary:
- Fixes issue #9932: https://github.com/openai/codex/issues/9932
- Prevents `$CODEX_HOME` (typically `~/.codex`) from being discovered as
a project `.codex` layer by skipping it during project layer traversal.
We compare both normalized absolute paths and best-effort canonicalized
paths to handle symlinks.
- Adds regression tests for home-directory invocation and for the case
where `CODEX_HOME` points to a project `.codex` directory (e.g.,
worktrees/editor integrations).

Testing:
- `cargo build -p codex-cli --bin codex`
- `cargo build -p codex-rmcp-client --bin test_stdio_server`
- `cargo test -p codex-core`
- `cargo test --all-features`
- Manual: ran `target/debug/codex` from `~` and confirmed the
disabled-folder warning and trust prompt no longer appear.
2026-02-01 21:45:27 -08:00
Charley Cunningham
a6ca72561c Make plan highlight use popup grey background (#10253)
## Summary
- align proposed plan background with popup surface color by reusing
`user_message_bg`
- remove the custom blue-tinted plan background

<img width="1572" height="1568" alt="image"
src="https://github.com/user-attachments/assets/63a5341e-4342-4c07-b6b0-c4350c3b2639"
/>
2026-02-01 21:45:27 -08:00
Ahmed Ibrahim
64cc979687 plan prompt (#10255)
# External (non-OpenAI) Pull Request Requirements

Before opening this Pull Request, please read the dedicated
"Contributing" markdown file or your PR may be closed:
https://github.com/openai/codex/blob/main/docs/contributing.md

If your PR conforms to our contribution guidelines, replace this text
with a detailed and high quality description of your changes.

Include a link to a bug report or enhancement request.
2026-02-01 21:45:27 -08:00
Charley Cunningham
e0911d0ed3 Fix deploy (#10251)
Fix
https://github.com/openai/codex/actions/runs/21527697445/job/62035898666
2026-02-01 21:45:27 -08:00
Ahmed Ibrahim
e27ea34dda Plan mode prompt (#10238)
# External (non-OpenAI) Pull Request Requirements

Before opening this Pull Request, please read the dedicated
"Contributing" markdown file or your PR may be closed:
https://github.com/openai/codex/blob/main/docs/contributing.md

If your PR conforms to our contribution guidelines, replace this text
with a detailed and high quality description of your changes.

Include a link to a bug report or enhancement request.
2026-02-01 21:45:27 -08:00
pash
121f081d43 fix test after rebase 2026-01-30 11:29:42 -08:00
pash
5acb68d6c7 moving to headers 2026-01-30 11:24:19 -08:00
pash
7b26f3539e moving to headers 2026-01-30 11:24:19 -08:00
pash
024f49e63e moving to headers 2026-01-30 11:24:19 -08:00
pash
9eff9b835e metadata timeout 2026-01-30 11:24:19 -08:00
pash
37a287a3f0 clippy 2026-01-30 11:24:19 -08:00
pash
4190aa3a04 fix responses_headers test 2026-01-30 11:24:19 -08:00
pash
b267af326d moving to headers 2026-01-30 11:24:19 -08:00
pash
c479bff448 fix workspace context test path on windows 2026-01-30 11:24:19 -08:00
pash
231103ba3b remove workspace hint from session context 2026-01-30 11:24:19 -08:00
pash
061b4d900d skip remote lookup outside git repos 2026-01-30 11:24:19 -08:00
pash
edc4f8a2d0 address clippy lints for workspace context 2026-01-30 11:24:18 -08:00
pash
ffa0486a41 inline workspace xml format args 2026-01-30 11:24:18 -08:00
pash
62ea1d6940 render workspace git context as xml 2026-01-30 11:24:18 -08:00
pash
bdd376dfc9 add workspace git context to session prefix 2026-01-30 11:24:18 -08:00
13 changed files with 350 additions and 81 deletions

View File

@@ -1,3 +1,4 @@
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::OnceLock;
@@ -5,6 +6,7 @@ use crate::api_bridge::CoreAuthProvider;
use crate::api_bridge::auth_provider_from_auth;
use crate::api_bridge::map_api_error;
use crate::auth::UnauthorizedRecovery;
use crate::turn_metadata::build_turn_metadata_header;
use codex_api::AggregateStreamExt;
use codex_api::ChatClient as ApiChatClient;
use codex_api::CompactClient as ApiCompactClient;
@@ -72,6 +74,7 @@ use crate::transport_manager::TransportManager;
pub const WEB_SEARCH_ELIGIBLE_HEADER: &str = "x-oai-web-search-eligible";
pub const X_CODEX_TURN_STATE_HEADER: &str = "x-codex-turn-state";
pub const X_CODEX_TURN_METADATA_HEADER: &str = "x-codex-turn-metadata";
#[derive(Debug)]
struct ModelClientState {
@@ -108,6 +111,10 @@ pub struct ModelClientSession {
/// keep sending it unchanged between turn requests (e.g., for retries, incremental
/// appends, or continuation requests), and must not send it between different turns.
turn_state: Arc<OnceLock<String>>,
/// Turn-scoped metadata attached to every request in the turn.
turn_metadata_header: Option<HeaderValue>,
/// Working directory used to lazily compute turn metadata at send time.
turn_metadata_cwd: Option<PathBuf>,
}
#[allow(clippy::too_many_arguments)]
@@ -140,13 +147,21 @@ impl ModelClient {
}
}
pub fn new_session(&self) -> ModelClientSession {
pub fn new_session(
&self,
turn_metadata_header: Option<String>,
turn_metadata_cwd: Option<PathBuf>,
) -> ModelClientSession {
let turn_metadata_header =
turn_metadata_header.and_then(|value| HeaderValue::from_str(&value).ok());
ModelClientSession {
state: Arc::clone(&self.state),
connection: None,
websocket_last_items: Vec::new(),
transport_manager: self.state.transport_manager.clone(),
turn_state: Arc::new(OnceLock::new()),
turn_metadata_header,
turn_metadata_cwd,
}
}
}
@@ -257,6 +272,21 @@ impl ModelClient {
}
impl ModelClientSession {
async fn ensure_turn_metadata_header(&mut self) {
if self.turn_metadata_header.is_some() {
return;
}
let Some(cwd) = self.turn_metadata_cwd.as_deref() else {
return;
};
let Some(value) = build_turn_metadata_header(cwd).await else {
return;
};
if let Ok(header_value) = HeaderValue::from_str(value.as_str()) {
self.turn_metadata_header = Some(header_value);
}
}
/// Streams a single model turn using either the Responses or Chat
/// Completions wire API, depending on the configured provider.
///
@@ -264,6 +294,9 @@ impl ModelClientSession {
/// based on the `show_raw_agent_reasoning` flag in the config.
pub async fn stream(&mut self, prompt: &Prompt) -> Result<ResponseStream> {
let wire_api = self.state.provider.wire_api;
if matches!(wire_api, WireApi::Responses) {
self.ensure_turn_metadata_header().await;
}
match wire_api {
WireApi::Responses => {
let websocket_enabled = self.responses_websocket_enabled()
@@ -380,7 +413,11 @@ impl ModelClientSession {
store_override: None,
conversation_id: Some(conversation_id),
session_source: Some(self.state.session_source.clone()),
extra_headers: build_responses_headers(&self.state.config, Some(&self.turn_state)),
extra_headers: build_responses_headers(
&self.state.config,
Some(&self.turn_state),
self.turn_metadata_header.as_ref(),
),
compression,
turn_state: Some(Arc::clone(&self.turn_state)),
}
@@ -713,6 +750,7 @@ fn experimental_feature_headers(config: &Config) -> ApiHeaderMap {
fn build_responses_headers(
config: &Config,
turn_state: Option<&Arc<OnceLock<String>>>,
turn_metadata_header: Option<&HeaderValue>,
) -> ApiHeaderMap {
let mut headers = experimental_feature_headers(config);
headers.insert(
@@ -731,6 +769,9 @@ fn build_responses_headers(
{
headers.insert(X_CODEX_TURN_STATE_HEADER, header_value);
}
if let Some(header_value) = turn_metadata_header {
headers.insert(X_CODEX_TURN_METADATA_HEADER, header_value.clone());
}
headers
}

View File

@@ -119,6 +119,7 @@ use crate::error::Result as CodexResult;
use crate::exec::StreamOutput;
use crate::exec_policy::ExecPolicyUpdateError;
use crate::feedback_tags;
use crate::git_info::get_git_repo_root;
use crate::instructions::UserInstructions;
use crate::mcp::CODEX_APPS_MCP_SERVER_NAME;
use crate::mcp::auth::compute_auth_statuses;
@@ -503,8 +504,9 @@ pub(crate) struct TurnContext {
pub(crate) tool_call_gate: Arc<ReadinessFlag>,
pub(crate) truncation_policy: TruncationPolicy,
pub(crate) dynamic_tools: Vec<DynamicToolSpec>,
/// Per-turn metadata serialized as a header value for outbound model requests.
pub(crate) turn_metadata_header: Option<String>,
}
impl TurnContext {
pub(crate) fn resolve_path(&self, path: Option<String>) -> PathBuf {
path.as_ref()
@@ -705,6 +707,7 @@ impl Session {
tool_call_gate: Arc::new(ReadinessFlag::new()),
truncation_policy: model_info.truncation_policy.into(),
dynamic_tools: session_configuration.dynamic_tools.clone(),
turn_metadata_header: None,
}
}
@@ -3176,6 +3179,7 @@ async fn spawn_review_thread(
tool_call_gate: Arc::new(ReadinessFlag::new()),
dynamic_tools: parent_turn_context.dynamic_tools.clone(),
truncation_policy: model_info.truncation_policy.into(),
turn_metadata_header: None,
};
// Seed the child task with the review prompt as the initial user message.
@@ -3379,7 +3383,10 @@ pub(crate) async fn run_turn(
// many turns, from the perspective of the user, it is a single turn.
let turn_diff_tracker = Arc::new(tokio::sync::Mutex::new(TurnDiffTracker::new()));
let mut client_session = turn_context.client.new_session();
let mut client_session = turn_context.client.new_session(
turn_context.turn_metadata_header.clone(),
Some(turn_context.cwd.clone()),
);
loop {
// Note that pending_input would be something like a message the user
@@ -4442,8 +4449,6 @@ pub(super) fn get_last_assistant_message_from_turn(responses: &[ResponseItem]) -
#[cfg(test)]
pub(crate) use tests::make_session_and_context;
use crate::git_info::get_git_repo_root;
#[cfg(test)]
pub(crate) use tests::make_session_and_context_with_rx;

View File

@@ -335,7 +335,10 @@ async fn drain_to_completed(
turn_context: &TurnContext,
prompt: &Prompt,
) -> CodexResult<()> {
let mut client_session = turn_context.client.new_session();
let mut client_session = turn_context.client.new_session(
turn_context.turn_metadata_header.clone(),
Some(turn_context.cwd.clone()),
);
let mut stream = client_session.stream(prompt).await?;
loop {
let maybe_event = stream.next().await;

View File

@@ -28,6 +28,7 @@ impl EnvironmentContext {
cwd,
// should compare all fields except shell
shell: _,
..
} = other;
self.cwd == *cwd
@@ -66,6 +67,7 @@ impl EnvironmentContext {
let shell_name = self.shell.name();
lines.push(format!(" <shell>{shell_name}</shell>"));
lines.push(ENVIRONMENT_CONTEXT_CLOSE_TAG.to_string());
lines.join("\n")
}

View File

@@ -1,3 +1,4 @@
use std::collections::BTreeMap;
use std::collections::HashSet;
use std::path::Path;
use std::path::PathBuf;
@@ -109,6 +110,92 @@ pub async fn collect_git_info(cwd: &Path) -> Option<GitInfo> {
Some(git_info)
}
/// Collect fetch remotes in a multi-root-friendly format: {"origin": "https://..."}.
pub async fn get_git_remote_urls(cwd: &Path) -> Option<BTreeMap<String, String>> {
let is_git_repo = run_git_command_with_timeout(&["rev-parse", "--git-dir"], cwd)
.await?
.status
.success();
if !is_git_repo {
return None;
}
get_git_remote_urls_assume_git_repo(cwd).await
}
/// Collect fetch remotes without checking whether `cwd` is in a git repo.
pub async fn get_git_remote_urls_assume_git_repo(cwd: &Path) -> Option<BTreeMap<String, String>> {
get_git_remote_urls_assume_git_repo_with_timeout(cwd, GIT_COMMAND_TIMEOUT).await
}
/// Collect fetch remotes without checking whether `cwd` is in a git repo,
/// using the provided timeout.
pub async fn get_git_remote_urls_assume_git_repo_with_timeout(
cwd: &Path,
timeout_dur: TokioDuration,
) -> Option<BTreeMap<String, String>> {
let output = run_git_command_with_timeout_override(&["remote", "-v"], cwd, timeout_dur).await?;
if !output.status.success() {
return None;
}
let stdout = String::from_utf8(output.stdout).ok()?;
parse_git_remote_urls(stdout.as_str())
}
/// Return the current HEAD commit hash without checking whether `cwd` is in a git repo.
pub async fn get_head_commit_hash(cwd: &Path) -> Option<String> {
get_head_commit_hash_with_timeout(cwd, GIT_COMMAND_TIMEOUT).await
}
/// Return the current HEAD commit hash without checking whether `cwd` is in a
/// git repo, using the provided timeout.
pub async fn get_head_commit_hash_with_timeout(
cwd: &Path,
timeout_dur: TokioDuration,
) -> Option<String> {
let output =
run_git_command_with_timeout_override(&["rev-parse", "HEAD"], cwd, timeout_dur).await?;
if !output.status.success() {
return None;
}
let stdout = String::from_utf8(output.stdout).ok()?;
let hash = stdout.trim();
if hash.is_empty() {
None
} else {
Some(hash.to_string())
}
}
fn parse_git_remote_urls(stdout: &str) -> Option<BTreeMap<String, String>> {
let mut remotes = BTreeMap::new();
for line in stdout.lines() {
let Some(fetch_line) = line.strip_suffix(" (fetch)") else {
continue;
};
let Some((name, url_part)) = fetch_line
.split_once('\t')
.or_else(|| fetch_line.split_once(' '))
else {
continue;
};
let url = url_part.trim_start();
if !url.is_empty() {
remotes.insert(name.to_string(), url.to_string());
}
}
if remotes.is_empty() {
None
} else {
Some(remotes)
}
}
/// A minimal commit summary entry used for pickers (subject + timestamp + sha).
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CommitLogEntry {
@@ -185,11 +272,19 @@ pub async fn git_diff_to_remote(cwd: &Path) -> Option<GitDiffToRemote> {
/// Run a git command with a timeout to prevent blocking on large repositories
async fn run_git_command_with_timeout(args: &[&str], cwd: &Path) -> Option<std::process::Output> {
let result = timeout(
GIT_COMMAND_TIMEOUT,
Command::new("git").args(args).current_dir(cwd).output(),
)
.await;
run_git_command_with_timeout_override(args, cwd, GIT_COMMAND_TIMEOUT).await
}
/// Run a git command with a caller-provided timeout.
async fn run_git_command_with_timeout_override(
args: &[&str],
cwd: &Path,
timeout_dur: TokioDuration,
) -> Option<std::process::Output> {
let mut command = Command::new("git");
command.args(args).current_dir(cwd);
command.kill_on_drop(true);
let result = timeout(timeout_dur, command.output()).await;
match result {
Ok(Ok(output)) => Some(output),

View File

@@ -101,6 +101,7 @@ pub mod state_db;
pub mod terminal;
mod tools;
pub mod turn_diff_tracker;
mod turn_metadata;
pub use rollout::ARCHIVED_SESSIONS_SUBDIR;
pub use rollout::INTERACTIVE_SESSION_SOURCES;
pub use rollout::RolloutRecorder;
@@ -130,6 +131,7 @@ pub mod util;
pub use apply_patch::CODEX_APPLY_PATCH_ARG1;
pub use client::WEB_SEARCH_ELIGIBLE_HEADER;
pub use client::X_CODEX_TURN_METADATA_HEADER;
pub use command_safety::is_dangerous_command;
pub use command_safety::is_safe_command;
pub use exec_policy::ExecPolicyError;

View File

@@ -0,0 +1,47 @@
use std::collections::BTreeMap;
use std::path::Path;
use serde::Serialize;
use tokio::time::Duration as TokioDuration;
use crate::git_info::get_git_remote_urls_assume_git_repo_with_timeout;
use crate::git_info::get_git_repo_root;
use crate::git_info::get_head_commit_hash_with_timeout;
const TURN_METADATA_TIMEOUT: TokioDuration = TokioDuration::from_millis(150);
#[derive(Serialize)]
struct TurnMetadataWorkspace {
#[serde(skip_serializing_if = "Option::is_none")]
associated_remote_urls: Option<BTreeMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
latest_git_commit_hash: Option<String>,
}
#[derive(Serialize)]
struct TurnMetadata {
workspaces: BTreeMap<String, TurnMetadataWorkspace>,
}
/// this happens at request send time only
pub(crate) async fn build_turn_metadata_header(cwd: &Path) -> Option<String> {
let repo_root = get_git_repo_root(cwd)?;
let (latest_git_commit_hash, associated_remote_urls) = tokio::join!(
get_head_commit_hash_with_timeout(cwd, TURN_METADATA_TIMEOUT),
get_git_remote_urls_assume_git_repo_with_timeout(cwd, TURN_METADATA_TIMEOUT)
);
if latest_git_commit_hash.is_none() && associated_remote_urls.is_none() {
return None;
}
let mut workspaces = BTreeMap::new();
workspaces.insert(
repo_root.to_string_lossy().into_owned(),
TurnMetadataWorkspace {
associated_remote_urls,
latest_git_commit_hash,
},
);
serde_json::to_string(&TurnMetadata { workspaces }).ok()
}

View File

@@ -2,79 +2,56 @@ You are Codex, a coding agent based on GPT-5. You and the user share the same wo
{{ personality }}
# Working with the user
You interact with the user through a terminal. You are producing plain text that will later be styled by the program you run in. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value. Follow the formatting rules exactly.
## Final answer formatting rules
- You may format with GitHub-flavored Markdown.
- Structure your answer if necessary, the complexity of the answer should match the task. If the task is simple, your answer should be a one-liner. Order sections from general to specific to supporting.
## Tone and style
- Anything you say outside of tool use is shown to the user. Do not narrate abstractly; explain what you are doing and why, using plain language.
- Output will be rendered in a command line interface or minimal UI so keep responses tight, scannable, and low-noise. Generally avoid the use of emojis. You may format with GitHub-flavored Markdown.
- Never use nested bullets. Keep lists flat (single level). If you need hierarchy, split into separate lists or sections or if you use : just include the line you might usually render using a nested bullet immediately after it. For numbered lists, only use the `1. 2. 3.` style markers (with a period), never `1)`.
- When writing a final assistant response, state the solution first before explaining your answer. The complexity of the answer should match the task. If the task is simple, your answer should be short. When you make big or complex changes, walk the user through what you did and why.
- Headers are optional, only use them when you think they are necessary. If you do use them, use short Title Case (1-3 words) wrapped in **…**. Don't add a blank line.
- Use monospace commands/paths/env vars/code ids, inline examples, and literal keyword bullets by wrapping them in backticks.
- Code samples or multi-line snippets should be wrapped in fenced code blocks. Include an info string as often as possible.
- File References: Never output the content of large files, just provide references. When referencing files in your response follow the below rules:
* Use inline code to make file paths clickable.
* Each reference should have a stand alone path. Even if it's the same file.
* Accepted: absolute, workspacerelative, a/ or b/ diff prefixes, or bare filename/suffix.
* Optionally include line/column (1based): :line[:column] or #Lline[Ccolumn] (column defaults to 1).
* Do not use URIs like file://, vscode://, or https://.
* Do not provide range of lines
* Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\repo\project\main.rs:12:5
- Dont use emojis.
## Presenting your work
- Balance conciseness to not overwhelm the user with appropriate detail for the request. Do not narrate abstractly; explain what you are doing and why.
- Never output the content of large files, just provide references. Use inline code to make file paths clickable; each reference should have a stand alone path, even if it's the same file. Paths may be absolute, workspace-relative, a//b/ diff-prefixed, or bare filename/suffix; locations may be :line[:column] or #Lline[Ccolumn] (1-based; column defaults to 1). Do not use file://, vscode://, or https://, and do not provide line ranges. Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\repo\project\main.rs:12:5
- The user does not see command execution outputs. When asked to show the output of a command (e.g. `git show`), relay the important details in your answer or summarize the key lines so the user understands the result.
- Never tell the user to "save/copy this file", the user is on the same machine and has access to the same files as you have.
- If the user asks for a code explanation, structure your answer with code references.
- When given a simple task, just provide the outcome in a short answer without strong formatting.
- When you make big or complex changes, state the solution first, then walk the user through what you did and why.
- For casual chit-chat, just chat.
- Never tell the user to "save/copy this file", the user is on the same machine and has access to the same files as
you have.
- If you weren't able to do something, for example run tests, tell the user.
- If there are natural next steps the user may want to take, suggest them at the end of your response. Do not make suggestions if there are no natural next steps. When suggesting multiple options, use numeric lists for the suggestions so the user can quickly respond with a single number.
- If there are natural next steps the user may want to take, suggest them at the end of your response. Do not make suggestions if there are no natural next steps.
# General
- When searching for text or files, prefer using `rg` or `rg --files` respectively because `rg` is much faster than alternatives like `grep`. (If the `rg` command is not found, then use alternatives.)
## Editing constraints
# Code style
- Follow the precedence rules user instructions > system / dev / user / AGENTS.md instructions > match local file conventions > instructions below.
- Use language-appropriate best practices.
- Optimize for clarity, readability, and maintainability.
- Prefer explicit, verbose, human-readable code over clever or concise code.
- Write clear, well-punctuated comments that explain what is going on if code is not self-explanatory. You should not add comments like "Assigns the value to the variable", but a brief comment might be useful ahead of a complex code block that the user would otherwise have to spend time parsing out. Usage of these comments should be rare.
- Default to ASCII when editing or creating files. Only introduce non-ASCII or other Unicode characters when there is a clear justification and the file already uses them.
- Add succinct code comments that explain what is going on if code is not self-explanatory. You should not add comments like "Assigns the value to the variable", but a brief comment might be useful ahead of a complex code block that the user would otherwise have to spend time parsing out. Usage of these comments should be rare.
- Try to use apply_patch for single file edits, but it is fine to explore other options to make the edit if it does not work well. Do not use apply_patch for changes that are auto-generated (i.e. generating package.json or running a lint or format command like gofmt) or when scripting is more efficient (such as search and replacing a string across a codebase).
- You may be in a dirty git worktree.
# Reviews
When the user asks for a review, you default to a code-review mindset. Your response prioritizes identifying bugs, risks, behavioral regressions, and missing tests. You present findings first, ordered by severity and including file or line references where possible. Open questions or assumptions follow. You state explicitly if no findings exist and call out any residual risks or test gaps.
# Your environment
## Using GIT
- You may be working in a dirty git worktree.
* NEVER revert existing changes you did not make unless explicitly requested, since these changes were made by the user.
* If asked to make a commit or code edits and there are unrelated changes to your work or changes that you didn't make in those files, don't revert those changes.
* If the changes are in files you've touched recently, you should read carefully and understand how you can work with the changes rather than reverting them.
* If the changes are in unrelated files, just ignore them and don't revert them.
- Do not amend a commit unless explicitly requested to do so.
- While you are working, you might notice unexpected changes that you didn't make. If this happens, STOP IMMEDIATELY and ask the user how they would like to proceed.
- **NEVER** use destructive commands like `git reset --hard` or `git checkout --` unless specifically requested or approved by the user.
- While you are working, you might notice unexpected changes that you didn't make. It's likely the user made them. If this happens, STOP IMMEDIATELY and ask the user how they would like to proceed.
- Be cautious when using git. **NEVER** use destructive commands like `git reset --hard` or `git checkout --` unless specifically requested or approved by the user.
- You struggle using the git interactive console. **ALWAYS** prefer using non-interactive git commands.
## Plan tool
## Agents.md
When using the planning tool:
- Skip using the planning tool for straightforward tasks (roughly the easiest 25%).
- Do not make single-step plans.
- When you made a plan, update it after having performed one of the sub-tasks that you shared on the plan.
- If the directory you are in has an AGENTS.md file, it is provided to you at the top, and you don't have to search for it.
- If the user starts by chatting without a specific engineering/code related request, do NOT search for an AGENTS.md. Only do so once there is a relevant request.
## Special user requests
# Tool use
- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as `date`), you should do so.
- When the user asks for a review, you default to a code-review mindset. Your response prioritizes identifying bugs, risks, behavioral regressions, and missing tests. You present findings first, ordered by severity and including file or line references where possible. Open questions or assumptions follow. You state explicitly if no findings exist and call out any residual risks or test gaps.
## Frontend tasks
When doing frontend design tasks, avoid collapsing into "AI slop" or safe, average-looking layouts.
Aim for interfaces that feel intentional, bold, and a bit surprising.
- Typography: Use expressive, purposeful fonts and avoid default stacks (Inter, Roboto, Arial, system).
- Color & Look: Choose a clear visual direction; define CSS variables; avoid purple-on-white defaults. No purple bias or dark mode bias.
- Motion: Use a few meaningful animations (page-load, staggered reveals) instead of generic micro-motions.
- Background: Don't rely on flat, single-color backgrounds; use gradients, shapes, or subtle patterns to build atmosphere.
- Overall: Avoid boilerplate layouts and interchangeable UI patterns. Vary themes, type families, and visual languages across outputs.
- Ensure the page loads properly on both desktop and mobile
Exception: If working within an existing website or design system, preserve the established patterns, structure, and visual language.
- Unless you are otherwise instructed, prefer using `rg` or `rg --files` respectively when searching because `rg` is much faster than alternatives like `grep`. If the `rg` command is not found, then use alternatives.
- Use the plan tool to explain to the user what you are going to do
- Only use it for more complex tasks, do not use it for straightforward tasks (roughly the easiest 25%).
- Do not make single-step plans. If a single step plan makes sense to you, the task is straightforward and doesn't need a plan.
- When you made a plan, update it after having performed one of the sub-tasks that you shared on the plan.
- Try to use apply_patch for single file edits, but it is fine to explore other options to make the edit if it does not work well. Do not use apply_patch for changes that are auto-generated (i.e. generating package.json or running a lint or format command like gofmt) or when scripting is more efficient (such as search and replacing a string across a codebase).

View File

@@ -102,7 +102,7 @@ async fn run_request(input: Vec<ResponseItem>) -> Value {
SessionSource::Exec,
TransportManager::new(),
)
.new_session();
.new_session(None, None);
let mut prompt = Prompt::default();
prompt.input = input;

View File

@@ -103,7 +103,7 @@ async fn run_stream_with_bytes(sse_body: &[u8]) -> Vec<ResponseEvent> {
SessionSource::Exec,
TransportManager::new(),
)
.new_session();
.new_session(None, None);
let mut prompt = Prompt::default();
prompt.input = vec![ResponseItem::Message {

View File

@@ -12,6 +12,7 @@ use codex_core::ResponseItem;
use codex_core::TransportManager;
use codex_core::WEB_SEARCH_ELIGIBLE_HEADER;
use codex_core::WireApi;
use codex_core::X_CODEX_TURN_METADATA_HEADER;
use codex_core::models_manager::manager::ModelsManager;
use codex_otel::OtelManager;
use codex_protocol::ThreadId;
@@ -23,6 +24,7 @@ use core_test_support::load_default_config_for_test;
use core_test_support::responses;
use core_test_support::test_codex::test_codex;
use futures::StreamExt;
use pretty_assertions::assert_eq;
use tempfile::TempDir;
use wiremock::matchers::header;
@@ -98,7 +100,7 @@ async fn responses_stream_includes_subagent_header_on_review() {
session_source,
TransportManager::new(),
)
.new_session();
.new_session(None, None);
let mut prompt = Prompt::default();
prompt.input = vec![ResponseItem::Message {
@@ -124,6 +126,101 @@ async fn responses_stream_includes_subagent_header_on_review() {
);
}
#[tokio::test]
async fn responses_stream_includes_turn_metadata_header_when_set() {
core_test_support::skip_if_no_network!();
let server = responses::start_mock_server().await;
let response_body = responses::sse(vec![
responses::ev_response_created("resp-1"),
responses::ev_completed("resp-1"),
]);
let request_recorder = responses::mount_sse_once(&server, response_body).await;
let provider = ModelProviderInfo {
name: "mock".into(),
base_url: Some(format!("{}/v1", server.uri())),
env_key: None,
env_key_instructions: None,
experimental_bearer_token: None,
wire_api: WireApi::Responses,
query_params: None,
http_headers: None,
env_http_headers: None,
request_max_retries: Some(0),
stream_max_retries: Some(0),
stream_idle_timeout_ms: Some(5_000),
requires_openai_auth: false,
supports_websockets: false,
};
let codex_home = TempDir::new().expect("failed to create TempDir");
let mut config = load_default_config_for_test(&codex_home).await;
config.model_provider_id = provider.name.clone();
config.model_provider = provider.clone();
let effort = config.model_reasoning_effort;
let summary = config.model_reasoning_summary;
let model = ModelsManager::get_model_offline(config.model.as_deref());
config.model = Some(model.clone());
let config = Arc::new(config);
let conversation_id = ThreadId::new();
let auth_mode = AuthMode::Chatgpt;
let session_source = SessionSource::SubAgent(SubAgentSource::Review);
let model_info = ModelsManager::construct_model_info_offline(model.as_str(), &config);
let otel_manager = OtelManager::new(
conversation_id,
model.as_str(),
model_info.slug.as_str(),
None,
Some("test@test.com".to_string()),
Some(auth_mode),
false,
"test".to_string(),
session_source.clone(),
);
let turn_metadata =
r#"{"workspaces":{"/repo":{"latest_git_commit_hash":"abc123"}}}"#.to_string();
let mut client_session = ModelClient::new(
Arc::clone(&config),
None,
model_info,
otel_manager,
provider,
effort,
summary,
conversation_id,
session_source,
TransportManager::new(),
)
.new_session_with_turn_metadata(Some(turn_metadata.clone()));
let mut prompt = Prompt::default();
prompt.input = vec![ResponseItem::Message {
id: None,
role: "user".into(),
content: vec![ContentItem::InputText {
text: "hello".into(),
}],
end_turn: None,
}];
let mut stream = client_session.stream(&prompt).await.expect("stream failed");
while let Some(event) = stream.next().await {
if matches!(event, Ok(ResponseEvent::Completed { .. })) {
break;
}
}
let request = request_recorder.single_request();
assert_eq!(
request.header(X_CODEX_TURN_METADATA_HEADER).as_deref(),
Some(turn_metadata.as_str())
);
}
#[tokio::test]
async fn responses_stream_includes_subagent_header_on_other() {
core_test_support::skip_if_no_network!();
@@ -197,7 +294,7 @@ async fn responses_stream_includes_subagent_header_on_other() {
session_source,
TransportManager::new(),
)
.new_session();
.new_session(None, None);
let mut prompt = Prompt::default();
prompt.input = vec![ResponseItem::Message {
@@ -354,7 +451,7 @@ async fn responses_respects_model_info_overrides_from_config() {
session_source,
TransportManager::new(),
)
.new_session();
.new_session(None, None);
let mut prompt = Prompt::default();
prompt.input = vec![ResponseItem::Message {

View File

@@ -1190,7 +1190,7 @@ async fn azure_responses_request_includes_store_and_reasoning_ids() {
SessionSource::Exec,
TransportManager::new(),
)
.new_session();
.new_session(None, None);
let mut prompt = Prompt::default();
prompt.input.push(ResponseItem::Reasoning {

View File

@@ -53,7 +53,7 @@ async fn responses_websocket_streams_request() {
.await;
let harness = websocket_harness(&server).await;
let mut session = harness.client.new_session();
let mut session = harness.client.new_session(None, None);
let prompt = prompt_with_input(vec![message_item("hello")]);
stream_until_complete(&mut session, &prompt).await;
@@ -83,7 +83,7 @@ async fn responses_websocket_emits_websocket_telemetry_events() {
let harness = websocket_harness(&server).await;
harness.otel_manager.reset_runtime_metrics();
let mut session = harness.client.new_session();
let mut session = harness.client.new_session(None, None);
let prompt = prompt_with_input(vec![message_item("hello")]);
stream_until_complete(&mut session, &prompt).await;
@@ -113,7 +113,7 @@ async fn responses_websocket_emits_reasoning_included_event() {
.await;
let harness = websocket_harness(&server).await;
let mut session = harness.client.new_session();
let mut session = harness.client.new_session(None, None);
let prompt = prompt_with_input(vec![message_item("hello")]);
let mut stream = session
@@ -147,7 +147,7 @@ async fn responses_websocket_appends_on_prefix() {
.await;
let harness = websocket_harness(&server).await;
let mut session = harness.client.new_session();
let mut session = harness.client.new_session(None, None);
let prompt_one = prompt_with_input(vec![message_item("hello")]);
let prompt_two = prompt_with_input(vec![message_item("hello"), message_item("second")]);
@@ -183,7 +183,7 @@ async fn responses_websocket_creates_on_non_prefix() {
.await;
let harness = websocket_harness(&server).await;
let mut session = harness.client.new_session();
let mut session = harness.client.new_session(None, None);
let prompt_one = prompt_with_input(vec![message_item("hello")]);
let prompt_two = prompt_with_input(vec![message_item("different")]);