Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions .github/workflows/bazel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
# signal without putting PR latency back on the critical path. When
# Code-mode unit tests run on every Bazel target. When authenticated RBE
# is available, the Windows-cross shards exercise the source-built V8 path.
timeout-minutes: 30
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -139,7 +139,7 @@ jobs:
# Split the Windows Bazel test leg across separate Windows hosts. Jobs with
# BuildBuddy credentials use Linux RBE for build actions; test execution
# remains on a Windows runner.
timeout-minutes: 30
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
Expand All @@ -148,9 +148,7 @@ jobs:
- 2
- 3
- 4
runs-on:
group: ${{ github.event.repository.name }}-runners
labels: ${{ github.event.repository.name }}-windows-x64
runs-on: windows-latest
name: Bazel test on windows-latest for x86_64-pc-windows-gnullvm shard ${{ matrix.shard }}/4
environment:
name: bazel
Expand Down Expand Up @@ -188,6 +186,16 @@ jobs:
set -euo pipefail

bazel_test_query='tests(//...) except tests(//third_party/v8:all) except attr(tags, "manual", tests(//...))'
if [[ -z "${BUILDBUDDY_API_KEY:-}" ]]; then
# Without authenticated RBE, this job falls back from Windows
# cross-compile to native hosted Windows tests. Keep that fallback
# focused on stable target-level Windows coverage; the
# subprocess/ConPTY-heavy suites below are covered by Linux/macOS
# PR jobs and the native Windows main-branch lane.
bazel_test_query="${bazel_test_query} except //codex-rs/core:core-all-test"
bazel_test_query="${bazel_test_query} except //codex-rs/shell-command:shell-command-unit-tests"
bazel_test_query="${bazel_test_query} except //codex-rs/utils/pty:pty-unit-tests"
fi
mapfile -t bazel_targets < <(
./.github/scripts/run-bazel-query-ci.sh --output=label -- "${bazel_test_query}" \
| LC_ALL=C sort
Expand Down Expand Up @@ -267,9 +275,7 @@ jobs:
# it a larger timeout.
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
timeout-minutes: 40
runs-on:
group: ${{ github.event.repository.name }}-runners
labels: ${{ github.event.repository.name }}-windows-x64
runs-on: windows-latest
name: Bazel test on windows-latest for x86_64-pc-windows-gnullvm (native main)
environment:
name: bazel
Expand Down Expand Up @@ -343,7 +349,7 @@ jobs:
uses: ./.github/actions/check-clean-worktree

clippy:
timeout-minutes: 30
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
Expand All @@ -358,10 +364,7 @@ jobs:
target: aarch64-apple-darwin
- os: windows-latest
target: x86_64-pc-windows-gnullvm
runs_on:
group: ${{ github.event.repository.name }}-runners
labels: ${{ github.event.repository.name }}-windows-x64
runs-on: ${{ matrix.runs_on || matrix.os }}
runs-on: ${{ matrix.os }}
name: Bazel clippy on ${{ matrix.os }} for ${{ matrix.target }}
environment:
name: bazel
Expand Down Expand Up @@ -447,7 +450,7 @@ jobs:
uses: ./.github/actions/check-clean-worktree

verify-release-build:
timeout-minutes: 30
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
Expand All @@ -458,10 +461,7 @@ jobs:
target: aarch64-apple-darwin
- os: windows-latest
target: x86_64-pc-windows-gnullvm
runs_on:
group: ${{ github.event.repository.name }}-runners
labels: ${{ github.event.repository.name }}-windows-x64
runs-on: ${{ matrix.runs_on || matrix.os }}
runs-on: ${{ matrix.os }}
name: Verify release build on ${{ matrix.os }} for ${{ matrix.target }}
environment:
name: bazel
Expand Down
13 changes: 5 additions & 8 deletions .github/workflows/rust-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ jobs:

argument_comment_lint_prebuilt:
name: Argument comment lint - ${{ matrix.name }}
runs-on: ${{ matrix.runs_on || matrix.runner }}
runs-on: ${{ matrix.runner }}
timeout-minutes: ${{ matrix.timeout_minutes }}
needs: changed
environment:
Expand All @@ -184,16 +184,13 @@ jobs:
include:
- name: Linux
runner: ubuntu-24.04
timeout_minutes: 30
timeout_minutes: 60
- name: macOS
runner: macos-15-xlarge
timeout_minutes: 30
timeout_minutes: 60
- name: Windows
runner: windows-x64
timeout_minutes: 30
runs_on:
group: ${{ github.event.repository.name }}-runners
labels: ${{ github.event.repository.name }}-windows-x64
runner: windows-latest
timeout_minutes: 60
steps:
- name: Check whether argument comment lint should run
id: argument_comment_lint_gate
Expand Down
12 changes: 4 additions & 8 deletions .github/workflows/sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ on:

jobs:
python-sdk:
runs-on:
group: ${{ github.event.repository.name }}-runners
labels: ${{ github.event.repository.name }}-linux-x64
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout repository
Expand Down Expand Up @@ -44,10 +42,8 @@ jobs:
uses: ./.github/actions/check-clean-worktree

sdks:
runs-on:
group: ${{ github.event.repository.name }}-runners
labels: ${{ github.event.repository.name }}-linux-x64
timeout-minutes: 10
runs-on: ubuntu-24.04
timeout-minutes: 60
environment:
name: bazel
deployment: false
Expand Down Expand Up @@ -156,7 +152,7 @@ jobs:
run: pnpm -r --filter ./sdk/typescript run test

- name: Save bazel repository cache
if: always() && !cancelled() && steps.setup_bazel.outputs.cache-hit != 'true'
if: always() && !cancelled()
continue-on-error: true
uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
Expand Down
16 changes: 16 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -396,13 +396,22 @@ crate.annotation(

inject_repo(crate, "llvm", "llvm-project", "macos_sdk")

crate.annotation(
crate = "cxx-build",
patch_args = ["-p1"],
patches = [
"//patches:cxx-build_bazel_out_dir_shared.patch",
],
)
crate.annotation(
# Provide the hermetic SDK path so the build script doesn't try to invoke an unavailable `xcrun --show-sdk-path`.
build_script_data = [
"@macos_sdk//sysroot",
],
build_script_env = {
"CXX_BUILD_BAZEL_OUT_DIR_SHARED": "1",
"WEBRTC_SYS_DARWIN_SDK_PATH": "$(location @macos_sdk//sysroot)",
"WEBRTC_SYS_BAZEL_OUT_DIR_SCRATCH": "1",
"WEBRTC_SYS_LINK_OUT_DIR": "1",
},
crate = "webrtc-sys",
Expand All @@ -412,6 +421,13 @@ crate.annotation(
"//patches:webrtc-sys_hermetic_darwin_sysroot.patch",
],
)
crate.annotation(
crate = "webrtc-sys-build",
patch_args = ["-p1"],
patches = [
"//patches:webrtc-sys-build_bazel_out_dir_scratch.patch",
],
)

# Fix readme inclusions
crate.annotation(
Expand Down
7 changes: 7 additions & 0 deletions codex-rs/app-server-protocol/schema/json/ClientRequest.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions codex-rs/app-server-protocol/schema/typescript/v2/index.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion codex-rs/app-server-protocol/src/protocol/thread_history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,8 @@ impl ThreadHistoryBuilder {
| RolloutItem::InterAgentCommunicationMetadata { .. }
| RolloutItem::TurnContext(_)
| RolloutItem::WorldState(_)
| RolloutItem::SessionMeta(_) => {}
| RolloutItem::SessionMeta(_)
| RolloutItem::SamplingBoundary(_) => {}
}
}

Expand Down
5 changes: 5 additions & 0 deletions codex-rs/app-server-protocol/src/protocol/v2/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,11 @@ fn thread_fork_last_turn_id_round_trips() {
serde_json::Value::Null,
"optional lastTurnId should serialize as null when omitted"
);
assert_eq!(
omitted["activeForkMode"],
serde_json::Value::Null,
"optional activeForkMode should serialize as null when omitted"
);
}

#[test]
Expand Down
18 changes: 18 additions & 0 deletions codex-rs/app-server-protocol/src/protocol/v2/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,24 @@ pub struct ThreadForkParams {
#[experimental("thread/fork.excludeTurns")]
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub exclude_turns: bool,
/// How to fork a currently active source thread.
///
/// Omitted preserves the legacy interrupted snapshot behavior. Use
/// `nonInterrupting` to fork from an existing stable source-owned sampling
/// boundary without cancelling or mutating the source thread.
#[experimental("thread/fork.activeForkMode")]
#[serde(default)]
#[ts(optional = nullable)]
pub active_fork_mode: Option<ThreadForkActiveMode>,
}

#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub enum ThreadForkActiveMode {
Interrupt,
NonInterrupting,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
Expand Down
4 changes: 2 additions & 2 deletions codex-rs/app-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ Example with notification opt-out:

- `thread/start` — create a new thread; emits `thread/started` (including the current `thread.status`) and auto-subscribes you to turn/item events for that thread. When the request includes a `cwd` and the resolved sandbox is `workspace-write` or full access, app-server also marks that project as trusted in the user `config.toml`. Pass `sessionStartSource: "clear"` when starting a replacement thread after clearing the current session so `SessionStart` hooks receive `source: "clear"` instead of the default `"startup"`. Experimental `allowProviderModelFallback` lets providers backed by an authoritative static model catalog replace an unavailable requested `model` with the catalog default; dynamic or cached catalogs preserve the requested model. Experimental `runtimeWorkspaceRoots` replaces the thread-scoped runtime workspace roots used to materialize `:workspace_roots`; paths must be absolute. For permissions, prefer experimental `permissions` profile selection by id; the legacy `sandbox` shorthand is still accepted but cannot be combined with `permissions`. Deprecated experimental `multiAgentMode` is ignored; use Ultra reasoning effort for proactive multi-agent behavior. Experimental `environments` selects the sticky execution environments for turns on the thread; omit it to use the server default, pass `[]` to disable environments, or pass explicit environment ids with per-environment `cwd`. Experimental `selectedCapabilityRoots` selects environment-owned plugin or standalone-skill roots using environment-native absolute paths. Skills found below those roots are listed and read through the owning environment. Stdio MCP servers declared by selected plugins are started in that environment, and HTTP MCP connections use that environment's HTTP client.
- `thread/resume` — reopen an existing thread by id so subsequent `turn/start` calls append to it. Accepts the same permission override rules as `thread/start`.
- `thread/fork` — fork an existing thread into a new thread id by copying the stored history; pass an optional `lastTurnId` to copy history only through that turn, inclusive, and drop later turns from the fork. An in-progress `lastTurnId` is rejected. If `lastTurnId` is null while the source thread is mid-turn, the fork records the same interruption marker as `turn/interrupt` instead of inheriting an unmarked partial turn suffix. The returned `thread.forkedFromId` points at the source thread when known. Accepts `ephemeral: true` for an in-memory temporary fork, emits `thread/started` (including the current `thread.status`), and auto-subscribes you to turn/item events for the new thread. Experimental clients can pass `excludeTurns: true` when they plan to page fork history via `thread/turns/list` instead of receiving the full turn array immediately. Accepts the same permission override rules as `thread/start`.
- `thread/fork` — fork an existing thread into a new thread id by copying the stored history; pass an optional `lastTurnId` to copy history only through that turn, inclusive, and drop later turns from the fork. An in-progress `lastTurnId` is rejected. If `lastTurnId` is null while the source thread is mid-turn, the default active fork mode records the same interruption marker as `turn/interrupt` instead of inheriting an unmarked partial turn suffix. Experimental clients can pass `activeForkMode: "nonInterrupting"` to fork from the latest existing stable sampling boundary without interrupting the source thread; if no boundary is available for a mid-turn source, the request fails. The returned `thread.forkedFromId` points at the source thread when known. Accepts `ephemeral: true` for an in-memory temporary fork, emits `thread/started` (including the current `thread.status`), and auto-subscribes you to turn/item events for the new thread. Experimental clients can pass `excludeTurns: true` when they plan to page fork history via `thread/turns/list` instead of receiving the full turn array immediately. Accepts the same permission override rules as `thread/start`.
- `thread/start`, `thread/resume`, and `thread/fork` responses include the legacy `sandbox` compatibility projection. `instructionSources` lists loaded instruction files using each source environment's native absolute path syntax, including files loaded from remote environments. Experimental clients can read `runtimeWorkspaceRoots` for the thread-scoped runtime roots and `activePermissionProfile` for the named or implicit built-in profile identity/provenance when known. Their deprecated experimental `multiAgentMode` field, and the corresponding thread setting, always report `explicitRequestOnly`; Ultra reasoning effort is the source of proactive multi-agent behavior.
- `thread/list` — page through stored threads; supports cursor-based pagination and optional `modelProviders`, `sourceKinds`, `archived`, `cwd`, and `searchTerm` filters. Experimental clients can use `parentThreadId` for direct spawned children or `ancestorThreadId` for spawned descendants at any depth; the two filters are mutually exclusive. Review and Guardian threads are not included because they do not participate in that spawn-edge lifecycle. Each returned `thread` includes `status` (`ThreadStatus`), defaulting to `notLoaded` when the thread is not currently loaded. Subagent threads also include `parentThreadId` when the immediate parent is known.
- `thread/loaded/list` — list the thread ids currently loaded in memory.
Expand Down Expand Up @@ -355,7 +355,7 @@ Example:
} }
```

To branch from a stored session, call `thread/fork` with the `thread.id`. This creates a new thread id and emits a `thread/started` notification for it. The returned `thread.sessionId` identifies the current live session tree root. Root threads use their own `thread.id` as `thread.sessionId`; stored threads that are not loaded also report their own `thread.id`, because resuming one makes it the root of a new live session tree. When the source history includes persisted token usage, the server also emits `thread/tokenUsage/updated` for the new thread immediately after the response. If the source thread is actively running, the fork snapshots it as if the current turn had been interrupted first. Pass `ephemeral: true` when the fork should stay in-memory only:
To branch from a stored session, call `thread/fork` with the `thread.id`. This creates a new thread id and emits a `thread/started` notification for it. The returned `thread.sessionId` identifies the current live session tree root. Root threads use their own `thread.id` as `thread.sessionId`; stored threads that are not loaded also report their own `thread.id`, because resuming one makes it the root of a new live session tree. When the source history includes persisted token usage, the server also emits `thread/tokenUsage/updated` for the new thread immediately after the response. If the source thread is actively running, the default fork snapshots it as if the current turn had been interrupted first. Pass `activeForkMode: "nonInterrupting"` to fork from an existing stable boundary without interrupting the active source; a mid-turn source with no stable boundary returns an invalid-request error. Pass `ephemeral: true` when the fork should stay in-memory only:

```json
{ "method": "thread/fork", "id": 12, "params": { "threadId": "thr_123", "ephemeral": true } }
Expand Down
Loading
Loading