Merge remote-tracking branch 'origin/main' into codex/pr28761-refresh

This commit is contained in:
Chris Bookholt
2026-06-29 15:24:17 -07:00
1113 changed files with 65251 additions and 11569 deletions
+9 -7
View File
@@ -107,8 +107,9 @@ common:ci-bazel --config=ci
common:ci-bazel --build_metadata=TAG_workflow=bazel
# Keep code-mode integration cases out of ordinary Bazel legs. The
# Windows-cross config below re-enables them after generating its Windows V8
# snapshot on the Windows runner.
common:ci-bazel --test_env=CODEX_BAZEL_TEST_SKIP_FILTERS=suite::code_mode::
# snapshot on the Windows runner. Also skip the ConPTY Ctrl-C integration test
# until Windows Bazel CI can reliably interrupt foreground processes.
common:ci-bazel --test_env=CODEX_BAZEL_TEST_SKIP_FILTERS=suite::code_mode::,tests::windows_tests::conpty_ctrl_c_interrupts_powershell_foreground_child
# Shared config for Bazel-backed Rust linting.
build:clippy --aspects=@rules_rust//rust:defs.bzl%rust_clippy_aspect
@@ -191,11 +192,12 @@ common:ci-windows-cross --strategy=TestRunner=local
common:ci-windows-cross --strategy=V8Mksnapshot=local
common:ci-windows-cross --local_test_jobs=4
common:ci-windows-cross --test_env=RUST_TEST_THREADS=1
# Native Windows CI still covers the PowerShell tests. The cross-built gnullvm
# binaries currently hang in PowerShell AST parser tests when those binaries are
# run on the Windows runner. Keep V8-backed code-mode tests enabled except for
# the hidden dynamic-tool callback test, which currently times out on Windows.
common:ci-windows-cross --test_env=CODEX_BAZEL_TEST_SKIP_FILTERS=powershell,suite::code_mode::code_mode_can_call_hidden_dynamic_tools
# Native Windows CI still covers the PowerShell parser-process tests. The
# cross-built gnullvm binaries currently hang in those tests when run on the
# Windows runner. Keep V8-backed code-mode tests enabled except for the hidden
# dynamic-tool callback test, which currently times out on Windows. This config
# replaces the base skip list, so repeat the exact ConPTY Ctrl-C test exclusion.
common:ci-windows-cross --test_env=CODEX_BAZEL_TEST_SKIP_FILTERS=command_safety::powershell_parser::tests::,suite::code_mode::code_mode_can_call_hidden_dynamic_tools,tests::windows_tests::conpty_ctrl_c_interrupts_powershell_foreground_child
common:ci-windows-cross --platforms=//:windows_x86_64_gnullvm
common:ci-windows-cross --extra_execution_platforms=//:rbe,//:windows_x86_64_msvc
common:ci-windows-cross --extra_toolchains=//:windows_gnullvm_tests_on_msvc_host_toolchain
+1 -1
View File
@@ -3,7 +3,7 @@ name: code-review
description: Run a final code review on a pull request
---
Use subagents to review code using all code-review-* skills in this repository other than this orchestrator. One subagent per skill. Pass full skill path to subagents. Use xhigh reasoning.
Use subagents to review code using all code-review-* skills other than this orchestrator. One subagent per skill. Pass full skill path to subagents. Use xhigh reasoning.
You must return every single issue from every subagent. You can return an unlimited number of findings.
Use raw Markdown to report findings.
+95 -8
View File
@@ -1,17 +1,104 @@
---
name: remote-tests
description: How to run tests using remote executor.
description: Testing against remote executors in integration tests.
---
Some Codex integration tests select `local`, `docker`, or `wine-exec` through
`CODEX_TEST_ENVIRONMENT`. The legacy `CODEX_TEST_REMOTE_ENV=<container>` still
selects Docker; otherwise execution is local.
Remote executor tests exercise the app-server/exec-server split to ensure that agent features work
in both local and remote execution environments.
Docker container is built and initialized via ./scripts/test-remote-env.sh
Remote executor tests currently require an x86_64 Linux host machine. There are two flavors:
On x86-64 Linux, run Wine exec with
`bazel test //codex-rs/core:core-all-wine-exec-test --test_output=errors`.
Temporary blockers belong beside the test in `skip_if_wine_exec!` calls.
1. Docker (Linux exec-server)
2. Wine (Windows exec-server)
## Test Fixtures
Individual test cases must opt-in to being run against a remote executor.
### codex_core
Use `TestCodexBuilder::build_with_auto_env()` to opt-in to remote execution in core integration
tests unless the test needs more precise control over its executor.
### app-server
Start the server with `TestAppServer::new_with_auto_env()` unless the test defines its own
`$CODEX_HOME/environments.toml` or will define custom environments at runtime.
Start threads with `TestAppServer::send_thread_start_request_with_auto_env()` if you've created the
server with the `auto_env` approach. Omit `ThreadStartParams.environments` (leave it as `None`) when
doing so.
## Test Skips
If a test doesn't pass in a particular remote executor configuration you can skip it in just that
configuration. Include a string reason for future readers when the selected skip macro supports
one.
Choose the skip macro by what causes the test to fail:
- `skip_if_target_windows!`: Windows target behavior.
- `skip_if_wine_exec!`: Wine-exec runner constraints.
- `skip_if_host_windows!`: Windows host constraints.
- `skip_if_remote!`: Local-only test behavior.
- `skip_if_no_remote_env!`: Remote-only test behavior.
Prefer defining tests that run in all host/target configurations by default. See the `$path-types`
skill for the most common changes required to make tests compatible.
## Docker
Docker container is built and initialized via ./scripts/test-remote-env.sh. Sourcing this script
in bash also provides the `codex_remote_env_cleanup` function to use after testing.
To run core integration tests against a Docker remote executor:
```bash
bash -c '
set -euo pipefail
unset CODEX_TEST_REMOTE_EXEC_SERVER_URL
source scripts/test-remote-env.sh
trap codex_remote_env_cleanup EXIT
cd codex-rs
just test -p codex-core --test all
'
```
To run app-server integration tests against a Docker remote executor:
```bash
bash -c '
set -euo pipefail
unset CODEX_TEST_REMOTE_EXEC_SERVER_URL
source scripts/test-remote-env.sh
trap codex_remote_env_cleanup EXIT
cd codex-rs
just test -p codex-app-server --test all
'
```
## Wine
These tests build an exec-server for Windows and run it under Wine, with the app-server staying on
the Linux host. The cross-platform build dependency means they only run in Bazel.
For core integration tests:
```sh
bazel test //codex-rs/core:core-all-wine-exec-test
```
For app-server integration tests:
```sh
bazel test //codex-rs/app-server:app-server-all-wine-exec-test
```
## Devboxes
You can use a devbox to run these tests if you are running on a macOS machine.
You can list devboxes via `applied_devbox ls`, pick the one with `codex` in the name.
Connect to devbox via `ssh <devbox_name>`.
+1
View File
@@ -1,5 +1,6 @@
# Core crate ownership.
/codex-rs/core/ @openai/codex-core-agent-team
/codex-rs/exec-server-protocol/ @openai/codex-core-agent-team
/codex-rs/ext/extension-api/ @openai/codex-core-agent-team
/codex-rs/prompts/ @openai/codex-core-agent-team
/codex-rs/utils/path-uri/ @openai/codex-core-agent-team
@@ -0,0 +1,19 @@
name: check-clean-worktree
description: Fail when a CI job leaves tracked changes or untracked files in the repository worktree.
runs:
using: composite
steps:
- name: Check for a clean worktree
shell: bash
run: |
set -euo pipefail
status="$(git -C "${GITHUB_WORKSPACE}" status --porcelain=v1 --untracked-files=normal --ignore-submodules=none)"
if [[ -z "${status}" ]]; then
exit 0
fi
echo "::error::CI job left tracked changes or untracked files in the repository worktree"
printf '%s\n' "${status}"
exit 1
@@ -34,6 +34,10 @@ runs:
- name: Set up Bazel
uses: bazel-contrib/setup-bazel@c5acdfb288317d0b5c0bbd7a396a3dc868bb0f86 # 0.19.0
# Without an explicit Bazelisk version, setup-bazel leaves PATH unchanged
# and Windows can use the runner's standalone Bazel, ignoring .bazelversion.
with:
bazelisk-version: 1.28.1
- name: Configure Bazel repository cache
id: configure_bazel_repository_cache
+4
View File
@@ -5,21 +5,25 @@
"macos-aarch64": {
"name": "codex-zsh-aarch64-apple-darwin.tar.gz",
"format": "tar.gz",
"hash": "sha256",
"path": "codex-zsh/bin/zsh"
},
"macos-x86_64": {
"name": "codex-zsh-x86_64-apple-darwin.tar.gz",
"format": "tar.gz",
"hash": "sha256",
"path": "codex-zsh/bin/zsh"
},
"linux-x86_64": {
"name": "codex-zsh-x86_64-unknown-linux-musl.tar.gz",
"format": "tar.gz",
"hash": "sha256",
"path": "codex-zsh/bin/zsh"
},
"linux-aarch64": {
"name": "codex-zsh-aarch64-unknown-linux-musl.tar.gz",
"format": "tar.gz",
"hash": "sha256",
"path": "codex-zsh/bin/zsh"
}
}
@@ -9,6 +9,7 @@ Usage: build-codex-package-archive.sh \
--entrypoint-dir <dir> \
--archive-dir <dir> \
[--bwrap-bin <path>] \
[--zsh-manifest <path>] \
[--codex-command-runner-bin <path>] \
[--codex-windows-sandbox-setup-bin <path>] \
[--target-suffixed-entrypoint]
@@ -48,6 +49,10 @@ while [[ $# -gt 0 ]]; do
bwrap_bin_provided="true"
shift 2
;;
--zsh-manifest)
resource_args+=(--zsh-manifest "${2:?--zsh-manifest requires a value}")
shift 2
;;
--codex-command-runner-bin)
resource_args+=(
--codex-command-runner-bin
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""Fail a terminal CI job unless every serialized dependency succeeded.
Parent workflows pass GitHub's `toJSON(needs)` object through the NEEDS
environment variable. Treat skipped and cancelled dependencies as failures too:
for a required fan-in job, only an explicit success is safe to accept.
"""
import json
import os
def main() -> None:
# Keep result policy in one script so blocking-ci and postmerge-ci cannot
# drift in how they interpret dependency conclusions.
needs = json.loads(os.environ["NEEDS"])
failures = sorted(
(name, dependency["result"])
for name, dependency in needs.items()
if dependency["result"] != "success"
)
if failures:
print("CI dependencies did not succeed:")
for name, result in failures:
print(f"{name}: {result}")
raise SystemExit(1)
print("All CI dependencies succeeded.")
if __name__ == "__main__":
main()
+87 -9
View File
@@ -1,12 +1,44 @@
#!/usr/bin/env python3
"""Decide which V8 canary work is needed for a commit range.
The workflow deliberately has no trigger-level path filters because it is both
directly triggered for pull requests and called by postmerge-ci. Keeping the
patterns here gives those entrypoints one source of truth; unrelated events
still run metadata but skip the expensive build matrices.
"""
import argparse
import subprocess
import tomllib
from fnmatch import fnmatchcase
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
# These patterns replace the old pull_request/push path filters. Include parent
# workflow changes because they can alter whether the canary is invoked.
CANARY_PATH_PATTERNS = {
".bazelrc",
".github/actions/setup-bazel-ci/**",
".github/scripts/run_bazel_with_buildbuddy.py",
".github/scripts/rusty_v8_bazel.py",
".github/scripts/rusty_v8_module_bazel.py",
".github/scripts/v8_canary_changes.py",
".github/workflows/postmerge-ci.yml",
".github/workflows/rusty-v8-release.yml",
".github/workflows/v8-canary.yml",
"MODULE.bazel",
"MODULE.bazel.lock",
"codex-rs/Cargo.toml",
"patches/BUILD.bazel",
"patches/llvm_*.patch",
"patches/rules_cc_*.patch",
"patches/v8_*.patch",
"third_party/v8/**",
}
# Windows source builds are a narrower, more expensive subset of the canary.
# A V8 version change also requires them even when no path below changed.
WINDOWS_SOURCE_BUILD_PATHS = {
".github/scripts/rusty_v8_bazel.py",
".github/scripts/rusty_v8_module_bazel.py",
@@ -16,6 +48,30 @@ WINDOWS_SOURCE_BUILD_PATHS = {
}
def matching_canary_paths(changed_files: set[str]) -> set[str]:
"""Return changed paths that require the general V8 build matrix."""
return {
path
for path in changed_files
if any(fnmatchcase(path, pattern) for pattern in CANARY_PATH_PATTERNS)
}
def canary_required(
changed_files: set[str],
base_v8_version: str,
head_v8_version: str,
*,
force: bool = False,
) -> bool:
"""Return whether the general V8 build matrix should run."""
return (
force
or base_v8_version != head_v8_version
or bool(matching_canary_paths(changed_files))
)
def resolved_v8_version(cargo_lock: bytes) -> str:
versions = sorted(
{
@@ -36,6 +92,7 @@ def windows_source_required(
*,
force: bool = False,
) -> bool:
"""Return whether Windows must rebuild rusty_v8 from source."""
return (
force
or base_v8_version != head_v8_version
@@ -58,6 +115,8 @@ def merge_base(base: str, head: str, *, root: Path = ROOT) -> str:
def changed_files(base: str, head: str, *, root: Path = ROOT) -> set[str]:
# Three-dot diff gives PRs merge-base semantics while remaining equivalent
# to before/after for ordinary linear pushes to main.
output = git_output(
"diff",
"--name-only",
@@ -79,25 +138,44 @@ def parse_args() -> argparse.Namespace:
def main() -> None:
args = parse_args()
if args.force:
required = True
reason = "manual workflow dispatch"
# workflow_dispatch has no comparison range, and callers use it as a
# manual retry path, so it intentionally runs every variant.
canary = True
canary_reason = "manual workflow dispatch"
windows_source = True
windows_source_reason = "manual workflow dispatch"
elif not args.base or not args.head:
raise SystemExit("--base and --head are required unless --force is set")
else:
files = changed_files(args.base, args.head)
base_version = v8_version_at_revision(merge_base(args.base, args.head))
head_version = v8_version_at_revision(args.head)
required = windows_source_required(files, base_version, head_version)
matched_canary_paths = sorted(matching_canary_paths(files))
canary = canary_required(files, base_version, head_version)
windows_source = windows_source_required(files, base_version, head_version)
if base_version != head_version:
reason = f"v8 version changed from {base_version} to {head_version}"
canary_reason = (
f"v8 version changed from {base_version} to {head_version}"
)
windows_source_reason = canary_reason
else:
matched_paths = sorted(files & WINDOWS_SOURCE_BUILD_PATHS)
reason = (
", ".join(matched_paths) if matched_paths else "no relevant changes"
canary_reason = (
", ".join(matched_canary_paths)
if matched_canary_paths
else "no relevant changes"
)
matched_windows_paths = sorted(files & WINDOWS_SOURCE_BUILD_PATHS)
windows_source_reason = (
", ".join(matched_windows_paths)
if matched_windows_paths
else "no relevant changes"
)
print(f"windows_source_required={str(required).lower()}")
print(f"windows_source_reason={reason}")
print(f"canary_required={str(canary).lower()}")
print(f"canary_reason={canary_reason}")
print(f"windows_source_required={str(windows_source).lower()}")
print(f"windows_source_reason={windows_source_reason}")
if __name__ == "__main__":
+21 -4
View File
@@ -4,10 +4,7 @@ name: Bazel
# https://github.com/cerisier/toolchains_llvm_bootstrapped/blob/main/.github/workflows/ci.yaml
on:
pull_request: {}
push:
branches:
- main
workflow_call:
workflow_dispatch:
concurrency:
@@ -134,6 +131,10 @@ jobs:
path: ${{ steps.prepare_bazel.outputs.repository-cache-path }}
key: ${{ steps.prepare_bazel.outputs.repository-cache-key }}
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
test-windows-shard:
# Split the Windows Bazel test leg across separate Windows hosts. Jobs with
# BuildBuddy credentials use Linux RBE for build actions; test execution
@@ -239,6 +240,10 @@ jobs:
path: ${{ runner.temp }}/bazel-execution-logs
if-no-files-found: ignore
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
test-windows:
# Preserve the existing required-check surface while the real work happens
# in the sharded Windows jobs above.
@@ -333,6 +338,10 @@ jobs:
path: ${{ steps.prepare_bazel.outputs.repository-cache-path }}
key: ${{ steps.prepare_bazel.outputs.repository-cache-key }}
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
clippy:
timeout-minutes: 30
strategy:
@@ -433,6 +442,10 @@ jobs:
path: ${{ steps.prepare_bazel.outputs.repository-cache-path }}
key: ${{ steps.prepare_bazel.outputs.repository-cache-key }}
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
verify-release-build:
timeout-minutes: 30
strategy:
@@ -545,3 +558,7 @@ jobs:
with:
path: ${{ steps.prepare_bazel.outputs.repository-cache-path }}
key: ${{ steps.prepare_bazel.outputs.repository-cache-key }}
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
+19 -4
View File
@@ -1,7 +1,7 @@
name: blob-size-policy
on:
pull_request: {}
workflow_call:
jobs:
check:
@@ -14,13 +14,24 @@ jobs:
fetch-depth: 0
persist-credentials: false
- name: Determine PR comparison range
- name: Determine comparison range
id: range
shell: bash
run: |
set -euo pipefail
echo "base=${{ github.event.pull_request.base.sha }}" >> "$GITHUB_OUTPUT"
echo "head=${{ github.event.pull_request.head.sha }}" >> "$GITHUB_OUTPUT"
# PRs inspect the proposed diff; main pushes inspect only the commit
# range that just landed. Both paths feed the same blob-size checker.
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
base='${{ github.event.pull_request.base.sha }}'
head='${{ github.event.pull_request.head.sha }}'
else
base='${{ github.event.before }}'
head='${{ github.sha }}'
fi
echo "base=$base" >> "$GITHUB_OUTPUT"
echo "head=$head" >> "$GITHUB_OUTPUT"
- name: Check changed blob sizes
env:
@@ -32,3 +43,7 @@ jobs:
--head "$HEAD_SHA" \
--max-bytes 512000 \
--allowlist .github/blob-size-allowlist.txt
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
+79
View File
@@ -0,0 +1,79 @@
name: blocking-ci
# This is the single entrypoint for checks that block a PR merge. It also runs
# after pushes to main so the same check family stays grouped in the Actions UI.
on:
pull_request: {}
push:
branches: [main]
jobs:
# Keep reusable workflow calls alphabetized. The `required` job below is the
# version-controlled list that the main-branch ruleset should require.
bazel:
name: Bazel
uses: ./.github/workflows/bazel.yml
secrets: inherit
blob-size-policy:
name: Blob size policy
uses: ./.github/workflows/blob-size-policy.yml
secrets: inherit
cargo-deny:
name: cargo-deny
uses: ./.github/workflows/cargo-deny.yml
secrets: inherit
codespell:
name: Codespell
uses: ./.github/workflows/codespell.yml
secrets: inherit
repo-checks:
name: repo-checks
uses: ./.github/workflows/repo-checks.yml
secrets: inherit
rust-ci:
name: rust-ci
uses: ./.github/workflows/rust-ci.yml
secrets: inherit
sdk:
name: sdk
uses: ./.github/workflows/sdk.yml
secrets: inherit
required:
name: CI required
# Without `always()`, GitHub skips this job after a failed dependency and a
# required check can appear successful instead of reporting the failure.
if: ${{ always() }}
needs:
- bazel
- blob-size-policy
- cargo-deny
- codespell
- repo-checks
- rust-ci
- sdk
runs-on: ubuntu-24.04
steps:
# Keep the helper on the same revision as the caller and child workflows.
# CI workflow uploads are restricted, so this repository does not need a
# separate trusted-base checkout for the terminal policy step. Using the
# PR head also lets the introducing PR exercise a newly added helper.
#
# During the initial rollout, PR branches created before
# check_ci_results.py exists must rebase onto main before this gate can
# run.
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- name: Require successful dependencies
env:
NEEDS: ${{ toJSON(needs) }}
run: python3 .github/scripts/check_ci_results.py
+5 -4
View File
@@ -1,10 +1,7 @@
name: cargo-deny
on:
pull_request:
push:
branches:
- main
workflow_call:
# Cargo's libgit2 transport has been flaky when fetching git dependencies with
# nested submodules. Prefer the system git CLI across every Cargo invocation.
@@ -32,3 +29,7 @@ jobs:
with:
rust-version: 1.95.0
manifest-path: ./codex-rs/Cargo.toml
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
+5 -4
View File
@@ -3,10 +3,7 @@
name: Codespell
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_call:
permissions:
contents: read
@@ -28,3 +25,7 @@ jobs:
uses: codespell-project/actions-codespell@8f01853be192eb0f849a5c7d721450e7a467c579 # v2.2
with:
ignore_words_file: .codespellignore
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
+1
View File
@@ -78,6 +78,7 @@ jobs:
30. automations - Issues involving scheduled automation tasks or heartbeats.
31. pets - Issues involving pets avatars and animations.
32. agent - Fallback only for core agent loop or agent-related issues that do not fit app-server, connectivity, subagent, session, config, plan, computer-use, browser, memory, imagen, remote, performance, automations, or pets.
33. aws-bedrock - Issues involving the Amazon Bedrock model provider or Bedrock Mantle. Do not use for unrelated AWS services or generic AWS mentions.
Issue number: ${{ github.event.issue.number }}
+40
View File
@@ -0,0 +1,40 @@
name: postmerge-ci
# This is the single entrypoint for main-only CI that is intentionally outside
# the merge-blocking suite. It keeps the broader postmerge signal in one run.
on:
push:
branches: [main]
jobs:
# Keep reusable workflow calls alphabetized. Each child retains its own
# workflow_dispatch trigger so maintainers can rerun flaky suites directly.
rust-ci-full:
name: rust-ci-full
uses: ./.github/workflows/rust-ci-full.yml
secrets: inherit
v8-canary:
name: v8-canary
uses: ./.github/workflows/v8-canary.yml
secrets: inherit
results:
name: Postmerge CI results
needs:
- rust-ci-full
- v8-canary
if: ${{ always() }}
runs-on: ubuntu-24.04
steps:
# Postmerge runs use the pushed main commit, so this helper always comes
# from the same revision that defined the parent workflow.
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.sha }}
persist-credentials: false
- name: Require successful dependencies
env:
NEEDS: ${{ toJSON(needs) }}
run: python3 .github/scripts/check_ci_results.py
@@ -1,8 +1,7 @@
name: ci
name: repo-checks
on:
pull_request: {}
push: { branches: [main] }
workflow_call:
jobs:
build-test:
@@ -88,3 +87,7 @@ jobs:
- name: Prettier (run `pnpm run format:fix` to fix)
run: pnpm run format
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
+3 -1
View File
@@ -1,8 +1,10 @@
name: rust-ci-full
on:
workflow_call:
push:
branches:
- main
# Main pushes enter through postmerge-ci. Keep this opt-in branch trigger
# for developers who want the full suite before merging.
- "**full-ci**"
workflow_dispatch:
+21 -1
View File
@@ -1,6 +1,6 @@
name: rust-ci
on:
pull_request: {}
workflow_call:
workflow_dispatch:
# Cargo's libgit2 transport has been flaky when fetching git dependencies with
@@ -58,6 +58,10 @@ jobs:
echo "codex=$codex" >> "$GITHUB_OUTPUT"
echo "workflows=$workflows" >> "$GITHUB_OUTPUT"
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
# --- Fast Cargo-native PR checks -------------------------------------------
general:
name: Format / etc
@@ -83,6 +87,10 @@ jobs:
- name: Rust benchmark smoke test
run: just bench-smoke
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
cargo_shear:
name: cargo shear
runs-on: ubuntu-24.04
@@ -103,6 +111,10 @@ jobs:
- name: cargo shear
run: cargo shear --deny-warnings
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
argument_comment_lint_package:
name: Argument comment lint package
runs-on: ubuntu-24.04
@@ -154,6 +166,10 @@ jobs:
env:
RUST_MIN_STACK: "8388608" # 8 MiB
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
argument_comment_lint_prebuilt:
name: Argument comment lint - ${{ matrix.name }}
runs-on: ${{ matrix.runs_on || matrix.runner }}
@@ -205,6 +221,10 @@ jobs:
target: ${{ runner.os }}
buildbuddy-api-key: ${{ secrets.BUILDBUDDY_API_KEY }}
- name: Check for a clean worktree
if: always() && !cancelled() && steps.argument_comment_lint_gate.outputs.run == 'true'
uses: ./.github/actions/check-clean-worktree
# --- Gatherer job that you mark as the ONLY required status -----------------
results:
name: CI results (required)
+80 -1
View File
@@ -1,15 +1,56 @@
name: rust-release-zsh
on:
workflow_call:
push:
tags:
- "codex-zsh-v*.*.*"
env:
ZSH_COMMIT: 77045ef899e53b9598bebc5a41db93a548a40ca6
ZSH_PATCH: codex-rs/shell-escalation/patches/zsh-exec-wrapper.patch
concurrency:
group: ${{ github.workflow }}::${{ github.ref_name }}
cancel-in-progress: false
jobs:
metadata:
runs-on: ubuntu-latest
outputs:
release_tag: ${{ steps.release_tag.outputs.release_tag }}
steps:
- name: Validate release tag
id: release_tag
env:
RELEASE_TAG: ${{ github.ref_name }}
shell: bash
run: |
set -euo pipefail
if [[ ! "${RELEASE_TAG}" =~ ^codex-zsh-v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Tag ${RELEASE_TAG} does not match codex-zsh-vX.Y.Z." >&2
exit 1
fi
echo "release_tag=${RELEASE_TAG}" >> "${GITHUB_OUTPUT}"
- name: Ensure release does not exist
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ steps.release_tag.outputs.release_tag }}
shell: bash
run: |
set -euo pipefail
if gh release view "${RELEASE_TAG}" --repo "${GITHUB_REPOSITORY}" > /dev/null 2>&1; then
echo "Release ${RELEASE_TAG} already exists; publish changed artifacts under a new tag." >&2
exit 1
fi
linux:
name: Build zsh (Linux) - ${{ matrix.variant }} - ${{ matrix.target }}
needs: metadata
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
container:
@@ -62,6 +103,7 @@ jobs:
darwin:
name: Build zsh (macOS) - ${{ matrix.variant }} - ${{ matrix.target }}
needs: metadata
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
@@ -101,3 +143,40 @@ jobs:
with:
name: codex-zsh-${{ matrix.target }}
path: dist/zsh/${{ matrix.target }}/*
publish-release:
needs:
- metadata
- linux
- darwin
runs-on: ubuntu-latest
permissions:
contents: write
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: dist
- name: Create GitHub Release
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
with:
tag_name: ${{ needs.metadata.outputs.release_tag }}
name: ${{ needs.metadata.outputs.release_tag }}
files: dist/**
# Keep zsh artifact releases out of Codex's normal "latest release" channel.
prerelease: true
- name: Publish DotSlash manifest
uses: facebook/dotslash-publish-release@9c9ec027515c34db9282a09a25a9cab5880b2c52 # v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag: ${{ needs.metadata.outputs.release_tag }}
config: .github/dotslash-zsh-config.json
+26 -18
View File
@@ -14,6 +14,9 @@ on:
tags:
- "rust-v*.*.*"
env:
CODEX_ZSH_RELEASE_TAG: codex-zsh-v0.1.0
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true
@@ -354,6 +357,15 @@ jobs:
cp target/${{ matrix.target }}/release/codex-${{ matrix.target }}.dmg "$dest/codex-${{ matrix.target }}.dmg"
fi
- name: Download packaged zsh manifest
if: ${{ runner.os != 'macOS' }}
shell: bash
run: |
set -euo pipefail
curl -fsSL \
"https://github.com/${GITHUB_REPOSITORY}/releases/download/${CODEX_ZSH_RELEASE_TAG}/codex-zsh" \
-o "${RUNNER_TEMP}/codex-zsh"
- name: Build Codex package archive
if: ${{ runner.os != 'macOS' }}
shell: bash
@@ -366,7 +378,8 @@ jobs:
--target "$TARGET" \
--bundle "$BUNDLE" \
--entrypoint-dir "target/${TARGET}/release" \
--archive-dir "dist/${TARGET}"
--archive-dir "dist/${TARGET}" \
--zsh-manifest "${RUNNER_TEMP}/codex-zsh"
- name: Build Python runtime wheel
if: ${{ matrix.bundle == 'primary' && runner.os != 'macOS' }}
@@ -697,6 +710,14 @@ jobs:
cp "target/${{ matrix.target }}/release/${binary}" "$dest/${binary}-${{ matrix.target }}"
done
- name: Download packaged zsh manifest
shell: bash
run: |
set -euo pipefail
curl -fsSL \
"https://github.com/${GITHUB_REPOSITORY}/releases/download/${CODEX_ZSH_RELEASE_TAG}/codex-zsh" \
-o "${RUNNER_TEMP}/codex-zsh"
- name: Build Codex package archive
shell: bash
env:
@@ -708,7 +729,8 @@ jobs:
--target "$TARGET" \
--bundle "$BUNDLE" \
--entrypoint-dir "target/${TARGET}/release" \
--archive-dir "dist/${TARGET}"
--archive-dir "dist/${TARGET}" \
--zsh-manifest "${RUNNER_TEMP}/codex-zsh"
- name: Build Python runtime wheel
if: ${{ matrix.bundle == 'primary' }}
@@ -1043,11 +1065,6 @@ jobs:
with:
publish: true
zsh-release-assets:
name: zsh release assets
needs: tag-check
uses: ./.github/workflows/rust-release-zsh.yml
release:
needs:
- tag-check
@@ -1055,7 +1072,6 @@ jobs:
- finalize-macos
- build-windows
- argument-comment-lint-release-assets
- zsh-release-assets
if: >-
${{
always() &&
@@ -1063,8 +1079,7 @@ jobs:
needs.build.result == 'success' &&
needs.finalize-macos.result == 'success' &&
needs.build-windows.result == 'success' &&
needs.argument-comment-lint-release-assets.result == 'success' &&
needs.zsh-release-assets.result == 'success'
needs.argument-comment-lint-release-assets.result == 'success'
}}
name: release
runs-on: ubuntu-latest
@@ -1113,7 +1128,7 @@ jobs:
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: dist
pattern: "{*-symbols,argument-comment-lint-*,codex-zsh-*,python-runtime-wheel-*}"
pattern: "{*-symbols,argument-comment-lint-*,python-runtime-wheel-*}"
- name: List
run: ls -R dist/
@@ -1236,13 +1251,6 @@ jobs:
tag: ${{ github.ref_name }}
config: .github/dotslash-config.json
- uses: facebook/dotslash-publish-release@9c9ec027515c34db9282a09a25a9cab5880b2c52 # v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag: ${{ github.ref_name }}
config: .github/dotslash-zsh-config.json
- uses: facebook/dotslash-publish-release@9c9ec027515c34db9282a09a25a9cab5880b2c52 # v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+9 -3
View File
@@ -1,9 +1,7 @@
name: sdk
on:
push:
branches: [main]
pull_request: {}
workflow_call:
jobs:
python-sdk:
@@ -41,6 +39,10 @@ jobs:
/tmp/uv/bin/uv run --frozen --no-sync pytest
'
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
sdks:
runs-on:
group: ${{ github.event.repository.name }}-runners
@@ -161,3 +163,7 @@ jobs:
path: |
~/.cache/bazel-repo-cache
key: bazel-cache-x86_64-unknown-linux-gnu-${{ hashFiles('MODULE.bazel', 'codex-rs/Cargo.lock', 'codex-rs/Cargo.toml') }}
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
+27 -39
View File
@@ -1,44 +1,12 @@
name: v8-canary
# Do not use trigger-level path filters here. This workflow is also called by
# postmerge-ci, and GitHub cannot share a path filter between pull_request and
# workflow_call. v8_canary_changes.py is the single source of truth instead;
# unrelated events run only the cheap metadata job below.
on:
pull_request:
paths:
- ".bazelrc"
- ".github/actions/setup-bazel-ci/**"
- ".github/scripts/run_bazel_with_buildbuddy.py"
- ".github/scripts/rusty_v8_bazel.py"
- ".github/scripts/rusty_v8_module_bazel.py"
- ".github/scripts/v8_canary_changes.py"
- ".github/workflows/rusty-v8-release.yml"
- ".github/workflows/v8-canary.yml"
- "MODULE.bazel"
- "MODULE.bazel.lock"
- "codex-rs/Cargo.toml"
- "patches/BUILD.bazel"
- "patches/llvm_*.patch"
- "patches/rules_cc_*.patch"
- "patches/v8_*.patch"
- "third_party/v8/**"
push:
branches:
- main
paths:
- ".bazelrc"
- ".github/actions/setup-bazel-ci/**"
- ".github/scripts/run_bazel_with_buildbuddy.py"
- ".github/scripts/rusty_v8_bazel.py"
- ".github/scripts/rusty_v8_module_bazel.py"
- ".github/scripts/v8_canary_changes.py"
- ".github/workflows/rusty-v8-release.yml"
- ".github/workflows/v8-canary.yml"
- "MODULE.bazel"
- "MODULE.bazel.lock"
- "codex-rs/Cargo.toml"
- "patches/BUILD.bazel"
- "patches/llvm_*.patch"
- "patches/rules_cc_*.patch"
- "patches/v8_*.patch"
- "third_party/v8/**"
workflow_call:
pull_request: {}
workflow_dispatch:
# Cargo's libgit2 transport has been flaky when fetching git dependencies with
@@ -54,6 +22,10 @@ jobs:
metadata:
runs-on: ubuntu-latest
outputs:
# A stale PR head can contain the old detector, which does not emit this
# output. Missing must mean "run" so older branches cannot silently skip
# the expensive V8 coverage while reporting success.
canary_required: ${{ steps.changes.outputs.canary_required || 'true' }}
v8_version: ${{ steps.v8_version.outputs.version }}
windows_source_required: ${{ steps.changes.outputs.windows_source_required }}
@@ -77,7 +49,7 @@ jobs:
version="$(python3 .github/scripts/rusty_v8_bazel.py resolved-v8-crate-version)"
echo "version=${version}" >> "$GITHUB_OUTPUT"
- name: Detect whether Windows source artifacts need rebuilding
- name: Detect V8 canary changes
id: changes
env:
BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }}
@@ -87,6 +59,8 @@ jobs:
run: |
set -euo pipefail
# Manual runs have no meaningful before/after range. Force every V8
# variant so workflow_dispatch remains a reliable retry path.
if [[ "${EVENT_NAME}" == "workflow_dispatch" ]]; then
output="$(python3 .github/scripts/v8_canary_changes.py --force)"
else
@@ -97,9 +71,15 @@ jobs:
echo "${output}"
echo "${output}" >> "${GITHUB_OUTPUT}"
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
build:
name: Build ${{ matrix.variant }} ${{ matrix.target }}
needs: metadata
# Metadata always runs; only relevant changes pay for the large matrix.
if: ${{ needs.metadata.outputs.canary_required == 'true' }}
runs-on: ${{ matrix.runner }}
permissions:
contents: read
@@ -322,6 +302,10 @@ jobs:
name: v8-canary-${{ needs.metadata.outputs.v8_version }}-${{ matrix.variant }}-${{ matrix.target }}
path: dist/${{ matrix.target }}/*
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
build-windows-source:
name: Build ptrcomp-sandbox ${{ matrix.target }} from source
needs: metadata
@@ -459,3 +443,7 @@ jobs:
with:
name: v8-canary-${{ needs.metadata.outputs.v8_version }}-ptrcomp-sandbox-${{ matrix.target }}
path: dist/${{ matrix.target }}/*
- name: Check for a clean worktree
if: always() && !cancelled()
uses: ./.github/actions/check-clean-worktree
+2
View File
@@ -60,6 +60,8 @@ yarn-error.log*
# ci
.vercel/
.netlify/
/.tmp/sdk-ci/
/upstream-rusty-v8/
# patches
apply_patch/
+18 -5
View File
@@ -35,9 +35,8 @@ In the codex-rs folder where the rust code lives:
- When working with MCP tool calls, prefer using `codex-rs/codex-mcp/src/mcp_connection_manager.rs` to handle mutation of tools and tool calls. Aim to minimize the footprint of changes and leverage existing abstractions rather than plumbing code through multiple levels of function calls.
- Do not call `reset_client_session` unnecessarily; let the incremental check logic decide whether to reuse the previous request.
- If you change Rust dependencies (`Cargo.toml` or `Cargo.lock`), run `just bazel-lock-update` from the
repo root to refresh `MODULE.bazel.lock`, and include that lockfile update in the same change.
- After dependency changes, run `just bazel-lock-check` from the repo root so lockfile drift is caught
locally before CI.
repo root to refresh `MODULE.bazel.lock`, and include that lockfile update in the same change. CI
verifies lockfile drift.
- Bazel does not automatically make source-tree files available to compile-time Rust file access. If
you add `include_str!`, `include_bytes!`, `sqlx::migrate!`, or similar build-time file or
directory reads, update the crate's `BUILD.bazel` (`compile_data`, `build_script_data`, or test
@@ -220,10 +219,13 @@ Use `just bench-smoke` to dry-run the benchmark for a single iteration to ensure
- Under Bazel, binaries and resources may live under runfiles; use `codex_utils_cargo_bin::cargo_bin` to resolve absolute paths that remain stable after `chdir`.
- When locating fixture files or test resources under Bazel, avoid `env!("CARGO_MANIFEST_DIR")`. Prefer `codex_utils_cargo_bin::find_resource!` so paths resolve correctly under both Cargo and Bazel runfiles.
### Integration tests (core)
### Integration tests
#### codex_core integration testing
- Prefer the utilities in `core_test_support::responses` when writing end-to-end Codex tests.
- Use `TestCodexBuilder::build_with_auto_env()` by default to ensure that new tests work with
foreign app/exec OSes. See $remote-tests for details.
- All `mount_sse*` helpers return a `ResponseMock`; hold onto it so you can assert against outbound `/responses` POST bodies.
- Use `ResponseMock::single_request()` when a test should only issue one POST, or `ResponseMock::requests()` to inspect every captured `ResponsesRequest`.
- `ResponsesRequest` exposes helpers (`body_json`, `input`, `function_call_output`, `custom_tool_call_output`, `call_output`, `header`, `path`, `query_param`) so assertions can target structured payloads instead of manual JSON digging.
@@ -247,6 +249,14 @@ Use `just bench-smoke` to dry-run the benchmark for a single iteration to ensure
// assert using request.function_call_output(call_id) or request.json_body() or other helpers.
```
#### app-server integration testing
- Tests should exercise app-server's public JSON-RPC API.
- Use similar server mocking as for core integration tests.
- Use `TestAppServer::new_with_auto_env()` and `TestAppServer::send_thread_start_request_with_auto_env()`
by default to ensure that new tests work with foreign app/exec OSes. See `$remote-tests` for
details.
## App-server API Development Best Practices
These guidelines apply to app-server protocol work in `codex-rs`, especially:
@@ -307,3 +317,6 @@ closest `pyproject.toml`'s `requires-python` field to see what minimum runtime v
## Platform Support
Tests and features must support Linux, macOS and Windows unless feature is explicitly OS-specific.
Codex supports running connected app-server and exec-server on different operating systems. See the
`$remote-tests` skill for details about integration testing these configurations.
+1 -1
View File
@@ -309,7 +309,7 @@ crate.annotation(
# Build scripts compile in Bazel's exec configuration, so target-specific
# optional build deps are otherwise dropped for the musl release platforms.
build_script_deps = [
"@crates//:openssl-src-300.5.5+3.5.5",
"@crates//:openssl-src-300.6.1+3.6.3",
],
build_script_env = {
"OPENSSL_DIR": "$(execpath @openssl//:gen_dir)",
+6 -6
View File
@@ -986,8 +986,8 @@
"git+https://github.com/juberti-oai/rust-sdks.git?rev=e2d1d1d230c6fc9df171ccb181423f957bb3c1f0#e2d1d1d230c6fc9df171ccb181423f957bb3c1f0_webrtc-sys-build": "{\"dependencies\":[{\"name\":\"anyhow\"},{\"name\":\"fs2\"},{\"name\":\"regex\"},{\"default_features\":false,\"features\":[\"rustls-tls-native-roots\",\"blocking\"],\"name\":\"reqwest\",\"optional\":false},{\"name\":\"scratch\"},{\"name\":\"semver\"},{\"name\":\"zip\"}],\"features\":{},\"strip_prefix\":\"webrtc-sys/build\"}",
"git+https://github.com/nornagon/crossterm?rev=87db8bfa6dc99427fd3b071681b07fc31c6ce995#87db8bfa6dc99427fd3b071681b07fc31c6ce995_crossterm": "{\"dependencies\":[{\"default_features\":true,\"features\":[],\"name\":\"bitflags\",\"optional\":false},{\"default_features\":false,\"features\":[],\"name\":\"futures-core\",\"optional\":true},{\"name\":\"parking_lot\"},{\"default_features\":true,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"filedescriptor\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":false,\"features\":[],\"name\":\"libc\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[\"os-poll\"],\"name\":\"mio\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":false,\"features\":[\"std\",\"stdio\",\"termios\"],\"name\":\"rustix\",\"optional\":false,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[],\"name\":\"signal-hook\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[\"support-v1_0\"],\"name\":\"signal-hook-mio\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[],\"name\":\"crossterm_winapi\",\"optional\":true,\"target\":\"cfg(windows)\"},{\"default_features\":true,\"features\":[\"winuser\",\"winerror\"],\"name\":\"winapi\",\"optional\":true,\"target\":\"cfg(windows)\"}],\"features\":{\"bracketed-paste\":[],\"default\":[\"bracketed-paste\",\"windows\",\"events\"],\"event-stream\":[\"dep:futures-core\",\"events\"],\"events\":[\"dep:mio\",\"dep:signal-hook\",\"dep:signal-hook-mio\"],\"serde\":[\"dep:serde\",\"bitflags/serde\"],\"use-dev-tty\":[\"filedescriptor\",\"rustix/process\"],\"windows\":[\"dep:winapi\",\"dep:crossterm_winapi\"]},\"strip_prefix\":\"\"}",
"git+https://github.com/nornagon/ratatui?rev=9b2ad1298408c45918ee9f8241a6f95498cdbed2#9b2ad1298408c45918ee9f8241a6f95498cdbed2_ratatui": "{\"dependencies\":[{\"name\":\"bitflags\"},{\"name\":\"cassowary\"},{\"name\":\"compact_str\"},{\"default_features\":true,\"features\":[],\"name\":\"crossterm\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"document-features\",\"optional\":true},{\"name\":\"indoc\"},{\"name\":\"instability\"},{\"name\":\"itertools\"},{\"name\":\"lru\"},{\"default_features\":true,\"features\":[],\"name\":\"palette\",\"optional\":true},{\"name\":\"paste\"},{\"default_features\":true,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true},{\"default_features\":true,\"features\":[\"derive\"],\"name\":\"strum\",\"optional\":false},{\"default_features\":true,\"features\":[],\"name\":\"termwiz\",\"optional\":true},{\"default_features\":true,\"features\":[\"local-offset\"],\"name\":\"time\",\"optional\":true},{\"name\":\"unicode-segmentation\"},{\"name\":\"unicode-truncate\"},{\"name\":\"unicode-width\"},{\"default_features\":true,\"features\":[],\"name\":\"termion\",\"optional\":true,\"target\":\"cfg(not(windows))\"}],\"features\":{\"all-widgets\":[\"widget-calendar\"],\"crossterm\":[\"dep:crossterm\"],\"default\":[\"crossterm\",\"underline-color\"],\"macros\":[],\"palette\":[\"dep:palette\"],\"scrolling-regions\":[],\"serde\":[\"dep:serde\",\"bitflags/serde\",\"compact_str/serde\"],\"termion\":[\"dep:termion\"],\"termwiz\":[\"dep:termwiz\"],\"underline-color\":[\"dep:crossterm\"],\"unstable\":[\"unstable-rendered-line-info\",\"unstable-widget-ref\",\"unstable-backend-writer\"],\"unstable-backend-writer\":[],\"unstable-rendered-line-info\":[],\"unstable-widget-ref\":[],\"widget-calendar\":[\"dep:time\"]},\"strip_prefix\":\"\"}",
"git+https://github.com/openai-oss-forks/tokio-tungstenite?rev=e5e64b86722c5453c4038131c3193faa49a648ad#e5e64b86722c5453c4038131c3193faa49a648ad_tokio-tungstenite": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"sink\",\"std\"],\"name\":\"futures-util\",\"optional\":false},{\"name\":\"log\"},{\"default_features\":true,\"features\":[],\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\"},{\"default_features\":false,\"features\":[],\"name\":\"rustls\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-native-certs\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-pki-types\",\"optional\":true},{\"default_features\":false,\"features\":[\"io-util\"],\"name\":\"tokio\",\"optional\":false},{\"default_features\":true,\"features\":[],\"name\":\"tokio-native-tls\",\"optional\":true},{\"default_features\":false,\"features\":[],\"name\":\"tokio-rustls\",\"optional\":true},{\"default_features\":false,\"features\":[],\"name\":\"tungstenite\",\"optional\":false},{\"default_features\":true,\"features\":[],\"name\":\"webpki-roots\",\"optional\":true}],\"features\":{\"__rustls-tls\":[\"rustls\",\"rustls-pki-types\",\"tokio-rustls\",\"stream\",\"tungstenite/__rustls-tls\",\"handshake\"],\"connect\":[\"stream\",\"tokio/net\",\"tokio/time\",\"handshake\"],\"default\":[\"connect\",\"handshake\"],\"handshake\":[\"tungstenite/handshake\"],\"native-tls\":[\"native-tls-crate\",\"tokio-native-tls\",\"stream\",\"tungstenite/native-tls\",\"handshake\"],\"native-tls-vendored\":[\"native-tls\",\"native-tls-crate/vendored\",\"tungstenite/native-tls-vendored\"],\"proxy\":[\"tungstenite/proxy\",\"tokio/net\",\"handshake\"],\"rustls-tls-native-roots\":[\"__rustls-tls\",\"rustls-native-certs\"],\"rustls-tls-webpki-roots\":[\"__rustls-tls\",\"webpki-roots\"],\"stream\":[],\"url\":[\"tungstenite/url\"]},\"strip_prefix\":\"\"}",
"git+https://github.com/openai-oss-forks/tungstenite-rs?rev=9200079d3b54a1ff51072e24d81fd354f085156f#9200079d3b54a1ff51072e24d81fd354f085156f_tungstenite": "{\"dependencies\":[{\"name\":\"bytes\"},{\"default_features\":true,\"features\":[],\"name\":\"data-encoding\",\"optional\":true},{\"default_features\":false,\"features\":[\"zlib\"],\"name\":\"flate2\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"headers\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"http\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"httparse\",\"optional\":true},{\"name\":\"log\"},{\"default_features\":true,\"features\":[],\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\"},{\"name\":\"rand\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"rustls\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-native-certs\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-pki-types\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"sha1\",\"optional\":true},{\"name\":\"thiserror\"},{\"default_features\":true,\"features\":[],\"name\":\"url\",\"optional\":true},{\"name\":\"utf-8\"},{\"default_features\":true,\"features\":[],\"name\":\"webpki-roots\",\"optional\":true}],\"features\":{\"__rustls-tls\":[\"rustls\",\"rustls-pki-types\"],\"default\":[\"handshake\"],\"deflate\":[\"headers\",\"flate2\"],\"handshake\":[\"data-encoding\",\"headers\",\"httparse\",\"sha1\"],\"headers\":[\"http\",\"dep:headers\"],\"native-tls\":[\"native-tls-crate\"],\"native-tls-vendored\":[\"native-tls\",\"native-tls-crate/vendored\"],\"proxy\":[\"handshake\"],\"rustls-tls-native-roots\":[\"__rustls-tls\",\"rustls-native-certs\"],\"rustls-tls-webpki-roots\":[\"__rustls-tls\",\"webpki-roots\"],\"url\":[\"dep:url\"]},\"strip_prefix\":\"\"}",
"git+https://github.com/openai-oss-forks/tokio-tungstenite?rev=0e5b2d73aa18dd9f0a50ee9ff199d5aef7594186#0e5b2d73aa18dd9f0a50ee9ff199d5aef7594186_tokio-tungstenite": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"sink\",\"std\"],\"name\":\"futures-util\",\"optional\":false},{\"name\":\"log\"},{\"default_features\":true,\"features\":[],\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\"},{\"default_features\":false,\"features\":[],\"name\":\"rustls\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-native-certs\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-pki-types\",\"optional\":true},{\"default_features\":false,\"features\":[\"io-util\"],\"name\":\"tokio\",\"optional\":false},{\"default_features\":true,\"features\":[],\"name\":\"tokio-native-tls\",\"optional\":true},{\"default_features\":false,\"features\":[],\"name\":\"tokio-rustls\",\"optional\":true},{\"default_features\":false,\"features\":[],\"name\":\"tungstenite\",\"optional\":false},{\"default_features\":true,\"features\":[],\"name\":\"webpki-roots\",\"optional\":true}],\"features\":{\"__rustls-tls\":[\"rustls\",\"rustls-pki-types\",\"tokio-rustls\",\"stream\",\"tungstenite/__rustls-tls\",\"handshake\"],\"connect\":[\"stream\",\"tokio/net\",\"tokio/time\",\"handshake\"],\"default\":[\"connect\",\"handshake\"],\"handshake\":[\"tungstenite/handshake\"],\"native-tls\":[\"native-tls-crate\",\"tokio-native-tls\",\"stream\",\"tungstenite/native-tls\",\"handshake\"],\"native-tls-vendored\":[\"native-tls\",\"native-tls-crate/vendored\",\"tungstenite/native-tls-vendored\"],\"proxy\":[\"tungstenite/proxy\",\"tokio/net\",\"handshake\"],\"rustls-tls-native-roots\":[\"__rustls-tls\",\"rustls-native-certs\"],\"rustls-tls-webpki-roots\":[\"__rustls-tls\",\"webpki-roots\"],\"stream\":[],\"url\":[\"tungstenite/url\"]},\"strip_prefix\":\"\"}",
"git+https://github.com/openai-oss-forks/tungstenite-rs?rev=4fffad30fe373adbdcffab9545e9e9bf4f2fc19f#4fffad30fe373adbdcffab9545e9e9bf4f2fc19f_tungstenite": "{\"dependencies\":[{\"name\":\"bytes\"},{\"default_features\":true,\"features\":[],\"name\":\"data-encoding\",\"optional\":true},{\"default_features\":false,\"features\":[\"zlib-rs\"],\"name\":\"flate2\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"headers\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"http\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"httparse\",\"optional\":true},{\"name\":\"log\"},{\"default_features\":true,\"features\":[],\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\"},{\"name\":\"rand\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"rustls\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-native-certs\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-pki-types\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"sha1\",\"optional\":true},{\"name\":\"thiserror\"},{\"default_features\":true,\"features\":[],\"name\":\"url\",\"optional\":true},{\"name\":\"utf-8\"},{\"default_features\":true,\"features\":[],\"name\":\"webpki-roots\",\"optional\":true}],\"features\":{\"__rustls-tls\":[\"rustls\",\"rustls-pki-types\"],\"default\":[\"handshake\"],\"deflate\":[\"headers\",\"flate2\"],\"handshake\":[\"data-encoding\",\"headers\",\"httparse\",\"sha1\"],\"headers\":[\"http\",\"dep:headers\"],\"native-tls\":[\"native-tls-crate\"],\"native-tls-vendored\":[\"native-tls\",\"native-tls-crate/vendored\"],\"proxy\":[\"handshake\"],\"rustls-tls-native-roots\":[\"__rustls-tls\",\"rustls-native-certs\"],\"rustls-tls-webpki-roots\":[\"__rustls-tls\",\"webpki-roots\"],\"url\":[\"dep:url\"]},\"strip_prefix\":\"\"}",
"git+https://github.com/rust-lang/rust-clippy?rev=20ce69b9a63bcd2756cd906fe0964d1e901e042a#20ce69b9a63bcd2756cd906fe0964d1e901e042a_clippy_utils": "{\"dependencies\":[{\"default_features\":false,\"features\":[],\"name\":\"arrayvec\",\"optional\":false},{\"name\":\"itertools\"},{\"name\":\"rustc_apfloat\"},{\"default_features\":true,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":false}],\"features\":{},\"strip_prefix\":\"clippy_utils\"}",
"git2_0.20.4": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2.1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^4.4.13\"},{\"name\":\"libc\",\"req\":\"^0.2\"},{\"name\":\"libgit2-sys\",\"req\":\"^0.18.3\"},{\"name\":\"log\",\"req\":\"^0.4.8\"},{\"name\":\"openssl-probe\",\"optional\":true,\"req\":\"^0.1\",\"target\":\"cfg(all(unix, not(target_os = \\\"macos\\\")))\"},{\"name\":\"openssl-sys\",\"optional\":true,\"req\":\"^0.9.45\",\"target\":\"cfg(all(unix, not(target_os = \\\"macos\\\")))\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.1.0\"},{\"features\":[\"formatting\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.37\"},{\"name\":\"url\",\"req\":\"^2.5.4\"}],\"features\":{\"default\":[\"ssh\",\"https\"],\"https\":[\"libgit2-sys/https\",\"openssl-sys\",\"openssl-probe\"],\"ssh\":[\"libgit2-sys/ssh\"],\"unstable\":[],\"vendored-libgit2\":[\"libgit2-sys/vendored\"],\"vendored-openssl\":[\"openssl-sys/vendored\",\"libgit2-sys/vendored-openssl\"],\"zlib-ng-compat\":[\"libgit2-sys/zlib-ng-compat\"]}}",
"gix-actor_0.40.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\",\"unicode\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-date\",\"req\":\"^0.15.0\"},{\"name\":\"gix-error\",\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"features\":[\"simd\"],\"name\":\"winnow\",\"req\":\"^0.7.14\"}],\"features\":{\"serde\":[\"dep:serde\",\"bstr/serde\",\"gix-date/serde\"]}}",
@@ -1197,7 +1197,6 @@
"libredox_0.1.14": "{\"dependencies\":[{\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"ioslice\",\"optional\":true,\"req\":\"^0.6\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"plain\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"redox_syscall\",\"optional\":true,\"req\":\"^0.7\"}],\"features\":{\"base\":[\"libc\"],\"call\":[\"base\"],\"default\":[\"base\",\"call\",\"std\",\"redox_syscall\",\"protocol\"],\"mkns\":[\"ioslice\"],\"protocol\":[\"plain\",\"bitflags\",\"redox_syscall\"],\"std\":[\"base\"]}}",
"libsqlite3-sys_0.37.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"runtime\"],\"kind\":\"build\",\"name\":\"bindgen\",\"optional\":true,\"req\":\"^0.72\"},{\"kind\":\"build\",\"name\":\"cc\",\"optional\":true,\"req\":\"^1.2.27\"},{\"name\":\"openssl-sys\",\"optional\":true,\"req\":\"^0.9.103\"},{\"kind\":\"build\",\"name\":\"pkg-config\",\"optional\":true,\"req\":\"^0.3.19\"},{\"kind\":\"build\",\"name\":\"prettyplease\",\"optional\":true,\"req\":\"^0.2.20\"},{\"default_features\":false,\"kind\":\"build\",\"name\":\"quote\",\"optional\":true,\"req\":\"^1.0.36\"},{\"features\":[\"full\",\"extra-traits\",\"visit-mut\"],\"kind\":\"build\",\"name\":\"syn\",\"optional\":true,\"req\":\"^2.0.89\"},{\"kind\":\"build\",\"name\":\"vcpkg\",\"optional\":true,\"req\":\"^0.2.15\"}],\"features\":{\"buildtime_bindgen\":[\"bindgen\",\"pkg-config\",\"vcpkg\"],\"bundled\":[\"cc\",\"bundled_bindings\"],\"bundled-sqlcipher\":[\"bundled\"],\"bundled-sqlcipher-vendored-openssl\":[\"bundled-sqlcipher\",\"openssl-sys/vendored\"],\"bundled-windows\":[\"cc\",\"bundled_bindings\"],\"bundled_bindings\":[],\"column_metadata\":[],\"default\":[\"min_sqlite_version_3_34_1\"],\"in_gecko\":[],\"loadable_extension\":[\"prettyplease\",\"quote\",\"syn\"],\"min_sqlite_version_3_34_1\":[\"pkg-config\",\"vcpkg\"],\"preupdate_hook\":[\"buildtime_bindgen\"],\"session\":[\"preupdate_hook\",\"buildtime_bindgen\"],\"sqlcipher\":[],\"unlock_notify\":[],\"wasm32-wasi-vfs\":[],\"with-asan\":[]}}",
"libssh2-sys_0.3.1": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1.0.25\"},{\"name\":\"libc\",\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"libc\"],\"name\":\"libz-sys\",\"req\":\"^1.1.0\"},{\"name\":\"openssl-sys\",\"req\":\"^0.9.35\",\"target\":\"cfg(unix)\"},{\"name\":\"openssl-sys\",\"optional\":true,\"req\":\"^0.9.35\",\"target\":\"cfg(windows)\"},{\"kind\":\"build\",\"name\":\"pkg-config\",\"req\":\"^0.3.11\"},{\"kind\":\"build\",\"name\":\"vcpkg\",\"req\":\"^0.2\",\"target\":\"cfg(target_env = \\\"msvc\\\")\"}],\"features\":{\"openssl-on-win32\":[\"openssl-sys\"],\"vendored-openssl\":[\"openssl-sys/vendored\"],\"zlib-ng-compat\":[\"libz-sys/zlib-ng\"]}}",
"libz-sys_1.1.23": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1.0.98\"},{\"kind\":\"build\",\"name\":\"cmake\",\"optional\":true,\"req\":\"^0.1.50\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.43\"},{\"kind\":\"build\",\"name\":\"pkg-config\",\"req\":\"^0.3.9\"},{\"kind\":\"build\",\"name\":\"vcpkg\",\"req\":\"^0.2.11\"}],\"features\":{\"asm\":[],\"default\":[\"libc\",\"stock-zlib\"],\"static\":[],\"stock-zlib\":[],\"zlib-ng\":[\"libc\",\"cmake\"],\"zlib-ng-no-cmake-experimental-community-maintained\":[\"libc\"]}}",
"libz-sys_1.1.25": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1.0.98\"},{\"kind\":\"build\",\"name\":\"cmake\",\"optional\":true,\"req\":\"^0.1.50\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.43\"},{\"kind\":\"build\",\"name\":\"pkg-config\",\"req\":\"^0.3.9\"},{\"kind\":\"build\",\"name\":\"vcpkg\",\"req\":\"^0.2.11\"}],\"features\":{\"asm\":[],\"default\":[\"libc\",\"stock-zlib\"],\"static\":[],\"stock-zlib\":[],\"zlib-ng\":[\"libc\",\"cmake\"],\"zlib-ng-no-cmake-experimental-community-maintained\":[\"libc\"]}}",
"link-cplusplus_1.0.12": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1\"}],\"features\":{\"default\":[],\"libc++\":[],\"libcxx\":[\"libc++\"],\"libstdc++\":[],\"libstdcxx\":[\"libstdc++\"],\"nothing\":[]}}",
"link-section_0.17.2": "{\"dependencies\":[{\"features\":[\"link_section\"],\"name\":\"linktime-proc-macro\",\"optional\":true,\"req\":\"^0.1.0\"},{\"kind\":\"dev\",\"name\":\"macrotest\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2\"}],\"features\":{\"default\":[\"proc_macro\",\"std\"],\"proc_macro\":[\"dep:linktime-proc-macro\"],\"std\":[]}}",
@@ -1294,7 +1293,7 @@
"openssl-macros_0.1.1": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{}}",
"openssl-probe_0.1.6": "{\"dependencies\":[],\"features\":{}}",
"openssl-probe_0.2.1": "{\"dependencies\":[],\"features\":{}}",
"openssl-src_300.5.5+3.5.5": "{\"dependencies\":[{\"name\":\"cc\",\"req\":\"^1.0.79\"}],\"features\":{\"camellia\":[],\"default\":[],\"force-engine\":[],\"idea\":[],\"ktls\":[],\"legacy\":[],\"no-dso\":[],\"seed\":[],\"ssl3\":[],\"weak-crypto\":[]}}",
"openssl-src_300.6.1+3.6.3": "{\"dependencies\":[{\"name\":\"cc\",\"req\":\"^1.0.79\"}],\"features\":{\"camellia\":[],\"default\":[],\"force-engine\":[],\"idea\":[],\"ktls\":[],\"legacy\":[],\"no-dso\":[],\"seed\":[],\"ssl3\":[],\"weak-crypto\":[]}}",
"openssl-sys_0.9.111": "{\"dependencies\":[{\"features\":[\"ssl\",\"bindgen\"],\"name\":\"aws-lc-fips-sys\",\"optional\":true,\"req\":\"^0.13\"},{\"features\":[\"ssl\"],\"name\":\"aws-lc-sys\",\"optional\":true,\"req\":\"^0.27\"},{\"features\":[\"experimental\"],\"kind\":\"build\",\"name\":\"bindgen\",\"optional\":true,\"req\":\"^0.72.0\"},{\"name\":\"bssl-sys\",\"optional\":true,\"req\":\"^0.1.0\"},{\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1.0.61\"},{\"name\":\"libc\",\"req\":\"^0.2\"},{\"features\":[\"legacy\"],\"kind\":\"build\",\"name\":\"openssl-src\",\"optional\":true,\"req\":\"^300.2.0\"},{\"kind\":\"build\",\"name\":\"pkg-config\",\"req\":\"^0.3.9\"},{\"kind\":\"build\",\"name\":\"vcpkg\",\"req\":\"^0.2.8\"}],\"features\":{\"aws-lc\":[\"dep:aws-lc-sys\"],\"aws-lc-fips\":[\"dep:aws-lc-fips-sys\"],\"unstable_boringssl\":[\"bssl-sys\"],\"vendored\":[\"openssl-src\"]}}",
"openssl-sys_0.9.112": "{\"dependencies\":[{\"features\":[\"ssl\",\"bindgen\"],\"name\":\"aws-lc-fips-sys\",\"optional\":true,\"req\":\"^0.13\"},{\"features\":[\"ssl\"],\"name\":\"aws-lc-sys\",\"optional\":true,\"req\":\"^0.38\"},{\"features\":[\"experimental\"],\"kind\":\"build\",\"name\":\"bindgen\",\"optional\":true,\"req\":\"^0.72.0\"},{\"name\":\"bssl-sys\",\"optional\":true,\"req\":\"^0.1.0\"},{\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1.0.61\"},{\"name\":\"libc\",\"req\":\"^0.2\"},{\"features\":[\"legacy\"],\"kind\":\"build\",\"name\":\"openssl-src\",\"optional\":true,\"req\":\"^300.2.0\"},{\"kind\":\"build\",\"name\":\"pkg-config\",\"req\":\"^0.3.9\"},{\"kind\":\"build\",\"name\":\"vcpkg\",\"req\":\"^0.2.8\"}],\"features\":{\"aws-lc\":[\"dep:aws-lc-sys\"],\"aws-lc-fips\":[\"dep:aws-lc-fips-sys\"],\"unstable_boringssl\":[\"bssl-sys\"],\"vendored\":[\"openssl-src\"]}}",
"openssl_0.10.75": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2.2.1\"},{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"name\":\"ffi\",\"package\":\"openssl-sys\",\"req\":\"^0.9.111\"},{\"name\":\"foreign-types\",\"req\":\"^0.3.1\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4\"},{\"name\":\"libc\",\"req\":\"^0.2\"},{\"name\":\"once_cell\",\"req\":\"^1.5.2\"},{\"name\":\"openssl-macros\",\"req\":\"^0.1.1\"}],\"features\":{\"aws-lc\":[\"ffi/aws-lc\"],\"aws-lc-fips\":[\"ffi/aws-lc-fips\"],\"bindgen\":[\"ffi/bindgen\"],\"default\":[],\"unstable_boringssl\":[\"ffi/unstable_boringssl\"],\"v101\":[],\"v102\":[],\"v110\":[],\"v111\":[],\"vendored\":[\"ffi/vendored\"]}}",
@@ -1450,8 +1449,8 @@
"resolv-conf_0.7.6": "{\"dependencies\":[],\"features\":{\"system\":[]}}",
"rfc6979_0.4.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"reset\"],\"name\":\"hmac\",\"req\":\"^0.12\"},{\"kind\":\"dev\",\"name\":\"sha2\",\"req\":\"^0.10\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2\"}],\"features\":{}}",
"ring_0.17.14": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1.2.8\"},{\"default_features\":false,\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"getrandom\",\"req\":\"^0.2.10\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.148\",\"target\":\"cfg(all(any(all(target_arch = \\\"aarch64\\\", target_endian = \\\"little\\\"), all(target_arch = \\\"arm\\\", target_endian = \\\"little\\\")), any(target_os = \\\"android\\\", target_os = \\\"linux\\\")))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.155\",\"target\":\"cfg(all(all(target_arch = \\\"aarch64\\\", target_endian = \\\"little\\\"), target_vendor = \\\"apple\\\", any(target_os = \\\"ios\\\", target_os = \\\"macos\\\", target_os = \\\"tvos\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\")))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.148\",\"target\":\"cfg(any(unix, windows, target_os = \\\"wasi\\\"))\"},{\"name\":\"untrusted\",\"req\":\"^0.9\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.37\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_Threading\"],\"name\":\"windows-sys\",\"req\":\"^0.52\",\"target\":\"cfg(all(all(target_arch = \\\"aarch64\\\", target_endian = \\\"little\\\"), target_os = \\\"windows\\\"))\"}],\"features\":{\"alloc\":[],\"default\":[\"alloc\",\"dev_urandom_fallback\"],\"dev_urandom_fallback\":[],\"less-safe-getrandom-custom-or-rdrand\":[],\"less-safe-getrandom-espidf\":[],\"slow_tests\":[],\"std\":[\"alloc\"],\"test_logging\":[],\"unstable-testing-arm-no-hw\":[],\"unstable-testing-arm-no-neon\":[],\"wasm32_unknown_unknown_js\":[\"getrandom/js\"]}}",
"rmcp-macros_1.7.0": "{\"dependencies\":[{\"name\":\"darling\",\"req\":\"^0.23\"},{\"name\":\"proc-macro2\",\"req\":\"^1\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{\"local\":[]}}",
"rmcp_1.7.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"async-trait\",\"req\":\"^0.1.89\"},{\"kind\":\"dev\",\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"default_features\":false,\"features\":[\"http1\",\"tokio\"],\"kind\":\"dev\",\"name\":\"axum\",\"req\":\"^0.8\"},{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"serde\",\"clock\",\"std\",\"oldtime\"],\"name\":\"chrono\",\"req\":\"^0.4.38\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"features\":[\"serde\",\"now\"],\"name\":\"chrono\",\"req\":\"^0.4.38\",\"target\":\"cfg(not(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\")))\"},{\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"http\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"http-body\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"http-body-util\",\"optional\":true,\"req\":\"^0.1\"},{\"features\":[\"client\",\"http1\"],\"name\":\"hyper\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"server\",\"http1\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1\"},{\"features\":[\"tokio\"],\"name\":\"hyper-util\",\"optional\":true,\"req\":\"^0.1\"},{\"features\":[\"tokio\"],\"kind\":\"dev\",\"name\":\"hyper-util\",\"req\":\"^0.1\"},{\"name\":\"jsonwebtoken\",\"optional\":true,\"req\":\"^10\"},{\"default_features\":false,\"name\":\"oauth2\",\"optional\":true,\"req\":\"^5.0\"},{\"name\":\"pastey\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2\"},{\"features\":[\"tokio1\"],\"name\":\"process-wrap\",\"optional\":true,\"req\":\"^9.0\"},{\"name\":\"rand\",\"optional\":true,\"req\":\"^0.10\"},{\"default_features\":false,\"features\":[\"json\",\"stream\"],\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.13.2\"},{\"name\":\"rmcp-macros\",\"optional\":true,\"req\":\"^1.7.0\"},{\"features\":[\"chrono04\"],\"name\":\"schemars\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"chrono04\"],\"kind\":\"dev\",\"name\":\"schemars\",\"req\":\"^1.1.0\"},{\"features\":[\"derive\",\"rc\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"sse-stream\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"thiserror\",\"req\":\"^2\"},{\"features\":[\"sync\",\"macros\",\"rt\",\"time\"],\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"name\":\"tokio-stream\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"tokio-util\",\"req\":\"^0.7\"},{\"name\":\"tower-service\",\"optional\":true,\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"tower-service\",\"req\":\"^0.3\"},{\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"env-filter\",\"std\",\"fmt\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"name\":\"url\",\"optional\":true,\"req\":\"^2.4\"},{\"kind\":\"dev\",\"name\":\"url\",\"req\":\"^2.4\"},{\"features\":[\"v4\"],\"name\":\"uuid\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"which\",\"optional\":true,\"req\":\"^8\"}],\"features\":{\"__reqwest\":[\"dep:reqwest\"],\"auth\":[\"dep:oauth2\",\"__reqwest\",\"dep:url\"],\"auth-client-credentials-jwt\":[\"auth\",\"dep:jsonwebtoken\",\"uuid\"],\"client\":[\"dep:tokio-stream\"],\"client-side-sse\":[\"dep:sse-stream\",\"dep:http\"],\"default\":[\"base64\",\"macros\",\"server\"],\"elicitation\":[\"dep:url\"],\"local\":[\"rmcp-macros?/local\"],\"macros\":[\"dep:rmcp-macros\",\"dep:pastey\"],\"reqwest\":[\"__reqwest\",\"reqwest?/rustls\"],\"reqwest-native-tls\":[\"__reqwest\",\"reqwest?/native-tls\"],\"reqwest-tls-no-provider\":[\"__reqwest\",\"reqwest?/rustls-no-provider\"],\"schemars\":[\"dep:schemars\"],\"server\":[\"transport-async-rw\",\"dep:schemars\",\"dep:pastey\"],\"server-side-http\":[\"uuid\",\"dep:rand\",\"dep:tokio-stream\",\"dep:http\",\"dep:http-body\",\"dep:http-body-util\",\"dep:bytes\",\"dep:sse-stream\",\"tower\"],\"tower\":[\"dep:tower-service\"],\"transport-async-rw\":[\"tokio/io-util\",\"tokio-util/codec\"],\"transport-child-process\":[\"transport-async-rw\",\"tokio/process\",\"dep:process-wrap\"],\"transport-io\":[\"transport-async-rw\",\"tokio/io-std\"],\"transport-streamable-http-client\":[\"client-side-sse\",\"transport-worker\"],\"transport-streamable-http-client-reqwest\":[\"transport-streamable-http-client\",\"__reqwest\"],\"transport-streamable-http-client-unix-socket\":[\"transport-streamable-http-client\",\"dep:hyper\",\"dep:hyper-util\",\"dep:http-body-util\",\"dep:http\",\"dep:bytes\",\"tokio/net\"],\"transport-streamable-http-server\":[\"transport-streamable-http-server-session\",\"server-side-http\",\"transport-worker\"],\"transport-streamable-http-server-session\":[\"transport-async-rw\",\"dep:tokio-stream\"],\"transport-worker\":[\"dep:tokio-stream\"],\"which-command\":[\"transport-child-process\",\"dep:which\"]}}",
"rmcp-macros_1.8.0": "{\"dependencies\":[{\"name\":\"darling\",\"req\":\"^0.23\"},{\"name\":\"proc-macro2\",\"req\":\"^1\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{\"local\":[]}}",
"rmcp_1.8.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"async-trait\",\"req\":\"^0.1.89\"},{\"kind\":\"dev\",\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"default_features\":false,\"features\":[\"http1\",\"tokio\"],\"kind\":\"dev\",\"name\":\"axum\",\"req\":\"^0.8\"},{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"serde\",\"clock\",\"std\",\"oldtime\"],\"name\":\"chrono\",\"req\":\"^0.4.38\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"features\":[\"serde\",\"now\"],\"name\":\"chrono\",\"req\":\"^0.4.38\",\"target\":\"cfg(not(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\")))\"},{\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"http\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"http-body\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"http-body-util\",\"optional\":true,\"req\":\"^0.1\"},{\"features\":[\"client\",\"http1\"],\"name\":\"hyper\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"server\",\"http1\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1\"},{\"features\":[\"tokio\"],\"name\":\"hyper-util\",\"optional\":true,\"req\":\"^0.1\"},{\"features\":[\"tokio\"],\"kind\":\"dev\",\"name\":\"hyper-util\",\"req\":\"^0.1\"},{\"name\":\"jsonwebtoken\",\"optional\":true,\"req\":\"^10\"},{\"default_features\":false,\"name\":\"oauth2\",\"optional\":true,\"req\":\"^5.0\"},{\"name\":\"pastey\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2\"},{\"features\":[\"tokio1\"],\"name\":\"process-wrap\",\"optional\":true,\"req\":\"^9.0\"},{\"name\":\"rand\",\"optional\":true,\"req\":\"^0.10\"},{\"default_features\":false,\"features\":[\"json\",\"stream\"],\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.13.2\"},{\"name\":\"rmcp-macros\",\"optional\":true,\"req\":\"^1.8.0\"},{\"features\":[\"chrono04\"],\"name\":\"schemars\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"chrono04\"],\"kind\":\"dev\",\"name\":\"schemars\",\"req\":\"^1.1.0\"},{\"features\":[\"derive\",\"rc\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"sse-stream\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"thiserror\",\"req\":\"^2\"},{\"features\":[\"sync\",\"macros\",\"rt\",\"time\"],\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"name\":\"tokio-stream\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"tokio-util\",\"req\":\"^0.7\"},{\"name\":\"tower-service\",\"optional\":true,\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"tower-service\",\"req\":\"^0.3\"},{\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"env-filter\",\"std\",\"fmt\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"name\":\"url\",\"optional\":true,\"req\":\"^2.4\"},{\"kind\":\"dev\",\"name\":\"url\",\"req\":\"^2.4\"},{\"features\":[\"v4\"],\"name\":\"uuid\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"which\",\"optional\":true,\"req\":\"^8\"}],\"features\":{\"__reqwest\":[\"dep:reqwest\"],\"auth\":[\"dep:oauth2\",\"__reqwest\",\"dep:url\"],\"auth-client-credentials-jwt\":[\"auth\",\"dep:jsonwebtoken\",\"uuid\"],\"client\":[\"dep:tokio-stream\"],\"client-side-sse\":[\"dep:sse-stream\",\"dep:http\"],\"default\":[\"base64\",\"macros\",\"server\"],\"elicitation\":[\"dep:url\"],\"local\":[\"rmcp-macros?/local\"],\"macros\":[\"dep:rmcp-macros\",\"dep:pastey\"],\"reqwest\":[\"__reqwest\",\"reqwest?/rustls\"],\"reqwest-native-tls\":[\"__reqwest\",\"reqwest?/native-tls\"],\"reqwest-tls-no-provider\":[\"__reqwest\",\"reqwest?/rustls-no-provider\"],\"schemars\":[\"dep:schemars\"],\"server\":[\"transport-async-rw\",\"dep:schemars\",\"dep:pastey\"],\"server-side-http\":[\"uuid\",\"dep:rand\",\"dep:tokio-stream\",\"dep:http\",\"dep:http-body\",\"dep:http-body-util\",\"dep:bytes\",\"dep:sse-stream\",\"tower\"],\"tower\":[\"dep:tower-service\"],\"transport-async-rw\":[\"tokio/io-util\",\"tokio-util/codec\"],\"transport-child-process\":[\"transport-async-rw\",\"tokio/process\",\"dep:process-wrap\"],\"transport-io\":[\"transport-async-rw\",\"tokio/io-std\"],\"transport-streamable-http-client\":[\"client-side-sse\",\"transport-worker\"],\"transport-streamable-http-client-reqwest\":[\"transport-streamable-http-client\",\"__reqwest\"],\"transport-streamable-http-client-unix-socket\":[\"transport-streamable-http-client\",\"dep:hyper\",\"dep:hyper-util\",\"dep:http-body-util\",\"dep:http\",\"dep:bytes\",\"tokio/net\"],\"transport-streamable-http-server\":[\"transport-streamable-http-server-session\",\"server-side-http\",\"transport-worker\"],\"transport-streamable-http-server-session\":[\"transport-async-rw\",\"dep:tokio-stream\"],\"transport-worker\":[\"dep:tokio-stream\"],\"which-command\":[\"transport-child-process\",\"dep:which\"]}}",
"rtrb_0.3.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"crossbeam-utils\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.10\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}",
"rust-embed-impl_8.11.0": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"name\":\"rust-embed-utils\",\"req\":\"^8.11.0\"},{\"name\":\"shellexpand\",\"optional\":true,\"req\":\"^3\"},{\"default_features\":false,\"features\":[\"derive\",\"parsing\",\"proc-macro\",\"printing\"],\"name\":\"syn\",\"req\":\"^2\"},{\"name\":\"walkdir\",\"req\":\"^2.3.1\"}],\"features\":{\"compression\":[],\"debug-embed\":[],\"deterministic-timestamps\":[],\"include-exclude\":[\"rust-embed-utils/include-exclude\"],\"interpolate-folder-path\":[\"shellexpand\"],\"mime-guess\":[\"rust-embed-utils/mime-guess\"]}}",
"rust-embed-utils_8.11.0": "{\"dependencies\":[{\"name\":\"globset\",\"optional\":true,\"req\":\"^0.4.8\"},{\"name\":\"mime_guess\",\"optional\":true,\"req\":\"^2.0.4\"},{\"name\":\"sha2\",\"req\":\"^0.10.5\"},{\"name\":\"walkdir\",\"req\":\"^2.3.1\"}],\"features\":{\"debug-embed\":[],\"include-exclude\":[\"globset\"],\"mime-guess\":[\"mime_guess\"]}}",
@@ -1876,6 +1875,7 @@
"zerovec_0.11.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.1\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"features\":[\"wasm_js\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"iai\",\"req\":\"^0.1.1\"},{\"features\":[\"json\"],\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.43.2\"},{\"default_features\":false,\"features\":[\"use-std\"],\"kind\":\"dev\",\"name\":\"postcard\",\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rand_distr\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"rand_pcg\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rmp-serde\",\"req\":\"^1.2.0\"},{\"default_features\":false,\"name\":\"schemars\",\"optional\":true,\"req\":\"^1.0.4\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.45\"},{\"default_features\":false,\"features\":[\"xxhash64\"],\"name\":\"twox-hash\",\"optional\":true,\"req\":\"^2.0.0\"},{\"default_features\":false,\"name\":\"yoke\",\"optional\":true,\"req\":\"^0.8.2\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"yoke\",\"req\":\"^0.8.2\"},{\"default_features\":false,\"name\":\"zerofrom\",\"req\":\"^0.1.6\"},{\"default_features\":false,\"name\":\"zerovec-derive\",\"optional\":true,\"req\":\"^0.11.3\"}],\"features\":{\"alloc\":[\"serde?/alloc\"],\"databake\":[\"dep:databake\"],\"derive\":[\"dep:zerovec-derive\"],\"hashmap\":[\"dep:twox-hash\",\"alloc\"],\"schemars\":[\"dep:schemars\",\"alloc\"],\"serde\":[\"dep:serde\"],\"std\":[],\"yoke\":[\"dep:yoke\"]}}",
"zip_0.6.6": "{\"dependencies\":[{\"name\":\"aes\",\"optional\":true,\"req\":\"^0.8.2\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"},{\"name\":\"byteorder\",\"req\":\"^1.4.3\"},{\"name\":\"bzip2\",\"optional\":true,\"req\":\"^0.4.3\"},{\"name\":\"constant_time_eq\",\"optional\":true,\"req\":\"^0.1.5\"},{\"name\":\"crc32fast\",\"req\":\"^1.3.2\"},{\"name\":\"crossbeam-utils\",\"req\":\"^0.8.8\",\"target\":\"cfg(any(all(target_arch = \\\"arm\\\", target_pointer_width = \\\"32\\\"), target_arch = \\\"mips\\\", target_arch = \\\"powerpc\\\"))\"},{\"default_features\":false,\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.0.23\"},{\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2.5\"},{\"features\":[\"reset\"],\"name\":\"hmac\",\"optional\":true,\"req\":\"^0.12.1\"},{\"name\":\"pbkdf2\",\"optional\":true,\"req\":\"^0.11.0\"},{\"name\":\"sha1\",\"optional\":true,\"req\":\"^0.10.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"time\",\"optional\":true,\"req\":\"^0.3.7\"},{\"features\":[\"formatting\",\"macros\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.7\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.3.2\"},{\"name\":\"zstd\",\"optional\":true,\"req\":\"^0.11.2\"}],\"features\":{\"aes-crypto\":[\"aes\",\"constant_time_eq\",\"hmac\",\"pbkdf2\",\"sha1\"],\"default\":[\"aes-crypto\",\"bzip2\",\"deflate\",\"time\",\"zstd\"],\"deflate\":[\"flate2/rust_backend\"],\"deflate-miniz\":[\"flate2/default\"],\"deflate-zlib\":[\"flate2/zlib\"],\"unreserved\":[]}}",
"zip_2.4.2": "{\"dependencies\":[{\"name\":\"aes\",\"optional\":true,\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.95\"},{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"req\":\"^1.4.1\",\"target\":\"cfg(fuzzing)\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"},{\"name\":\"bzip2\",\"optional\":true,\"req\":\"^0.5.0\"},{\"name\":\"chrono\",\"optional\":true,\"req\":\"^0.4\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"=4.4.18\"},{\"name\":\"constant_time_eq\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"crc32fast\",\"req\":\"^1.4\"},{\"name\":\"crossbeam-utils\",\"req\":\"^0.8.21\",\"target\":\"cfg(any(all(target_arch = \\\"arm\\\", target_pointer_width = \\\"32\\\"), target_arch = \\\"mips\\\", target_arch = \\\"powerpc\\\"))\"},{\"name\":\"deflate64\",\"optional\":true,\"req\":\"^0.1.9\"},{\"default_features\":false,\"name\":\"displaydoc\",\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"wasm_js\",\"std\"],\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.3.1\"},{\"features\":[\"wasm_js\",\"std\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.3.1\"},{\"features\":[\"reset\"],\"name\":\"hmac\",\"optional\":true,\"req\":\"^0.12\"},{\"name\":\"indexmap\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"lzma-rs\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"memchr\",\"req\":\"^2.7\"},{\"default_features\":false,\"name\":\"nt-time\",\"optional\":true,\"req\":\"^0.10.6\"},{\"name\":\"pbkdf2\",\"optional\":true,\"req\":\"^0.12\"},{\"name\":\"sha1\",\"optional\":true,\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.15\"},{\"name\":\"thiserror\",\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"time\",\"optional\":true,\"req\":\"^0.3.37\"},{\"default_features\":false,\"features\":[\"formatting\",\"macros\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.37\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.5\"},{\"name\":\"xz2\",\"optional\":true,\"req\":\"^0.1.7\"},{\"features\":[\"zeroize_derive\"],\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1.8\"},{\"name\":\"zopfli\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"zstd\",\"optional\":true,\"req\":\"^0.13\"}],\"features\":{\"_all-features\":[],\"_deflate-any\":[],\"aes-crypto\":[\"aes\",\"constant_time_eq\",\"hmac\",\"pbkdf2\",\"sha1\",\"getrandom\",\"zeroize\"],\"chrono\":[\"chrono/default\"],\"default\":[\"aes-crypto\",\"bzip2\",\"deflate64\",\"deflate\",\"lzma\",\"time\",\"zstd\",\"xz\"],\"deflate\":[\"flate2/rust_backend\",\"deflate-zopfli\",\"deflate-flate2\"],\"deflate-flate2\":[\"_deflate-any\"],\"deflate-miniz\":[\"deflate\",\"deflate-flate2\"],\"deflate-zlib\":[\"flate2/zlib\",\"deflate-flate2\"],\"deflate-zlib-ng\":[\"flate2/zlib-ng\",\"deflate-flate2\"],\"deflate-zopfli\":[\"zopfli\",\"_deflate-any\"],\"lzma\":[\"lzma-rs/stream\"],\"nt-time\":[\"dep:nt-time\"],\"unreserved\":[],\"xz\":[\"dep:xz2\"]}}",
"zlib-rs_0.5.5": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"crc32fast\",\"req\":\"^1.3.2\"},{\"kind\":\"dev\",\"name\":\"memoffset\",\"req\":\"^0.9.1\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1.0.3\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"}],\"features\":{\"ZLIB_DEBUG\":[],\"__internal-fuzz\":[\"arbitrary\"],\"__internal-fuzz-disable-checksum\":[],\"__internal-test\":[\"quickcheck\"],\"avx512\":[\"vpclmulqdq\"],\"c-allocator\":[],\"default\":[\"std\",\"c-allocator\"],\"rust-allocator\":[],\"std\":[\"rust-allocator\"],\"vpclmulqdq\":[]}}",
"zlib-rs_0.6.3": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"crc32fast\",\"req\":\"^1.3.2\"},{\"kind\":\"dev\",\"name\":\"memoffset\",\"req\":\"^0.9.1\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1.0.3\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"}],\"features\":{\"ZLIB_DEBUG\":[],\"__internal-api\":[],\"__internal-fuzz\":[\"arbitrary\"],\"__internal-fuzz-disable-checksum\":[],\"__internal-test\":[\"quickcheck\"],\"avx512\":[\"vpclmulqdq\"],\"c-allocator\":[],\"default\":[\"std\",\"c-allocator\"],\"rust-allocator\":[],\"std\":[\"rust-allocator\"],\"vpclmulqdq\":[]}}",
"zmij_1.0.19": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"name\":\"no-panic\",\"optional\":true,\"req\":\"^0.1.36\"},{\"kind\":\"dev\",\"name\":\"num-bigint\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"num-integer\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"num_cpus\",\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"opt-level\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"ryu\",\"req\":\"^1\"}],\"features\":{}}",
"zmij_1.0.21": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"name\":\"no-panic\",\"optional\":true,\"req\":\"^0.1.36\"},{\"kind\":\"dev\",\"name\":\"num-bigint\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"num-integer\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"num_cpus\",\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"opt-level\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"ryu\",\"req\":\"^1\"}],\"features\":{}}",
+94 -35
View File
@@ -402,6 +402,7 @@ dependencies = [
"codex-app-server-protocol",
"codex-config",
"codex-core",
"codex-exec-server",
"codex-features",
"codex-login",
"codex-models-manager",
@@ -1975,6 +1976,7 @@ dependencies = [
"codex-chatgpt",
"codex-cloud-config",
"codex-config",
"codex-connectors",
"codex-core",
"codex-core-plugins",
"codex-exec-server",
@@ -2136,6 +2138,7 @@ dependencies = [
"codex-otel",
"codex-protocol",
"codex-utils-cli",
"pretty_assertions",
"serde",
"serde_json",
"tokio",
@@ -2161,6 +2164,7 @@ dependencies = [
"codex-core",
"codex-login",
"codex-model-provider",
"codex-protocol",
"codex-state",
"codex-uds",
"codex-utils-absolute-path",
@@ -2169,9 +2173,11 @@ dependencies = [
"futures",
"gethostname",
"hmac 0.12.1",
"httpdate",
"jsonwebtoken",
"owo-colors",
"pretty_assertions",
"rand 0.9.3",
"serde",
"serde_json",
"sha2 0.10.9",
@@ -2290,7 +2296,6 @@ version = "0.0.0"
dependencies = [
"anyhow",
"clap",
"codex-app-server-protocol",
"codex-connectors",
"codex-core",
"codex-git-utils",
@@ -2311,6 +2316,7 @@ name = "codex-cli"
version = "0.0.0"
dependencies = [
"anyhow",
"app_test_support",
"assert_cmd",
"assert_matches",
"clap",
@@ -2403,12 +2409,15 @@ dependencies = [
"rustls-pki-types",
"serde",
"serde_json",
"sha2 0.10.9",
"system-configuration",
"tempfile",
"thiserror 2.0.18",
"tokio",
"tracing",
"tracing-opentelemetry",
"tracing-subscriber",
"windows-sys 0.52.0",
"zstd 0.13.3",
]
@@ -2497,6 +2506,7 @@ dependencies = [
"codex-code-mode-protocol",
"codex-protocol",
"deno_core_icudata",
"futures",
"pretty_assertions",
"serde_json",
"tokio",
@@ -2508,6 +2518,17 @@ dependencies = [
[[package]]
name = "codex-code-mode-host"
version = "0.0.0"
dependencies = [
"anyhow",
"codex-code-mode",
"codex-code-mode-protocol",
"codex-protocol",
"codex-utils-cargo-bin",
"pretty_assertions",
"serde_json",
"tokio",
"tokio-util",
]
[[package]]
name = "codex-code-mode-protocol"
@@ -2531,7 +2552,6 @@ version = "0.0.0"
dependencies = [
"anyhow",
"base64 0.22.1",
"codex-app-server-protocol",
"codex-execpolicy",
"codex-features",
"codex-file-system",
@@ -2552,6 +2572,7 @@ dependencies = [
"multimap",
"pretty_assertions",
"prost 0.14.3",
"regex-lite",
"schemars 0.8.22",
"serde",
"serde_ignored",
@@ -2578,8 +2599,9 @@ name = "codex-connectors"
version = "0.0.0"
dependencies = [
"anyhow",
"codex-app-server-protocol",
"codex-config",
"codex-plugin",
"indexmap 2.14.0",
"pretty_assertions",
"serde",
"serde_json",
@@ -2590,6 +2612,18 @@ dependencies = [
"urlencoding",
]
[[package]]
name = "codex-connectors-extension"
version = "0.0.0"
dependencies = [
"codex-connectors",
"codex-core-plugins",
"codex-plugin",
"codex-utils-path-uri",
"serde_json",
"thiserror 2.0.18",
]
[[package]]
name = "codex-context-fragments"
version = "0.0.0"
@@ -2611,6 +2645,7 @@ dependencies = [
"bm25",
"chrono",
"clap",
"codex-agent-graph-store",
"codex-analytics",
"codex-api",
"codex-app-server-protocol",
@@ -2751,6 +2786,7 @@ dependencies = [
"codex-analytics",
"codex-app-server-protocol",
"codex-config",
"codex-connectors",
"codex-core-skills",
"codex-exec-server",
"codex-git-utils",
@@ -2763,13 +2799,14 @@ dependencies = [
"codex-protocol",
"codex-tools",
"codex-utils-absolute-path",
"codex-utils-path",
"codex-utils-path-uri",
"codex-utils-plugins",
"dirs",
"flate2",
"indexmap 2.14.0",
"libc",
"pretty_assertions",
"regex",
"reqwest 0.12.28",
"semver",
"serde",
@@ -2793,7 +2830,6 @@ version = "0.0.0"
dependencies = [
"anyhow",
"codex-analytics",
"codex-app-server-protocol",
"codex-config",
"codex-context-fragments",
"codex-exec-server",
@@ -2879,12 +2915,13 @@ dependencies = [
"bytes",
"clatter",
"codex-api",
"codex-app-server-protocol",
"codex-client",
"codex-exec-server-protocol",
"codex-file-system",
"codex-network-proxy",
"codex-otel",
"codex-protocol",
"codex-sandboxing",
"codex-shell-command",
"codex-test-binary-support",
"codex-utils-absolute-path",
"codex-utils-path-uri",
@@ -2894,9 +2931,13 @@ dependencies = [
"futures",
"http 1.4.0",
"libc",
"opentelemetry",
"opentelemetry_sdk",
"pretty_assertions",
"prost 0.14.3",
"rcgen",
"reqwest 0.12.28",
"rustls",
"serde",
"serde_json",
"serial_test",
@@ -2908,11 +2949,28 @@ dependencies = [
"tokio-util",
"toml 0.9.11+spec-1.1.0",
"tracing",
"tracing-opentelemetry",
"tracing-subscriber",
"uuid",
"windows-sys 0.52.0",
"wiremock",
]
[[package]]
name = "codex-exec-server-protocol"
version = "0.0.0"
dependencies = [
"base64 0.22.1",
"codex-file-system",
"codex-network-proxy",
"codex-protocol",
"codex-shell-command",
"codex-utils-path-uri",
"pretty_assertions",
"serde",
"serde_json",
]
[[package]]
name = "codex-execpolicy"
version = "0.0.0"
@@ -2969,6 +3027,7 @@ dependencies = [
"codex-tools",
"codex-utils-absolute-path",
"pretty_assertions",
"serde_json",
"tokio",
]
@@ -3157,8 +3216,10 @@ dependencies = [
name = "codex-image-generation-extension"
version = "0.0.0"
dependencies = [
"base64 0.22.1",
"codex-api",
"codex-core",
"codex-exec-server",
"codex-extension-api",
"codex-login",
"codex-model-provider",
@@ -3174,6 +3235,7 @@ dependencies = [
"serde",
"serde_json",
"tokio",
"tracing",
]
[[package]]
@@ -3240,7 +3302,6 @@ dependencies = [
"base64 0.22.1",
"chrono",
"codex-agent-identity",
"codex-app-server-protocol",
"codex-client",
"codex-config",
"codex-keyring-store",
@@ -3284,6 +3345,7 @@ dependencies = [
"codex-api",
"codex-async-utils",
"codex-config",
"codex-connectors",
"codex-exec-server",
"codex-login",
"codex-model-provider",
@@ -3313,6 +3375,7 @@ name = "codex-mcp-extension"
version = "0.0.0"
dependencies = [
"codex-config",
"codex-connectors-extension",
"codex-core",
"codex-core-plugins",
"codex-exec-server",
@@ -3475,7 +3538,6 @@ name = "codex-model-provider-info"
version = "0.0.0"
dependencies = [
"codex-api",
"codex-app-server-protocol",
"codex-protocol",
"codex-utils-absolute-path",
"http 1.4.0",
@@ -3492,7 +3554,6 @@ name = "codex-models-manager"
version = "0.0.0"
dependencies = [
"chrono",
"codex-app-server-protocol",
"codex-collaboration-mode-templates",
"codex-login",
"codex-otel",
@@ -3528,7 +3589,10 @@ dependencies = [
"rama-tcp",
"rama-tls-rustls",
"rama-unix",
"rand 0.9.3",
"rustls-native-certs",
"schannel",
"security-framework 3.5.1",
"serde",
"serde_json",
"sha2 0.10.9",
@@ -3566,7 +3630,6 @@ version = "0.0.0"
dependencies = [
"chrono",
"codex-api",
"codex-app-server-protocol",
"codex-protocol",
"codex-utils-absolute-path",
"codex-utils-string",
@@ -3599,6 +3662,7 @@ dependencies = [
"codex-config",
"codex-protocol",
"codex-utils-absolute-path",
"codex-utils-path-uri",
"codex-utils-plugins",
"pretty_assertions",
"thiserror 2.0.18",
@@ -3713,7 +3777,6 @@ dependencies = [
"base64 0.22.1",
"bytes",
"codex-api",
"codex-client",
"codex-config",
"codex-exec-server",
"codex-keyring-store",
@@ -3754,7 +3817,6 @@ dependencies = [
"chrono",
"codex-file-search",
"codex-git-utils",
"codex-login",
"codex-otel",
"codex-protocol",
"codex-state",
@@ -3973,6 +4035,7 @@ dependencies = [
"chrono",
"codex-git-utils",
"codex-install-context",
"codex-otel",
"codex-protocol",
"codex-rollout",
"codex-state",
@@ -3991,8 +4054,8 @@ dependencies = [
name = "codex-tools"
version = "0.0.0"
dependencies = [
"codex-app-server-protocol",
"codex-code-mode",
"codex-connectors",
"codex-features",
"codex-file-system",
"codex-protocol",
@@ -4016,6 +4079,7 @@ name = "codex-tui"
version = "0.0.0"
dependencies = [
"anyhow",
"app_test_support",
"arboard",
"assert_matches",
"base64 0.22.1",
@@ -6024,8 +6088,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369"
dependencies = [
"crc32fast",
"libz-sys",
"miniz_oxide",
"zlib-rs 0.5.5",
]
[[package]]
@@ -6713,7 +6777,7 @@ dependencies = [
"prodash",
"thiserror 2.0.18",
"walkdir",
"zlib-rs",
"zlib-rs 0.6.3",
]
[[package]]
@@ -8766,17 +8830,6 @@ dependencies = [
"webrtc-sys",
]
[[package]]
name = "libz-sys"
version = "1.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15d118bbf3771060e7311cc7bb0545b01d08a8b4a7de949198dec1fa0ca1c0f7"
dependencies = [
"cc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "link-cplusplus"
version = "1.0.12"
@@ -9740,9 +9793,9 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
[[package]]
name = "openssl-src"
version = "300.5.5+3.5.5"
version = "300.6.1+3.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f1787d533e03597a7934fd0a765f0d28e94ecc5fb7789f8053b1e699a56f709"
checksum = "46eb8fb9fb3b61ce1c0f8a026c4c1a0714d3a9e138e7fbde78753ce2babc3846"
dependencies = [
"cc",
]
@@ -11459,9 +11512,9 @@ dependencies = [
[[package]]
name = "rmcp"
version = "1.7.0"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0810a9f717d9828f475fe1f629f4c305c8464b7f496c3a854b58d29e65f4058e"
checksum = "1d1f571c72940a19d9532fe52dbea8bc9912bf1d766c2970bb824056b86f3f59"
dependencies = [
"async-trait",
"base64 0.22.1",
@@ -11494,9 +11547,9 @@ dependencies = [
[[package]]
name = "rmcp-macros"
version = "1.7.0"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6aefac48c364756e97f04c0401ba3231e8607882c7c1d92da0437dc16307904d"
checksum = "1aad0035b69380782d78ea95b508327e6deaa2235909053e596eea8f27b5e1d5"
dependencies = [
"darling 0.23.0",
"proc-macro2",
@@ -13604,7 +13657,7 @@ dependencies = [
[[package]]
name = "tokio-tungstenite"
version = "0.28.0"
source = "git+https://github.com/openai-oss-forks/tokio-tungstenite?rev=e5e64b86722c5453c4038131c3193faa49a648ad#e5e64b86722c5453c4038131c3193faa49a648ad"
source = "git+https://github.com/openai-oss-forks/tokio-tungstenite?rev=0e5b2d73aa18dd9f0a50ee9ff199d5aef7594186#0e5b2d73aa18dd9f0a50ee9ff199d5aef7594186"
dependencies = [
"futures-util",
"log",
@@ -14042,7 +14095,7 @@ dependencies = [
[[package]]
name = "tungstenite"
version = "0.27.0"
source = "git+https://github.com/openai-oss-forks/tungstenite-rs?rev=9200079d3b54a1ff51072e24d81fd354f085156f#9200079d3b54a1ff51072e24d81fd354f085156f"
source = "git+https://github.com/openai-oss-forks/tungstenite-rs?rev=4fffad30fe373adbdcffab9545e9e9bf4f2fc19f#4fffad30fe373adbdcffab9545e9e9bf4f2fc19f"
dependencies = [
"bytes",
"data-encoding",
@@ -15803,6 +15856,12 @@ dependencies = [
"zstd 0.13.3",
]
[[package]]
name = "zlib-rs"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40990edd51aae2c2b6907af74ffb635029d5788228222c4bb811e9351c0caad3"
[[package]]
name = "zlib-rs"
version = "0.6.3"
+11 -6
View File
@@ -44,9 +44,11 @@ members = [
"secrets",
"exec",
"file-system",
"exec-server-protocol",
"exec-server",
"execpolicy",
"execpolicy-legacy",
"ext/connectors",
"ext/extension-api",
"ext/goal",
"ext/guardian",
@@ -164,6 +166,7 @@ codex-code-mode-protocol = { path = "code-mode-protocol" }
codex-home = { path = "codex-home" }
codex-config = { path = "config" }
codex-connectors = { path = "connectors" }
codex-connectors-extension = { path = "ext/connectors" }
codex-context-fragments = { path = "context-fragments" }
codex-core = { path = "core" }
codex-core-api = { path = "core-api" }
@@ -171,6 +174,7 @@ codex-core-plugins = { path = "core-plugins" }
codex-core-skills = { path = "core-skills" }
codex-exec = { path = "exec" }
codex-file-system = { path = "file-system" }
codex-exec-server-protocol = { path = "exec-server-protocol" }
codex-exec-server = { path = "exec-server" }
codex-execpolicy = { path = "execpolicy" }
codex-extension-api = { path = "ext/extension-api" }
@@ -314,6 +318,7 @@ glob = "0.3"
globset = "0.4"
hmac = "0.12.1"
http = "1.3.1"
httpdate = "1.0.3"
iana-time-zone = "0.1.64"
icu_decimal = "2.1"
icu_locale_core = "2.1"
@@ -368,7 +373,7 @@ rcgen = { version = "0.14.7", default-features = false, features = [
regex = "1.12.3"
regex-lite = "0.1.8"
reqwest = { version = "0.12", features = ["cookies"] }
rmcp = { version = "1.7.0", default-features = false }
rmcp = { version = "1.8.0", default-features = false }
runfiles = { git = "https://github.com/dzbarsky/rules_rust", rev = "b56cbaa8465e74127f1ea216f813cd377295ad81" }
rustls = { version = "0.23", default-features = false, features = [
"aws_lc_rs",
@@ -380,7 +385,7 @@ schemars = "0.8.22"
seccompiler = "0.5.0"
semver = "1.0"
sentry = "0.46.0"
serde = "1"
serde = { version = "1", features = ["rc"] }
serde_ignored = "0.1.14"
serde_json = "1"
serde_path_to_error = "0.1.20"
@@ -409,6 +414,7 @@ strum_macros = "0.28.0"
supports-color = "3.0.2"
syntect = "5"
sys-locale = "0.3.2"
system-configuration = "0.7"
tar = { version = "=0.4.45", default-features = false }
tempfile = "3.23.0"
test-log = "0.2.19"
@@ -501,7 +507,6 @@ unwrap_used = "deny"
# silence the false positive here instead of deleting a real dependency.
[workspace.metadata.cargo-shear]
ignored = [
"codex-agent-graph-store",
"icu_provider",
"openssl-sys",
"codex-v8-poc",
@@ -546,11 +551,11 @@ opt-level = 0
# ratatui = { path = "../../ratatui" }
crossterm = { git = "https://github.com/nornagon/crossterm", rev = "87db8bfa6dc99427fd3b071681b07fc31c6ce995" }
ratatui = { git = "https://github.com/nornagon/ratatui", rev = "9b2ad1298408c45918ee9f8241a6f95498cdbed2" }
tokio-tungstenite = { git = "https://github.com/openai-oss-forks/tokio-tungstenite", rev = "e5e64b86722c5453c4038131c3193faa49a648ad" }
tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev = "9200079d3b54a1ff51072e24d81fd354f085156f" }
tokio-tungstenite = { git = "https://github.com/openai-oss-forks/tokio-tungstenite", rev = "0e5b2d73aa18dd9f0a50ee9ff199d5aef7594186" }
tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev = "4fffad30fe373adbdcffab9545e9e9bf4f2fc19f" }
# Uncomment to debug local changes.
# rmcp = { path = "../../rust-sdk/crates/rmcp" }
[patch."ssh://git@github.com/openai-oss-forks/tungstenite-rs.git"]
tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev = "9200079d3b54a1ff51072e24d81fd354f085156f" }
tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev = "4fffad30fe373adbdcffab9545e9e9bf4f2fc19f" }
+1 -1
View File
@@ -22,4 +22,4 @@ thiserror = { workspace = true }
pretty_assertions = { workspace = true }
serde_json = { workspace = true }
tempfile = { workspace = true }
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
tokio = { workspace = true, features = ["macros", "rt-multi-thread", "sync"] }
+1
View File
@@ -9,4 +9,5 @@ pub use error::AgentGraphStoreError;
pub use error::AgentGraphStoreResult;
pub use local::LocalAgentGraphStore;
pub use store::AgentGraphStore;
pub use store::AgentGraphStoreFuture;
pub use types::ThreadSpawnEdgeStatus;
+58 -40
View File
@@ -4,7 +4,7 @@ use std::sync::Arc;
use crate::AgentGraphStore;
use crate::AgentGraphStoreError;
use crate::AgentGraphStoreResult;
use crate::AgentGraphStoreFuture;
use crate::ThreadSpawnEdgeStatus;
/// SQLite-backed implementation of [`AgentGraphStore`] using an existing state runtime.
@@ -29,65 +29,83 @@ impl LocalAgentGraphStore {
}
impl AgentGraphStore for LocalAgentGraphStore {
async fn upsert_thread_spawn_edge(
fn upsert_thread_spawn_edge(
&self,
parent_thread_id: ThreadId,
child_thread_id: ThreadId,
status: ThreadSpawnEdgeStatus,
) -> AgentGraphStoreResult<()> {
self.state_db
.upsert_thread_spawn_edge(parent_thread_id, child_thread_id, to_state_status(status))
.await
.map_err(internal_error)
) -> AgentGraphStoreFuture<'_, ()> {
Box::pin(async move {
self.state_db
.upsert_thread_spawn_edge(
parent_thread_id,
child_thread_id,
to_state_status(status),
)
.await
.map_err(internal_error)
})
}
async fn set_thread_spawn_edge_status(
fn set_thread_spawn_edge_status(
&self,
child_thread_id: ThreadId,
status: ThreadSpawnEdgeStatus,
) -> AgentGraphStoreResult<()> {
self.state_db
.set_thread_spawn_edge_status(child_thread_id, to_state_status(status))
.await
.map_err(internal_error)
) -> AgentGraphStoreFuture<'_, ()> {
Box::pin(async move {
self.state_db
.set_thread_spawn_edge_status(child_thread_id, to_state_status(status))
.await
.map_err(internal_error)
})
}
async fn list_thread_spawn_children(
fn list_thread_spawn_children(
&self,
parent_thread_id: ThreadId,
status_filter: Option<ThreadSpawnEdgeStatus>,
) -> AgentGraphStoreResult<Vec<ThreadId>> {
if let Some(status) = status_filter {
return self
.state_db
.list_thread_spawn_children_with_status(parent_thread_id, to_state_status(status))
.await
.map_err(internal_error);
}
) -> AgentGraphStoreFuture<'_, Vec<ThreadId>> {
Box::pin(async move {
if let Some(status) = status_filter {
return self
.state_db
.list_thread_spawn_children_with_status(
parent_thread_id,
to_state_status(status),
)
.await
.map_err(internal_error);
}
self.state_db
.list_thread_spawn_children(parent_thread_id)
.await
.map_err(internal_error)
self.state_db
.list_thread_spawn_children(parent_thread_id)
.await
.map_err(internal_error)
})
}
async fn list_thread_spawn_descendants(
fn list_thread_spawn_descendants(
&self,
root_thread_id: ThreadId,
status_filter: Option<ThreadSpawnEdgeStatus>,
) -> AgentGraphStoreResult<Vec<ThreadId>> {
match status_filter {
Some(status) => self
.state_db
.list_thread_spawn_descendants_with_status(root_thread_id, to_state_status(status))
.await
.map_err(internal_error),
None => self
.state_db
.list_thread_spawn_descendants(root_thread_id)
.await
.map_err(internal_error),
}
) -> AgentGraphStoreFuture<'_, Vec<ThreadId>> {
Box::pin(async move {
match status_filter {
Some(status) => self
.state_db
.list_thread_spawn_descendants_with_status(
root_thread_id,
to_state_status(status),
)
.await
.map_err(internal_error),
None => self
.state_db
.list_thread_spawn_descendants(root_thread_id)
.await
.map_err(internal_error),
}
})
}
}
+11 -4
View File
@@ -1,8 +1,15 @@
use std::future::Future;
use std::pin::Pin;
use codex_protocol::ThreadId;
use crate::AgentGraphStoreResult;
use crate::ThreadSpawnEdgeStatus;
/// Future returned by [`AgentGraphStore`] operations.
pub type AgentGraphStoreFuture<'a, T> =
Pin<Box<dyn Future<Output = AgentGraphStoreResult<T>> + Send + 'a>>;
/// Storage-neutral boundary for persisted thread-spawn parent/child topology.
///
/// Implementations are expected to return stable ordering for list methods so callers can merge
@@ -17,7 +24,7 @@ pub trait AgentGraphStore: Send + Sync {
parent_thread_id: ThreadId,
child_thread_id: ThreadId,
status: ThreadSpawnEdgeStatus,
) -> impl std::future::Future<Output = AgentGraphStoreResult<()>> + Send;
) -> AgentGraphStoreFuture<'_, ()>;
/// Update the persisted lifecycle status of a spawned thread's incoming edge.
///
@@ -26,7 +33,7 @@ pub trait AgentGraphStore: Send + Sync {
&self,
child_thread_id: ThreadId,
status: ThreadSpawnEdgeStatus,
) -> impl std::future::Future<Output = AgentGraphStoreResult<()>> + Send;
) -> AgentGraphStoreFuture<'_, ()>;
/// List direct spawned children of a parent thread.
///
@@ -37,7 +44,7 @@ pub trait AgentGraphStore: Send + Sync {
&self,
parent_thread_id: ThreadId,
status_filter: Option<ThreadSpawnEdgeStatus>,
) -> impl std::future::Future<Output = AgentGraphStoreResult<Vec<ThreadId>>> + Send;
) -> AgentGraphStoreFuture<'_, Vec<ThreadId>>;
/// List spawned descendants breadth-first by depth, then by thread id.
///
@@ -49,5 +56,5 @@ pub trait AgentGraphStore: Send + Sync {
&self,
root_thread_id: ThreadId,
status_filter: Option<ThreadSpawnEdgeStatus>,
) -> impl std::future::Future<Output = AgentGraphStoreResult<Vec<ThreadId>>> + Send;
) -> AgentGraphStoreFuture<'_, Vec<ThreadId>>;
}
+24 -4
View File
@@ -119,7 +119,7 @@ pub struct AgentIdentityJwtClaims {
pub agent_private_key: String,
pub account_id: String,
pub chatgpt_user_id: String,
pub email: String,
pub email: Option<String>,
pub plan_type: AuthPlanType,
pub chatgpt_account_is_fedramp: bool,
}
@@ -667,13 +667,33 @@ mod tests {
agent_private_key: "private-key".to_string(),
account_id: "account-id".to_string(),
chatgpt_user_id: "user-id".to_string(),
email: "user@example.com".to_string(),
email: Some("user@example.com".to_string()),
plan_type: AuthPlanType::Known(KnownPlan::Pro),
chatgpt_account_is_fedramp: false,
}
);
}
#[test]
fn decode_agent_identity_jwt_accepts_missing_email() {
let jwt = jwt_with_payload(serde_json::json!({
"iss": AGENT_IDENTITY_JWT_ISSUER,
"aud": AGENT_IDENTITY_JWT_AUDIENCE,
"iat": 1_700_000_000usize,
"exp": 4_000_000_000usize,
"agent_runtime_id": "agent-runtime-id",
"agent_private_key": "private-key",
"account_id": "account-id",
"chatgpt_user_id": "user-id",
"plan_type": "pro",
"chatgpt_account_is_fedramp": false,
}));
let claims = decode_agent_identity_jwt(&jwt, /*jwks*/ None).expect("JWT should decode");
assert_eq!(claims.email, None);
}
#[test]
fn decode_agent_identity_jwt_maps_raw_plan_aliases() {
let jwt = jwt_with_payload(serde_json::json!({
@@ -707,7 +727,7 @@ mod tests {
agent_private_key: "private-key".to_string(),
account_id: "account-id".to_string(),
chatgpt_user_id: "user-id".to_string(),
email: "user@example.com".to_string(),
email: Some("user@example.com".to_string()),
plan_type: AuthPlanType::Known(KnownPlan::Pro),
chatgpt_account_is_fedramp: false,
};
@@ -739,7 +759,7 @@ mod tests {
agent_private_key: "private-key".to_string(),
account_id: "account-id".to_string(),
chatgpt_user_id: "user-id".to_string(),
email: "user@example.com".to_string(),
email: Some("user@example.com".to_string()),
plan_type: AuthPlanType::Known(KnownPlan::Pro),
chatgpt_account_is_fedramp: false,
};
+310 -88
View File
@@ -62,6 +62,10 @@ use crate::facts::HookRunInput;
use crate::facts::InputError;
use crate::facts::InvocationType;
use crate::facts::PluginInstallFailedInput;
use crate::facts::PluginInstallRequestSource;
use crate::facts::PluginInstallRequested;
use crate::facts::PluginInstallRequestedInput;
use crate::facts::PluginInstallRequestedPlugin;
use crate::facts::PluginState;
use crate::facts::PluginStateChangedInput;
use crate::facts::PluginUsedInput;
@@ -168,6 +172,17 @@ use std::sync::Arc;
use std::sync::Mutex;
use tokio::sync::mpsc;
const TEST_PRODUCT_CLIENT_ID: &str = "codex_work_desktop";
fn test_tracking_context(thread_id: &str, turn_id: &str) -> TrackEventsContext {
TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: thread_id.to_string(),
turn_id: turn_id.to_string(),
product_client_id: TEST_PRODUCT_CLIENT_ID.to_string(),
}
}
fn sample_thread_with_metadata(
thread_id: &str,
ephemeral: bool,
@@ -177,11 +192,13 @@ fn sample_thread_with_metadata(
) -> Thread {
Thread {
id: thread_id.to_string(),
extra: None,
session_id: format!("session-{thread_id}"),
forked_from_id: None,
parent_thread_id,
preview: "first prompt".to_string(),
ephemeral,
history_mode: Default::default(),
model_provider: "openai".to_string(),
created_at: 1,
updated_at: 2,
@@ -219,7 +236,7 @@ fn sample_thread_start_response(
cwd: test_path_buf("/tmp").abs(),
runtime_workspace_roots: Vec::new(),
instruction_sources: Vec::new(),
approval_policy: AppServerAskForApproval::OnFailure,
approval_policy: AppServerAskForApproval::OnRequest,
approvals_reviewer: AppServerApprovalsReviewer::User,
sandbox: AppServerSandboxPolicy::DangerFullAccess,
active_permission_profile: None,
@@ -284,7 +301,7 @@ fn sample_thread_resume_response_with_source(
cwd: test_path_buf("/tmp").abs(),
runtime_workspace_roots: Vec::new(),
instruction_sources: Vec::new(),
approval_policy: AppServerAskForApproval::OnFailure,
approval_policy: AppServerAskForApproval::OnRequest,
approvals_reviewer: AppServerApprovalsReviewer::User,
sandbox: AppServerSandboxPolicy::DangerFullAccess,
active_permission_profile: None,
@@ -542,6 +559,7 @@ async fn ingest_rejected_turn_steer(
response: Box::new(sample_thread_resume_response(
"thread-2", /*ephemeral*/ false, "gpt-5",
)),
thread_originator: None,
},
out,
)
@@ -615,6 +633,7 @@ async fn ingest_turn_prerequisites(
response: Box::new(sample_thread_start_response(
"thread-2", /*ephemeral*/ false, "gpt-5",
)),
thread_originator: None,
},
out,
)
@@ -638,6 +657,7 @@ async fn ingest_turn_prerequisites(
connection_id: 7,
request_id: RequestId::Integer(3),
response: Box::new(sample_turn_start_response("turn-2")),
thread_originator: None,
},
out,
)
@@ -704,6 +724,7 @@ async fn ingest_review_prerequisites(
response: Box::new(sample_thread_start_response(
"thread-1", /*ephemeral*/ false, "gpt-5",
)),
thread_originator: None,
},
events,
)
@@ -1023,11 +1044,7 @@ fn normalize_path_for_skill_id_repo_root_not_in_skill_path_uses_absolute_path()
#[test]
fn app_mentioned_event_serializes_expected_shape() {
let tracking = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
};
let tracking = test_tracking_context("thread-1", "turn-1");
let event = TrackEventRequest::AppMentioned(CodexAppMentionedEventRequest {
event_type: "codex_app_mentioned",
event_params: codex_app_metadata(
@@ -1051,7 +1068,7 @@ fn app_mentioned_event_serializes_expected_shape() {
"thread_id": "thread-1",
"turn_id": "turn-1",
"app_name": "Calendar",
"product_client_id": originator().value,
"product_client_id": TEST_PRODUCT_CLIENT_ID,
"invoke_type": "explicit",
"model_slug": "gpt-5"
}
@@ -1061,11 +1078,7 @@ fn app_mentioned_event_serializes_expected_shape() {
#[test]
fn app_used_event_serializes_expected_shape() {
let tracking = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-2".to_string(),
turn_id: "turn-2".to_string(),
};
let tracking = test_tracking_context("thread-2", "turn-2");
let event = TrackEventRequest::AppUsed(CodexAppUsedEventRequest {
event_type: "codex_app_used",
event_params: codex_app_metadata(
@@ -1089,7 +1102,7 @@ fn app_used_event_serializes_expected_shape() {
"thread_id": "thread-2",
"turn_id": "turn-2",
"app_name": "Google Drive",
"product_client_id": originator().value,
"product_client_id": TEST_PRODUCT_CLIENT_ID,
"invoke_type": "implicit",
"model_slug": "gpt-5"
}
@@ -1380,16 +1393,8 @@ fn app_used_dedupe_is_keyed_by_turn_and_connector() {
invocation_type: Some(InvocationType::Implicit),
};
let turn_1 = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
};
let turn_2 = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-2".to_string(),
};
let turn_1 = test_tracking_context("thread-1", "turn-1");
let turn_2 = test_tracking_context("thread-1", "turn-2");
assert_eq!(queue.should_enqueue_app_used(&turn_1, &app), true);
assert_eq!(queue.should_enqueue_app_used(&turn_1, &app), false);
@@ -1652,6 +1657,7 @@ async fn initialize_caches_client_and_thread_lifecycle_publishes_once_initialize
/*ephemeral*/ false,
"gpt-5",
)),
thread_originator: None,
},
&mut events,
)
@@ -1697,6 +1703,7 @@ async fn initialize_caches_client_and_thread_lifecycle_publishes_once_initialize
response: Box::new(sample_thread_resume_response(
"thread-1", /*ephemeral*/ true, "gpt-5",
)),
thread_originator: None,
},
&mut events,
)
@@ -1741,6 +1748,157 @@ async fn initialize_caches_client_and_thread_lifecycle_publishes_once_initialize
);
}
#[tokio::test]
async fn thread_originator_overrides_shared_connection_across_thread_events() {
let mut reducer = AnalyticsReducer::default();
let mut events = Vec::new();
reducer
.ingest(sample_initialize_fact(/*connection_id*/ 7), &mut events)
.await;
for (request_id, thread_id, thread_originator) in [
(1, "thread-work", Some(TEST_PRODUCT_CLIENT_ID.to_string())),
(2, "thread-default", None),
] {
reducer
.ingest(
AnalyticsFact::ClientResponse {
connection_id: 7,
request_id: RequestId::Integer(request_id),
response: Box::new(sample_thread_start_response(
thread_id, /*ephemeral*/ false, "gpt-5",
)),
thread_originator,
},
&mut events,
)
.await;
}
let initialized = serde_json::to_value(&events).expect("serialize thread events");
assert_eq!(
initialized
.as_array()
.expect("thread events")
.iter()
.map(|event| {
json!({
"thread_id": event["event_params"]["thread_id"],
"app_server_client": event["event_params"]["app_server_client"],
})
})
.collect::<Vec<_>>(),
vec![
json!({
"thread_id": "thread-work",
"app_server_client": {
"product_client_id": TEST_PRODUCT_CLIENT_ID,
"client_name": "codex-tui",
"client_version": "1.0.0",
"rpc_transport": "websocket",
"experimental_api_enabled": false,
},
}),
json!({
"thread_id": "thread-default",
"app_server_client": {
"product_client_id": DEFAULT_ORIGINATOR,
"client_name": "codex-tui",
"client_version": "1.0.0",
"rpc_transport": "websocket",
"experimental_api_enabled": false,
},
}),
]
);
events.clear();
reducer
.ingest(
AnalyticsFact::ClientRequest {
connection_id: 7,
request_id: RequestId::Integer(3),
request: Box::new(sample_turn_start_request(
"thread-work",
/*request_id*/ 3,
)),
},
&mut events,
)
.await;
reducer
.ingest(
AnalyticsFact::ClientResponse {
connection_id: 7,
request_id: RequestId::Integer(3),
response: Box::new(sample_turn_start_response("turn-1")),
thread_originator: None,
},
&mut events,
)
.await;
ingest_completed_command_execution_item(&mut reducer, &mut events, "thread-work", "item-work")
.await;
ingest_complete_child_turn(&mut reducer, &mut events, "thread-work", "turn-1").await;
reducer
.ingest(
AnalyticsFact::Custom(CustomAnalyticsFact::Compaction(Box::new(
CodexCompactionEvent {
thread_id: "thread-work".to_string(),
turn_id: "turn-compact".to_string(),
trigger: CompactionTrigger::Manual,
reason: CompactionReason::UserRequested,
implementation: CompactionImplementation::Responses,
phase: CompactionPhase::StandaloneTurn,
strategy: CompactionStrategy::Memento,
status: CompactionStatus::Completed,
codex_error_kind: None,
codex_error_http_status_code: None,
active_context_tokens_before: 131_000,
active_context_tokens_after: 64_000,
retained_image_count: None,
compaction_summary_tokens: None,
cached_input_tokens: None,
started_at: 100,
completed_at: 101,
duration_ms: Some(1200),
},
))),
&mut events,
)
.await;
let lifecycle = serde_json::to_value(&events).expect("serialize lifecycle events");
assert_eq!(
lifecycle
.as_array()
.expect("lifecycle events")
.iter()
.map(|event| {
json!({
"event_type": event["event_type"],
"product_client_id":
event["event_params"]["app_server_client"]["product_client_id"],
})
})
.collect::<Vec<_>>(),
vec![
json!({
"event_type": "codex_command_execution_event",
"product_client_id": TEST_PRODUCT_CLIENT_ID,
}),
json!({
"event_type": "codex_turn_event",
"product_client_id": TEST_PRODUCT_CLIENT_ID,
}),
json!({
"event_type": "codex_compaction_event",
"product_client_id": TEST_PRODUCT_CLIENT_ID,
}),
]
);
}
#[tokio::test]
async fn unrelated_client_requests_are_ignored_by_reducer() {
let mut reducer = AnalyticsReducer::default();
@@ -1767,6 +1925,7 @@ async fn unrelated_client_requests_are_ignored_by_reducer() {
connection_id: 7,
request_id: RequestId::Integer(3),
response: Box::new(sample_turn_start_response("turn-2")),
thread_originator: None,
},
&mut events,
)
@@ -1792,6 +1951,7 @@ async fn unrelated_client_responses_are_ignored_by_reducer() {
response: Box::new(ClientResponsePayload::ThreadArchive(
ThreadArchiveResponse {},
)),
thread_originator: None,
},
&mut events,
)
@@ -1851,6 +2011,7 @@ async fn compaction_event_ingests_custom_fact() {
Some(AppServerThreadSource::Subagent),
Some(parent_thread_id.to_string()),
)),
thread_originator: None,
},
&mut events,
)
@@ -1971,6 +2132,7 @@ async fn guardian_review_event_ingests_custom_fact_with_optional_target_item() {
/*ephemeral*/ false,
"gpt-5",
)),
thread_originator: None,
},
&mut events,
)
@@ -2499,6 +2661,7 @@ async fn item_review_summaries_do_not_cross_threads_with_reused_item_ids() {
response: Box::new(sample_thread_start_response(
"thread-2", /*ephemeral*/ false, "gpt-5",
)),
thread_originator: None,
},
&mut events,
)
@@ -2749,7 +2912,7 @@ async fn subagent_thread_started_publishes_without_initialize() {
}
#[tokio::test]
async fn subagent_events_use_inherited_connection_unless_turn_connection_is_explicit() {
async fn subagent_events_keep_thread_originator_with_explicit_turn_connection() {
let mut reducer = AnalyticsReducer::default();
let mut events = Vec::new();
let parent_thread_id =
@@ -2786,6 +2949,7 @@ async fn subagent_events_use_inherited_connection_unless_turn_connection_is_expl
/*ephemeral*/ false,
"gpt-5",
)),
thread_originator: None,
},
&mut events,
)
@@ -2908,6 +3072,7 @@ async fn subagent_events_use_inherited_connection_unless_turn_connection_is_expl
connection_id: 8,
request_id: RequestId::Integer(3),
response: Box::new(sample_turn_start_response("turn-explicit")),
thread_originator: None,
},
&mut events,
)
@@ -2918,7 +3083,11 @@ async fn subagent_events_use_inherited_connection_unless_turn_connection_is_expl
};
assert_eq!(
event.event_params.app_server_client.product_client_id,
DEFAULT_ORIGINATOR
"parent-client"
);
assert_eq!(
event.event_params.app_server_client.client_name.as_deref(),
Some("codex-tui")
);
}
@@ -3008,11 +3177,7 @@ async fn subagent_tool_items_inherit_parent_connection_metadata() {
#[test]
fn plugin_used_event_serializes_expected_shape() {
let tracking = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-3".to_string(),
turn_id: "turn-3".to_string(),
};
let tracking = test_tracking_context("thread-3", "turn-3");
let event = TrackEventRequest::PluginUsed(CodexPluginUsedEventRequest {
event_type: "codex_plugin_used",
event_params: codex_plugin_used_metadata(&tracking, sample_plugin_metadata()),
@@ -3026,12 +3191,13 @@ fn plugin_used_event_serializes_expected_shape() {
"event_type": "codex_plugin_used",
"event_params": {
"plugin_id": "sample@test",
"remote_plugin_id": null,
"plugin_name": "sample",
"marketplace_name": "test",
"has_skills": true,
"mcp_server_count": 2,
"connector_ids": ["calendar", "drive"],
"product_client_id": originator().value,
"product_client_id": TEST_PRODUCT_CLIENT_ID,
"mcp_server_names": ["mcp-1", "mcp-2"],
"thread_id": "thread-3",
"turn_id": "turn-3",
@@ -3056,6 +3222,7 @@ fn plugin_management_event_serializes_expected_shape() {
"event_type": "codex_plugin_installed",
"event_params": {
"plugin_id": "sample@test",
"remote_plugin_id": null,
"plugin_name": "sample",
"marketplace_name": "test",
"has_skills": true,
@@ -3085,6 +3252,7 @@ fn plugin_install_failed_event_serializes_expected_shape() {
"event_type": "codex_plugin_install_failed",
"event_params": {
"plugin_id": "sample@test",
"remote_plugin_id": null,
"plugin_name": "sample",
"marketplace_name": "test",
"has_skills": true,
@@ -3098,7 +3266,7 @@ fn plugin_install_failed_event_serializes_expected_shape() {
}
#[test]
fn plugin_management_event_can_use_remote_plugin_id_override() {
fn plugin_management_event_keeps_plugin_id_local_when_remote_id_exists() {
let mut plugin = sample_plugin_metadata();
plugin.remote_plugin_id = Some("plugins~Plugin_remote".to_string());
let event = TrackEventRequest::PluginInstalled(CodexPluginEventRequest {
@@ -3109,20 +3277,26 @@ fn plugin_management_event_can_use_remote_plugin_id_override() {
let payload = serde_json::to_value(&event).expect("serialize plugin installed event");
assert_eq!(
payload["event_params"]["plugin_id"],
"plugins~Plugin_remote"
payload,
json!({
"event_type": "codex_plugin_installed",
"event_params": {
"plugin_id": "sample@test",
"remote_plugin_id": "plugins~Plugin_remote",
"plugin_name": "sample",
"marketplace_name": "test",
"has_skills": true,
"mcp_server_count": 2,
"connector_ids": ["calendar", "drive"],
"product_client_id": originator().value
}
})
);
assert_eq!(payload["event_params"]["plugin_name"], "sample");
assert_eq!(payload["event_params"]["marketplace_name"], "test");
}
#[test]
fn hook_run_event_serializes_expected_shape() {
let tracking = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-3".to_string(),
turn_id: "turn-3".to_string(),
};
let tracking = test_tracking_context("thread-3", "turn-3");
let event = TrackEventRequest::HookRun(CodexHookRunEventRequest {
event_type: "codex_hook_run",
event_params: codex_hook_run_metadata(
@@ -3144,6 +3318,7 @@ fn hook_run_event_serializes_expected_shape() {
"event_params": {
"thread_id": "thread-3",
"turn_id": "turn-3",
"product_client_id": TEST_PRODUCT_CLIENT_ID,
"model_slug": "gpt-5",
"hook_name": "PreToolUse",
"hook_source": "user",
@@ -3155,11 +3330,7 @@ fn hook_run_event_serializes_expected_shape() {
#[test]
fn hook_run_metadata_maps_sources_and_statuses() {
let tracking = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
};
let tracking = test_tracking_context("thread-1", "turn-1");
let system = serde_json::to_value(codex_hook_run_metadata(
&tracking,
@@ -3210,11 +3381,7 @@ fn hook_run_metadata_maps_sources_and_statuses() {
#[test]
fn hook_run_metadata_maps_stopped_status() {
let tracking = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
};
let tracking = test_tracking_context("thread-1", "turn-1");
let stopped = serde_json::to_value(codex_hook_run_metadata(
&tracking,
@@ -3240,16 +3407,8 @@ fn plugin_used_dedupe_is_keyed_by_turn_and_plugin() {
};
let plugin = sample_plugin_metadata();
let turn_1 = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
};
let turn_2 = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-2".to_string(),
};
let turn_1 = test_tracking_context("thread-1", "turn-1");
let turn_2 = test_tracking_context("thread-1", "turn-2");
assert_eq!(queue.should_enqueue_plugin_used(&turn_1, &plugin), true);
assert_eq!(queue.should_enqueue_plugin_used(&turn_1, &plugin), false);
@@ -3260,11 +3419,7 @@ fn plugin_used_dedupe_is_keyed_by_turn_and_plugin() {
async fn reducer_ingests_skill_invoked_fact() {
let mut reducer = AnalyticsReducer::default();
let mut events = Vec::new();
let tracking = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
};
let tracking = test_tracking_context("thread-1", "turn-1");
let skill_path = PathBuf::from("/Users/abc/.codex/skills/doc/SKILL.md");
let expected_skill_id = skill_id_for_local_skill(
/*repo_url*/ None,
@@ -3297,7 +3452,7 @@ async fn reducer_ingests_skill_invoked_fact() {
"skill_id": expected_skill_id,
"skill_name": "doc",
"event_params": {
"product_client_id": originator().value,
"product_client_id": TEST_PRODUCT_CLIENT_ID,
"skill_scope": "user",
"plugin_id": null,
"repo_url": null,
@@ -3314,11 +3469,7 @@ async fn reducer_ingests_skill_invoked_fact() {
async fn reducer_includes_plugin_id_for_plugin_skill_invocations() {
let mut reducer = AnalyticsReducer::default();
let mut events = Vec::new();
let tracking = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
};
let tracking = test_tracking_context("thread-1", "turn-1");
let skill_path =
PathBuf::from("/Users/abc/.codex/plugins/cache/test/sample/skills/doc/SKILL.md");
@@ -3353,11 +3504,7 @@ async fn reducer_ingests_hook_run_fact() {
reducer
.ingest(
AnalyticsFact::Custom(CustomAnalyticsFact::HookRun(HookRunInput {
tracking: TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
},
tracking: test_tracking_context("thread-1", "turn-1"),
hook: HookRunFact {
event_name: HookEventName::PostToolUse,
hook_source: HookSource::Unknown,
@@ -3380,11 +3527,7 @@ async fn reducer_ingests_hook_run_fact() {
async fn reducer_ingests_app_and_plugin_facts() {
let mut reducer = AnalyticsReducer::default();
let mut events = Vec::new();
let tracking = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
};
let tracking = test_tracking_context("thread-1", "turn-1");
reducer
.ingest(
@@ -3427,6 +3570,18 @@ async fn reducer_ingests_app_and_plugin_facts() {
assert_eq!(payload[0]["event_type"], "codex_app_mentioned");
assert_eq!(payload[1]["event_type"], "codex_app_used");
assert_eq!(payload[2]["event_type"], "codex_plugin_used");
assert_eq!(
payload[0]["event_params"]["product_client_id"],
TEST_PRODUCT_CLIENT_ID
);
assert_eq!(
payload[1]["event_params"]["product_client_id"],
TEST_PRODUCT_CLIENT_ID
);
assert_eq!(
payload[2]["event_params"]["product_client_id"],
TEST_PRODUCT_CLIENT_ID
);
}
#[tokio::test]
@@ -3453,6 +3608,7 @@ async fn reducer_ingests_plugin_state_changed_fact() {
"event_type": "codex_plugin_disabled",
"event_params": {
"plugin_id": "sample@test",
"remote_plugin_id": null,
"plugin_name": "sample",
"marketplace_name": "test",
"has_skills": true,
@@ -3464,6 +3620,66 @@ async fn reducer_ingests_plugin_state_changed_fact() {
);
}
#[tokio::test]
async fn reducer_ingests_plugin_install_requested_fact() {
let mut reducer = AnalyticsReducer::default();
let mut events = Vec::new();
let tracking = test_tracking_context("thread-1", "turn-1");
let request = PluginInstallRequested {
suggestion_id: "request_plugin_install_call-1".to_string(),
plugins: vec![
PluginInstallRequestedPlugin {
plugin_id: "calendar@openai-curated-remote".to_string(),
remote_plugin_id: Some("plugin_calendar".to_string()),
plugin_name: "Calendar".to_string(),
connector_ids: vec!["connector_calendar".to_string()],
},
PluginInstallRequestedPlugin {
plugin_id: "github@openai-curated-remote".to_string(),
remote_plugin_id: None,
plugin_name: "GitHub".to_string(),
connector_ids: vec!["connector_github".to_string()],
},
],
source: PluginInstallRequestSource::EndpointRecommendation,
};
reducer
.ingest(
AnalyticsFact::Custom(CustomAnalyticsFact::PluginInstallRequested(
PluginInstallRequestedInput { tracking, request },
)),
&mut events,
)
.await;
assert_eq!(
serde_json::to_value(&events).expect("serialize events"),
json!([{
"event_type": "codex_plugin_install_requested",
"event_params": {
"suggestion_id": "request_plugin_install_call-1",
"plugins": [{
"plugin_id": "calendar@openai-curated-remote",
"remote_plugin_id": "plugin_calendar",
"plugin_name": "Calendar",
"connector_ids": ["connector_calendar"],
}, {
"plugin_id": "github@openai-curated-remote",
"remote_plugin_id": null,
"plugin_name": "GitHub",
"connector_ids": ["connector_github"],
}],
"source": "endpoint_recommendation",
"thread_id": "thread-1",
"turn_id": "turn-1",
"model_slug": "gpt-5",
"product_client_id": originator().value,
}
}])
);
}
#[tokio::test]
async fn reducer_ingests_plugin_install_failed_fact() {
let mut reducer = AnalyticsReducer::default();
@@ -3488,6 +3704,7 @@ async fn reducer_ingests_plugin_install_failed_fact() {
"event_type": "codex_plugin_install_failed",
"event_params": {
"plugin_id": "sample@test",
"remote_plugin_id": null,
"plugin_name": "sample",
"marketplace_name": "test",
"has_skills": true,
@@ -3505,7 +3722,7 @@ async fn reducer_ingests_plugin_install_failed_fact_without_detail() {
let mut reducer = AnalyticsReducer::default();
let mut events = Vec::new();
let plugin = PluginTelemetryMetadata {
plugin_id: PluginId::parse("unknown@openai-curated-remote").expect("valid plugin id"),
plugin_id: None,
remote_plugin_id: Some("plugins~Plugin_00000000000000000000000000000000".to_string()),
capability_summary: None,
};
@@ -3528,9 +3745,10 @@ async fn reducer_ingests_plugin_install_failed_fact_without_detail() {
json!([{
"event_type": "codex_plugin_install_failed",
"event_params": {
"plugin_id": "plugins~Plugin_00000000000000000000000000000000",
"plugin_name": "unknown",
"marketplace_name": "openai-curated-remote",
"plugin_id": null,
"remote_plugin_id": "plugins~Plugin_00000000000000000000000000000000",
"plugin_name": null,
"marketplace_name": null,
"has_skills": null,
"mcp_server_count": null,
"connector_ids": null,
@@ -3819,6 +4037,7 @@ async fn accepted_turn_steer_emits_expected_event() {
connection_id: 7,
request_id: RequestId::Integer(4),
response: Box::new(sample_turn_steer_response("turn-2")),
thread_originator: None,
},
&mut out,
)
@@ -3990,6 +4209,7 @@ async fn turn_start_error_response_discards_pending_start_request() {
connection_id: 7,
request_id: RequestId::Integer(3),
response: Box::new(sample_turn_start_response("turn-2")),
thread_originator: None,
},
&mut out,
)
@@ -4318,6 +4538,7 @@ async fn accepted_steers_increment_turn_steer_count() {
connection_id: 7,
request_id: RequestId::Integer(4),
response: Box::new(sample_turn_steer_response("turn-2")),
thread_originator: None,
},
&mut out,
)
@@ -4365,6 +4586,7 @@ async fn accepted_steers_increment_turn_steer_count() {
connection_id: 7,
request_id: RequestId::Integer(6),
response: Box::new(sample_turn_steer_response("turn-2")),
thread_originator: None,
},
&mut out,
)
@@ -4569,7 +4791,7 @@ async fn turn_completed_without_started_notification_emits_null_started_at() {
fn sample_plugin_metadata() -> PluginTelemetryMetadata {
PluginTelemetryMetadata {
plugin_id: PluginId::parse("sample@test").expect("valid plugin id"),
plugin_id: Some(PluginId::parse("sample@test").expect("valid plugin id")),
remote_plugin_id: None,
capability_summary: Some(PluginCapabilitySummary {
config_name: "sample@test".to_string(),
+51 -1
View File
@@ -16,6 +16,8 @@ use crate::facts::ExternalAgentConfigImportFailureInput;
use crate::facts::HookRunFact;
use crate::facts::HookRunInput;
use crate::facts::PluginInstallFailedInput;
use crate::facts::PluginInstallRequested;
use crate::facts::PluginInstallRequestedInput;
use crate::facts::PluginState;
use crate::facts::PluginStateChangedInput;
use crate::facts::SkillInvocation;
@@ -38,6 +40,7 @@ use codex_app_server_protocol::ServerResponse;
use codex_login::AuthManager;
use codex_login::CodexAuth;
use codex_login::default_client::create_client;
use codex_plugin::PluginId;
use codex_plugin::PluginTelemetryMetadata;
use codex_protocol::request_permissions::RequestPermissionsResponse;
use std::collections::HashSet;
@@ -173,7 +176,15 @@ impl AnalyticsEventsQueue {
if emitted.len() >= ANALYTICS_EVENT_DEDUPE_MAX_KEYS {
emitted.clear();
}
emitted.insert((tracking.turn_id.clone(), plugin.plugin_id.as_key()))
let Some(plugin_id) = plugin
.plugin_id
.as_ref()
.map(PluginId::as_key)
.or_else(|| plugin.remote_plugin_id.clone())
else {
return true;
};
emitted.insert((tracking.turn_id.clone(), plugin_id))
}
}
@@ -301,6 +312,19 @@ impl AnalyticsEventsClient {
)));
}
pub fn track_plugin_install_requested(
&self,
tracking: TrackEventsContext,
request: PluginInstallRequested,
) {
self.record_fact(AnalyticsFact::Custom(
CustomAnalyticsFact::PluginInstallRequested(PluginInstallRequestedInput {
tracking,
request,
}),
));
}
pub fn track_compaction(&self, event: crate::facts::CodexCompactionEvent) {
self.record_fact(AnalyticsFact::Custom(CustomAnalyticsFact::Compaction(
Box::new(event),
@@ -411,6 +435,31 @@ impl AnalyticsEventsClient {
connection_id: u64,
request_id: RequestId,
response: ClientResponsePayload,
) {
self.track_response_inner(
connection_id,
request_id,
response,
/*thread_originator*/ None,
);
}
pub fn track_response_with_thread_originator(
&self,
connection_id: u64,
request_id: RequestId,
response: ClientResponsePayload,
thread_originator: String,
) {
self.track_response_inner(connection_id, request_id, response, Some(thread_originator));
}
fn track_response_inner(
&self,
connection_id: u64,
request_id: RequestId,
response: ClientResponsePayload,
thread_originator: Option<String>,
) {
if !matches!(
response,
@@ -426,6 +475,7 @@ impl AnalyticsEventsClient {
connection_id,
request_id,
response: Box::new(response),
thread_originator,
});
}
+5 -3
View File
@@ -277,11 +277,13 @@ fn sample_thread_archive_request() -> ClientRequest {
fn sample_thread(thread_id: &str) -> Thread {
Thread {
id: thread_id.to_string(),
extra: None,
session_id: format!("session-{thread_id}"),
forked_from_id: None,
parent_thread_id: None,
preview: "first prompt".to_string(),
ephemeral: false,
history_mode: Default::default(),
model_provider: "openai".to_string(),
created_at: 1,
updated_at: 2,
@@ -309,7 +311,7 @@ fn sample_thread_start_response() -> ClientResponsePayload {
cwd: test_path_buf("/tmp").abs(),
runtime_workspace_roots: Vec::new(),
instruction_sources: Vec::new(),
approval_policy: AppServerAskForApproval::OnFailure,
approval_policy: AppServerAskForApproval::OnRequest,
approvals_reviewer: AppServerApprovalsReviewer::User,
sandbox: AppServerSandboxPolicy::DangerFullAccess,
active_permission_profile: None,
@@ -327,7 +329,7 @@ fn sample_thread_resume_response() -> ClientResponsePayload {
cwd: test_path_buf("/tmp").abs(),
runtime_workspace_roots: Vec::new(),
instruction_sources: Vec::new(),
approval_policy: AppServerAskForApproval::OnFailure,
approval_policy: AppServerAskForApproval::OnRequest,
approvals_reviewer: AppServerApprovalsReviewer::User,
sandbox: AppServerSandboxPolicy::DangerFullAccess,
active_permission_profile: None,
@@ -346,7 +348,7 @@ fn sample_thread_fork_response() -> ClientResponsePayload {
cwd: test_path_buf("/tmp").abs(),
runtime_workspace_roots: Vec::new(),
instruction_sources: Vec::new(),
approval_policy: AppServerAskForApproval::OnFailure,
approval_policy: AppServerAskForApproval::OnRequest,
approvals_reviewer: AppServerApprovalsReviewer::User,
sandbox: AppServerSandboxPolicy::DangerFullAccess,
active_permission_profile: None,
+73 -6
View File
@@ -14,6 +14,7 @@ use crate::facts::CompactionTrigger;
use crate::facts::GoalEventKind;
use crate::facts::HookRunFact;
use crate::facts::InvocationType;
use crate::facts::PluginInstallRequested;
use crate::facts::PluginState;
use crate::facts::SubAgentThreadStartedInput;
use crate::facts::ThreadInitializationMode;
@@ -26,6 +27,7 @@ use crate::now_unix_millis;
use codex_app_server_protocol::CodexErrorInfo;
use codex_app_server_protocol::CommandExecutionSource;
use codex_login::default_client::originator;
use codex_plugin::PluginId;
use codex_plugin::PluginTelemetryMetadata;
use codex_protocol::approvals::NetworkApprovalProtocol;
use codex_protocol::models::AdditionalPermissionProfile;
@@ -79,6 +81,7 @@ pub(crate) enum TrackEventRequest {
#[allow(dead_code)]
ReviewEvent(CodexReviewEventRequest),
PluginUsed(CodexPluginUsedEventRequest),
PluginInstallRequested(CodexPluginInstallRequestedEventRequest),
PluginInstalled(CodexPluginEventRequest),
PluginUninstalled(CodexPluginEventRequest),
PluginEnabled(CodexPluginEventRequest),
@@ -772,6 +775,7 @@ pub(crate) struct CodexAppUsedEventRequest {
pub(crate) struct CodexHookRunMetadata {
pub(crate) thread_id: Option<String>,
pub(crate) turn_id: Option<String>,
pub(crate) product_client_id: Option<String>,
pub(crate) model_slug: Option<String>,
pub(crate) hook_name: Option<String>,
pub(crate) hook_source: Option<&'static str>,
@@ -933,6 +937,7 @@ pub(crate) struct CodexTurnSteerEventRequest {
#[derive(Serialize)]
pub(crate) struct CodexPluginMetadata {
pub(crate) plugin_id: Option<String>,
pub(crate) remote_plugin_id: Option<String>,
pub(crate) plugin_name: Option<String>,
pub(crate) marketplace_name: Option<String>,
pub(crate) has_skills: Option<bool>,
@@ -951,6 +956,31 @@ pub(crate) struct CodexPluginUsedMetadata {
pub(crate) model_slug: Option<String>,
}
#[derive(Serialize)]
pub(crate) struct CodexPluginInstallRequestedPluginMetadata {
pub(crate) plugin_id: String,
pub(crate) remote_plugin_id: Option<String>,
pub(crate) plugin_name: String,
pub(crate) connector_ids: Vec<String>,
}
#[derive(Serialize)]
pub(crate) struct CodexPluginInstallRequestedMetadata {
pub(crate) suggestion_id: String,
pub(crate) plugins: Vec<CodexPluginInstallRequestedPluginMetadata>,
pub(crate) source: crate::facts::PluginInstallRequestSource,
pub(crate) thread_id: String,
pub(crate) turn_id: String,
pub(crate) model_slug: String,
pub(crate) product_client_id: Option<String>,
}
#[derive(Serialize)]
pub(crate) struct CodexPluginInstallRequestedEventRequest {
pub(crate) event_type: &'static str,
pub(crate) event_params: CodexPluginInstallRequestedMetadata,
}
#[derive(Serialize)]
pub(crate) struct CodexPluginEventRequest {
pub(crate) event_type: &'static str,
@@ -1028,23 +1058,32 @@ pub(crate) fn codex_app_metadata(
thread_id: Some(tracking.thread_id.clone()),
turn_id: Some(tracking.turn_id.clone()),
app_name: app.app_name,
product_client_id: Some(originator().value),
product_client_id: Some(tracking.product_client_id.clone()),
invoke_type: app.invocation_type,
model_slug: Some(tracking.model_slug.clone()),
}
}
pub(crate) fn codex_plugin_metadata(plugin: PluginTelemetryMetadata) -> CodexPluginMetadata {
codex_plugin_metadata_with_product_client_id(plugin, originator().value)
}
fn codex_plugin_metadata_with_product_client_id(
plugin: PluginTelemetryMetadata,
product_client_id: String,
) -> CodexPluginMetadata {
let PluginTelemetryMetadata {
plugin_id,
remote_plugin_id,
capability_summary,
} = plugin;
let event_plugin_id = remote_plugin_id.unwrap_or_else(|| plugin_id.as_key());
CodexPluginMetadata {
plugin_id: Some(event_plugin_id),
plugin_name: Some(plugin_id.plugin_name),
marketplace_name: Some(plugin_id.marketplace_name),
plugin_id: plugin_id.as_ref().map(PluginId::as_key),
remote_plugin_id,
plugin_name: plugin_id
.as_ref()
.map(|plugin_id| plugin_id.plugin_name.clone()),
marketplace_name: plugin_id.map(|plugin_id| plugin_id.marketplace_name),
has_skills: capability_summary
.as_ref()
.map(|summary| summary.has_skills),
@@ -1058,6 +1097,30 @@ pub(crate) fn codex_plugin_metadata(plugin: PluginTelemetryMetadata) -> CodexPlu
.map(|connector_id| connector_id.0)
.collect()
}),
product_client_id: Some(product_client_id),
}
}
pub(crate) fn codex_plugin_install_requested_metadata(
tracking: &TrackEventsContext,
request: PluginInstallRequested,
) -> CodexPluginInstallRequestedMetadata {
CodexPluginInstallRequestedMetadata {
suggestion_id: request.suggestion_id,
plugins: request
.plugins
.into_iter()
.map(|plugin| CodexPluginInstallRequestedPluginMetadata {
plugin_id: plugin.plugin_id,
remote_plugin_id: plugin.remote_plugin_id,
plugin_name: plugin.plugin_name,
connector_ids: plugin.connector_ids,
})
.collect(),
source: request.source,
thread_id: tracking.thread_id.clone(),
turn_id: tracking.turn_id.clone(),
model_slug: tracking.model_slug.clone(),
product_client_id: Some(originator().value),
}
}
@@ -1135,7 +1198,10 @@ pub(crate) fn codex_plugin_used_metadata(
.as_ref()
.map(|summary| summary.mcp_server_names.clone());
CodexPluginUsedMetadata {
plugin: codex_plugin_metadata(plugin),
plugin: codex_plugin_metadata_with_product_client_id(
plugin,
tracking.product_client_id.clone(),
),
mcp_server_names,
thread_id: Some(tracking.thread_id.clone()),
turn_id: Some(tracking.turn_id.clone()),
@@ -1150,6 +1216,7 @@ pub(crate) fn codex_hook_run_metadata(
CodexHookRunMetadata {
thread_id: Some(tracking.thread_id.clone()),
turn_id: Some(tracking.turn_id.clone()),
product_client_id: Some(tracking.product_client_id.clone()),
model_slug: Some(tracking.model_slug.clone()),
hook_name: Some(analytics_hook_event_name(hook.event_name).to_owned()),
hook_source: Some(analytics_hook_source(hook.hook_source)),
+34
View File
@@ -41,17 +41,20 @@ pub struct TrackEventsContext {
pub model_slug: String,
pub thread_id: String,
pub turn_id: String,
pub product_client_id: String,
}
pub fn build_track_events_context(
model_slug: String,
thread_id: String,
turn_id: String,
product_client_id: String,
) -> TrackEventsContext {
TrackEventsContext {
model_slug,
thread_id,
turn_id,
product_client_id,
}
}
@@ -139,6 +142,7 @@ impl TurnCodexErrorFact {
#[serde(rename_all = "snake_case")]
pub enum CodexErrKind {
TurnAborted,
SessionBudgetExceeded,
Stream,
ContextWindowExceeded,
ThreadNotFound,
@@ -195,6 +199,7 @@ impl From<&CodexErr> for CodexErrKind {
fn from(error: &CodexErr) -> Self {
match error {
CodexErr::TurnAborted => CodexErrKind::TurnAborted,
CodexErr::SessionBudgetExceeded => CodexErrKind::SessionBudgetExceeded,
CodexErr::Stream(..) => CodexErrKind::Stream,
CodexErr::ContextWindowExceeded => CodexErrKind::ContextWindowExceeded,
CodexErr::ThreadNotFound(_) => CodexErrKind::ThreadNotFound,
@@ -459,6 +464,7 @@ pub(crate) enum AnalyticsFact {
connection_id: u64,
request_id: RequestId,
response: Box<ClientResponsePayload>,
thread_originator: Option<String>,
},
ErrorResponse {
connection_id: u64,
@@ -503,6 +509,7 @@ pub(crate) enum CustomAnalyticsFact {
AppUsed(AppUsedInput),
HookRun(HookRunInput),
PluginUsed(PluginUsedInput),
PluginInstallRequested(PluginInstallRequestedInput),
PluginStateChanged(PluginStateChangedInput),
PluginInstallFailed(PluginInstallFailedInput),
ExternalAgentConfigImportCompleted(ExternalAgentConfigImportCompletedInput),
@@ -540,6 +547,33 @@ pub(crate) struct PluginUsedInput {
pub plugin: PluginTelemetryMetadata,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PluginInstallRequestSource {
EndpointRecommendation,
LegacyDiscovery,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PluginInstallRequested {
pub suggestion_id: String,
pub plugins: Vec<PluginInstallRequestedPlugin>,
pub source: PluginInstallRequestSource,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PluginInstallRequestedPlugin {
pub plugin_id: String,
pub remote_plugin_id: Option<String>,
pub plugin_name: String,
pub connector_ids: Vec<String>,
}
pub(crate) struct PluginInstallRequestedInput {
pub tracking: TrackEventsContext,
pub request: PluginInstallRequested,
}
pub(crate) struct PluginStateChangedInput {
pub plugin: PluginTelemetryMetadata,
pub state: PluginState,
+3
View File
@@ -42,6 +42,9 @@ pub use facts::GoalEventKind;
pub use facts::HookRunFact;
pub use facts::InputError;
pub use facts::InvocationType;
pub use facts::PluginInstallRequestSource;
pub use facts::PluginInstallRequested;
pub use facts::PluginInstallRequestedPlugin;
pub use facts::SkillInvocation;
pub use facts::SubAgentThreadStartedInput;
pub use facts::ThreadInitializationMode;
+97 -39
View File
@@ -28,6 +28,7 @@ use crate::events::CodexOnboardingExternalAgentImportFailureMetadata;
use crate::events::CodexPluginEventRequest;
use crate::events::CodexPluginInstallFailedEventRequest;
use crate::events::CodexPluginInstallFailedMetadata;
use crate::events::CodexPluginInstallRequestedEventRequest;
use crate::events::CodexPluginUsedEventRequest;
use crate::events::CodexReviewEventParams;
use crate::events::CodexReviewEventRequest;
@@ -60,6 +61,7 @@ use crate::events::codex_app_metadata;
use crate::events::codex_compaction_event_params;
use crate::events::codex_goal_event_params;
use crate::events::codex_hook_run_metadata;
use crate::events::codex_plugin_install_requested_metadata;
use crate::events::codex_plugin_metadata;
use crate::events::codex_plugin_used_metadata;
use crate::events::plugin_state_event_type;
@@ -76,6 +78,7 @@ use crate::facts::ExternalAgentConfigImportCompletedInput;
use crate::facts::ExternalAgentConfigImportFailureInput;
use crate::facts::HookRunInput;
use crate::facts::PluginInstallFailedInput;
use crate::facts::PluginInstallRequestedInput;
use crate::facts::PluginState;
use crate::facts::PluginStateChangedInput;
use crate::facts::PluginUsedInput;
@@ -162,6 +165,20 @@ struct ConnectionState {
struct ThreadAnalyticsState {
connection_id: Option<u64>,
metadata: Option<ThreadMetadataState>,
originator: Option<String>,
}
impl ThreadAnalyticsState {
fn app_server_client(
&self,
connection_state: &ConnectionState,
) -> CodexAppServerClientMetadata {
let mut app_server_client = connection_state.app_server_client.clone();
if let Some(originator) = self.originator.as_ref() {
app_server_client.product_client_id.clone_from(originator);
}
app_server_client
}
}
#[derive(Clone, Copy)]
@@ -431,9 +448,11 @@ impl AnalyticsReducer {
connection_id,
request_id,
response,
thread_originator,
} => {
if let Some(response) = response.into_client_response(request_id) {
self.ingest_response(connection_id, response, out).await;
self.ingest_response(connection_id, response, thread_originator, out)
.await;
}
}
AnalyticsFact::ErrorResponse {
@@ -517,6 +536,9 @@ impl AnalyticsReducer {
CustomAnalyticsFact::PluginUsed(input) => {
self.ingest_plugin_used(input, out);
}
CustomAnalyticsFact::PluginInstallRequested(input) => {
self.ingest_plugin_install_requested(input, out);
}
CustomAnalyticsFact::PluginStateChanged(input) => {
self.ingest_plugin_state_changed(input, out);
}
@@ -569,6 +591,9 @@ impl AnalyticsReducer {
.and_then(|parent_thread_id| self.threads.get(parent_thread_id))
.and_then(|thread| thread.connection_id);
let thread_state = self.threads.entry(input.thread_id.clone()).or_default();
thread_state
.originator
.get_or_insert_with(|| input.product_client_id.clone());
thread_state
.metadata
.get_or_insert_with(|| ThreadMetadataState {
@@ -591,7 +616,7 @@ impl AnalyticsReducer {
input: GuardianReviewEventParams,
out: &mut Vec<TrackEventRequest>,
) {
let Some((connection_state, thread_metadata)) =
let Some((connection_state, thread_state, thread_metadata)) =
self.thread_context_or_warn(AnalyticsDropSite::guardian(&input))
else {
return;
@@ -601,7 +626,7 @@ impl AnalyticsReducer {
event_type: "codex_guardian_review",
event_params: GuardianReviewEventPayload {
session_id: thread_metadata.session_id.clone(),
app_server_client: connection_state.app_server_client.clone(),
app_server_client: thread_state.app_server_client(connection_state),
runtime: connection_state.runtime.clone(),
guardian_review: input,
},
@@ -729,7 +754,7 @@ impl AnalyticsReducer {
turn_id: Some(tracking.turn_id.clone()),
invoke_type: Some(invocation.invocation_type),
model_slug: Some(tracking.model_slug.clone()),
product_client_id: Some(originator().value),
product_client_id: Some(tracking.product_client_id.clone()),
repo_url,
skill_scope: Some(skill_scope.to_string()),
plugin_id: invocation.plugin_id,
@@ -775,6 +800,20 @@ impl AnalyticsReducer {
}));
}
fn ingest_plugin_install_requested(
&mut self,
input: PluginInstallRequestedInput,
out: &mut Vec<TrackEventRequest>,
) {
let PluginInstallRequestedInput { tracking, request } = input;
out.push(TrackEventRequest::PluginInstallRequested(
CodexPluginInstallRequestedEventRequest {
event_type: "codex_plugin_install_requested",
event_params: codex_plugin_install_requested_metadata(&tracking, request),
},
));
}
fn ingest_plugin_state_changed(
&mut self,
input: PluginStateChangedInput,
@@ -854,6 +893,7 @@ impl AnalyticsReducer {
&mut self,
connection_id: u64,
response: ClientResponse,
thread_originator: Option<String>,
out: &mut Vec<TrackEventRequest>,
) {
match response {
@@ -863,6 +903,7 @@ impl AnalyticsReducer {
response.thread,
response.model,
ThreadInitializationMode::New,
thread_originator,
out,
);
}
@@ -872,6 +913,7 @@ impl AnalyticsReducer {
response.thread,
response.model,
ThreadInitializationMode::Resumed,
thread_originator,
out,
);
}
@@ -881,6 +923,7 @@ impl AnalyticsReducer {
response.thread,
response.model,
ThreadInitializationMode::Forked,
thread_originator,
out,
);
}
@@ -1228,7 +1271,7 @@ impl AnalyticsReducer {
else {
return;
};
let Some((connection_state, thread_metadata)) = self
let Some((connection_state, thread_state, thread_metadata)) = self
.thread_context_or_warn(AnalyticsDropSite::tool_item(&notification, item_id))
else {
return;
@@ -1240,6 +1283,7 @@ impl AnalyticsReducer {
started_at_ms,
completed_at_ms,
connection_state,
thread_state,
thread_metadata,
review_summary: self.item_review_summaries.get(&key),
}) {
@@ -1296,6 +1340,7 @@ impl AnalyticsReducer {
thread: codex_app_server_protocol::Thread,
model: String,
initialization_mode: ThreadInitializationMode,
thread_originator: Option<String>,
out: &mut Vec<TrackEventRequest>,
) {
let session_source: SessionSource = thread.source.into();
@@ -1313,20 +1358,20 @@ impl AnalyticsReducer {
parent_thread_id,
initialization_mode,
);
self.threads.insert(
thread_id.clone(),
ThreadAnalyticsState {
connection_id: Some(connection_id),
metadata: Some(thread_metadata.clone()),
},
);
let thread_state = self.threads.entry(thread_id.clone()).or_default();
if let Some(originator) = thread_originator {
thread_state.originator = Some(originator);
}
thread_state.connection_id = Some(connection_id);
thread_state.metadata = Some(thread_metadata.clone());
let app_server_client = thread_state.app_server_client(connection_state);
out.push(TrackEventRequest::ThreadInitialized(
ThreadInitializedEvent {
event_type: "codex_thread_initialized",
event_params: ThreadInitializedEventParams {
thread_id,
session_id,
app_server_client: connection_state.app_server_client.clone(),
app_server_client,
runtime: connection_state.runtime.clone(),
model,
ephemeral: thread.ephemeral,
@@ -1342,7 +1387,7 @@ impl AnalyticsReducer {
}
fn ingest_compaction(&mut self, input: CodexCompactionEvent, out: &mut Vec<TrackEventRequest>) {
let Some((connection_state, thread_metadata)) =
let Some((connection_state, thread_state, thread_metadata)) =
self.thread_context_or_warn(AnalyticsDropSite::compaction(&input))
else {
return;
@@ -1353,7 +1398,7 @@ impl AnalyticsReducer {
event_params: codex_compaction_event_params(
input,
thread_metadata.session_id.clone(),
connection_state.app_server_client.clone(),
thread_state.app_server_client(connection_state),
connection_state.runtime.clone(),
thread_metadata.thread_source.clone(),
thread_metadata.subagent_source.clone(),
@@ -1364,7 +1409,7 @@ impl AnalyticsReducer {
}
fn ingest_goal(&mut self, input: CodexGoalEvent, out: &mut Vec<TrackEventRequest>) {
let Some((connection_state, thread_metadata)) =
let Some((connection_state, thread_state, thread_metadata)) =
self.thread_context_or_warn(AnalyticsDropSite::goal(&input))
else {
return;
@@ -1374,7 +1419,7 @@ impl AnalyticsReducer {
event_params: codex_goal_event_params(
input,
thread_metadata.session_id.clone(),
connection_state.app_server_client.clone(),
thread_state.app_server_client(connection_state),
connection_state.runtime.clone(),
thread_metadata.thread_source.clone(),
thread_metadata.subagent_source.clone(),
@@ -1463,11 +1508,11 @@ impl AnalyticsReducer {
return;
};
let drop_site = AnalyticsDropSite::turn_steer(&pending_request.thread_id);
let Some(thread_metadata) = self
.threads
.get(drop_site.thread_id)
.and_then(|thread| thread.metadata.as_ref())
else {
let Some(thread_state) = self.threads.get(drop_site.thread_id) else {
warn_missing_analytics_context(&drop_site, MissingAnalyticsContext::ThreadMetadata);
return;
};
let Some(thread_metadata) = thread_state.metadata.as_ref() else {
warn_missing_analytics_context(&drop_site, MissingAnalyticsContext::ThreadMetadata);
return;
};
@@ -1478,7 +1523,7 @@ impl AnalyticsReducer {
session_id: thread_metadata.session_id.clone(),
expected_turn_id: Some(pending_request.expected_turn_id),
accepted_turn_id,
app_server_client: connection_state.app_server_client.clone(),
app_server_client: thread_state.app_server_client(connection_state),
runtime: connection_state.runtime.clone(),
thread_source: thread_metadata.thread_source.clone(),
subagent_source: thread_metadata.subagent_source.clone(),
@@ -1509,7 +1554,7 @@ impl AnalyticsReducer {
&pending_review,
);
}
let Some((connection_state, thread_metadata)) =
let Some((connection_state, thread_state, thread_metadata)) =
self.thread_context_or_warn(AnalyticsDropSite::review(&pending_review))
else {
return;
@@ -1521,7 +1566,7 @@ impl AnalyticsReducer {
turn_id: pending_review.turn_id,
item_id: pending_review.item_id,
review_id: pending_review.review_id,
app_server_client: connection_state.app_server_client.clone(),
app_server_client: thread_state.app_server_client(connection_state),
runtime: connection_state.runtime.clone(),
thread_source: thread_metadata.thread_source.clone(),
subagent_source: thread_metadata.subagent_source.clone(),
@@ -1590,18 +1635,18 @@ impl AnalyticsReducer {
);
return;
};
let Some(thread_metadata) = self
.threads
.get(drop_site.thread_id)
.and_then(|thread| thread.metadata.as_ref())
else {
let Some(thread_state) = self.threads.get(drop_site.thread_id) else {
warn_missing_analytics_context(&drop_site, MissingAnalyticsContext::ThreadMetadata);
return;
};
let Some(thread_metadata) = thread_state.metadata.as_ref() else {
warn_missing_analytics_context(&drop_site, MissingAnalyticsContext::ThreadMetadata);
return;
};
let turn_event = TrackEventRequest::TurnEvent(Box::new(CodexTurnEventRequest {
event_type: "codex_turn_event",
event_params: codex_turn_event_params(
connection_state.app_server_client.clone(),
thread_state.app_server_client(connection_state),
connection_state.runtime.clone(),
turn_id.to_string(),
turn_state,
@@ -1643,17 +1688,18 @@ impl AnalyticsReducer {
fn thread_context_or_warn(
&self,
drop_site: AnalyticsDropSite<'_>,
) -> Option<(&ConnectionState, &ThreadMetadataState)> {
) -> Option<(
&ConnectionState,
&ThreadAnalyticsState,
&ThreadMetadataState,
)> {
let connection_state = self.thread_connection_or_warn(drop_site)?;
let Some(thread_metadata) = self
.threads
.get(drop_site.thread_id)
.and_then(|thread| thread.metadata.as_ref())
else {
let thread_state = self.threads.get(drop_site.thread_id)?;
let Some(thread_metadata) = thread_state.metadata.as_ref() else {
warn_missing_analytics_context(&drop_site, MissingAnalyticsContext::ThreadMetadata);
return None;
};
Some((connection_state, thread_metadata))
Some((connection_state, thread_state, thread_metadata))
}
}
@@ -1723,6 +1769,7 @@ struct ToolItemEventInput<'a> {
started_at_ms: u64,
completed_at_ms: u64,
connection_state: &'a ConnectionState,
thread_state: &'a ThreadAnalyticsState,
thread_metadata: &'a ThreadMetadataState,
review_summary: Option<&'a ItemReviewSummary>,
}
@@ -1735,6 +1782,7 @@ fn tool_item_event(input: ToolItemEventInput<'_>) -> Option<TrackEventRequest> {
started_at_ms,
completed_at_ms,
connection_state,
thread_state,
thread_metadata,
review_summary,
} = input;
@@ -1764,6 +1812,7 @@ fn tool_item_event(input: ToolItemEventInput<'_>) -> Option<TrackEventRequest> {
started_at_ms,
completed_at_ms,
connection_state,
thread_state,
thread_metadata,
review_summary,
},
@@ -1805,6 +1854,7 @@ fn tool_item_event(input: ToolItemEventInput<'_>) -> Option<TrackEventRequest> {
started_at_ms,
completed_at_ms,
connection_state,
thread_state,
thread_metadata,
review_summary,
},
@@ -1846,6 +1896,7 @@ fn tool_item_event(input: ToolItemEventInput<'_>) -> Option<TrackEventRequest> {
started_at_ms,
completed_at_ms,
connection_state,
thread_state,
thread_metadata,
review_summary,
},
@@ -1890,6 +1941,7 @@ fn tool_item_event(input: ToolItemEventInput<'_>) -> Option<TrackEventRequest> {
started_at_ms,
completed_at_ms,
connection_state,
thread_state,
thread_metadata,
review_summary,
},
@@ -1934,6 +1986,7 @@ fn tool_item_event(input: ToolItemEventInput<'_>) -> Option<TrackEventRequest> {
started_at_ms,
completed_at_ms,
connection_state,
thread_state,
thread_metadata,
review_summary,
},
@@ -1989,6 +2042,7 @@ fn tool_item_event(input: ToolItemEventInput<'_>) -> Option<TrackEventRequest> {
started_at_ms,
completed_at_ms,
connection_state,
thread_state,
thread_metadata,
review_summary,
},
@@ -2025,6 +2079,7 @@ fn tool_item_event(input: ToolItemEventInput<'_>) -> Option<TrackEventRequest> {
started_at_ms,
completed_at_ms,
connection_state,
thread_state,
thread_metadata,
review_summary,
},
@@ -2080,6 +2135,7 @@ struct ToolItemContext<'a> {
started_at_ms: u64,
completed_at_ms: u64,
connection_state: &'a ConnectionState,
thread_state: &'a ThreadAnalyticsState,
thread_metadata: &'a ThreadMetadataState,
review_summary: Option<&'a ItemReviewSummary>,
}
@@ -2098,7 +2154,9 @@ fn tool_item_base(
thread_id: thread_id.to_string(),
turn_id: turn_id.to_string(),
item_id,
app_server_client: context.connection_state.app_server_client.clone(),
app_server_client: context
.thread_state
.app_server_client(context.connection_state),
runtime: context.connection_state.runtime.clone(),
thread_source: thread_metadata.thread_source.clone(),
subagent_source: thread_metadata.subagent_source.clone(),
+8
View File
@@ -15,6 +15,7 @@ use anyhow::anyhow;
pub use backend::BackendKind;
use backend::BackendPaths;
use codex_app_server_protocol::RemoteControlConnectionStatus;
use codex_app_server_protocol::RemoteControlPairingStartResponse;
use codex_app_server_transport::app_server_control_socket_path;
use codex_utils_home_dir::find_codex_home;
use managed_install::managed_codex_bin;
@@ -225,6 +226,13 @@ pub async fn enable_remote_control_on_socket(
.await
}
/// Starts a manual pairing session through an already-running daemon app-server.
pub async fn start_remote_control_pairing() -> Result<RemoteControlPairingStartResponse> {
ensure_supported_platform()?;
let daemon = Daemon::from_environment()?;
remote_control_client::start_pairing(&daemon.socket_path).await
}
pub async fn set_remote_control(mode: RemoteControlMode) -> Result<RemoteControlOutput> {
ensure_supported_platform()?;
Daemon::from_environment()?.set_remote_control(mode).await
@@ -12,6 +12,8 @@ use codex_app_server_protocol::RemoteControlDisableParams;
use codex_app_server_protocol::RemoteControlDisableResponse;
use codex_app_server_protocol::RemoteControlEnableParams;
use codex_app_server_protocol::RemoteControlEnableResponse;
use codex_app_server_protocol::RemoteControlPairingStartParams;
use codex_app_server_protocol::RemoteControlPairingStartResponse;
use codex_app_server_protocol::RemoteControlStatusChangedNotification;
use codex_app_server_protocol::RequestId;
use serde::de::DeserializeOwned;
@@ -53,6 +55,35 @@ pub(crate) async fn disable_remote_control(socket_path: &Path) -> Result<RemoteC
Ok(RemoteControlReadyStatus::from(response))
}
pub(crate) async fn start_pairing(socket_path: &Path) -> Result<RemoteControlPairingStartResponse> {
let mut websocket = client::connect(socket_path).await?;
initialize_client(&mut websocket).await?;
let params = serde_json::to_value(RemoteControlPairingStartParams { manual_code: true })?;
send_remote_control_request(
&mut websocket,
REMOTE_CONTROL_REQUEST_ID.clone(),
"remoteControl/pairing/start",
Some(params),
)
.await?;
let response = match read_remote_control_response(
&mut websocket,
&REMOTE_CONTROL_REQUEST_ID,
"remoteControl/pairing/start",
)
.await?
{
RemoteControlRpcResponse::Success(response) => response,
RemoteControlRpcResponse::InvalidParams => {
return Err(anyhow!(
"remoteControl/pairing/start rejected manual pairing parameters"
));
}
};
websocket.close(None).await.ok();
Ok(response)
}
pub(crate) async fn enable_remote_control_with_connect_retry(
socket_path: &Path,
connect_timeout: Duration,
@@ -538,6 +569,53 @@ mod tests {
Ok(())
}
#[tokio::test]
async fn start_pairing_requests_manual_code() -> Result<()> {
let dir = TempDir::new()?;
let socket_path = dir.path().join("app-server.sock");
let listener = UnixListener::bind(&socket_path).await?;
let server_task = tokio::spawn(async move {
let mut websocket = accept_initialized_client(listener).await?;
let pairing = client::read_message(&mut websocket).await?;
let JSONRPCMessage::Request(pairing) = pairing else {
panic!("expected remoteControl/pairing/start request");
};
assert_eq!(pairing.id, REMOTE_CONTROL_REQUEST_ID);
assert_eq!(pairing.method, "remoteControl/pairing/start");
assert_eq!(
pairing.params,
Some(serde_json::json!({ "manualCode": true }))
);
client::send_message(
&mut websocket,
&JSONRPCMessage::Response(JSONRPCResponse {
id: REMOTE_CONTROL_REQUEST_ID,
result: serde_json::to_value(RemoteControlPairingStartResponse {
pairing_code: "pairing-code".to_string(),
manual_pairing_code: Some("ABCD-EFGH".to_string()),
environment_id: "env_test".to_string(),
expires_at: 1_700_000_000,
})?,
}),
)
.await?;
Ok::<_, anyhow::Error>(())
});
let response = start_pairing(&socket_path).await?;
server_task.await??;
assert_eq!(
response,
RemoteControlPairingStartResponse {
pairing_code: "pairing-code".to_string(),
manual_pairing_code: Some("ABCD-EFGH".to_string()),
environment_id: "env_test".to_string(),
expires_at: 1_700_000_000,
}
);
Ok(())
}
struct EnableScenario {
initial_notification: Option<RemoteControlStatusChangedNotification>,
enable_response: RemoteControlStatusChangedNotification,
+46 -11
View File
@@ -125,7 +125,6 @@
{
"enum": [
"untrusted",
"on-failure",
"on-request",
"never"
],
@@ -210,6 +209,7 @@
"type": "string"
},
"path": {
"description": "Absolute path for the root in the selected environment.",
"type": "string"
},
"type": {
@@ -1619,6 +1619,12 @@
"null"
]
},
"threadId": {
"type": [
"string",
"null"
]
},
"timeoutSecs": {
"format": "int64",
"type": [
@@ -1723,6 +1729,13 @@
},
"type": "array"
},
"skills": {
"default": [],
"items": {
"$ref": "#/definitions/SkillMigration"
},
"type": "array"
},
"subagents": {
"default": [],
"items": {
@@ -2670,6 +2683,12 @@
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"status": {
"type": [
"string",
@@ -2922,16 +2941,6 @@
},
{
"properties": {
"internal_chat_message_metadata_passthrough": {
"anyOf": [
{
"$ref": "#/definitions/InternalChatMessageMetadataPassthrough"
},
{
"type": "null"
}
]
},
"type": {
"enum": [
"compaction_trigger"
@@ -3417,6 +3426,17 @@
],
"type": "object"
},
"SkillMigration": {
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"SkillsConfigWriteParams": {
"properties": {
"enabled": {
@@ -3617,6 +3637,13 @@
"ephemeral": {
"type": "boolean"
},
"lastTurnId": {
"description": "Optional last turn id to fork through, inclusive.\n\nWhen specified, turns after `last_turn_id` are omitted from the fork. The referenced turn cannot be in progress.",
"type": [
"string",
"null"
]
},
"model": {
"description": "Configuration overrides for the forked thread, if any.",
"type": [
@@ -3733,6 +3760,13 @@
],
"type": "string"
},
"ThreadHistoryMode": {
"enum": [
"legacy",
"paginated"
],
"type": "string"
},
"ThreadInjectItemsParams": {
"properties": {
"items": {
@@ -4160,6 +4194,7 @@
"type": "object"
},
"ThreadRollbackParams": {
"description": "DEPRECATED: `thread/rollback` will be removed soon.",
"properties": {
"numTurns": {
"description": "The number of turns to drop from the end of the thread. Must be >= 1.\n\nThis only modifies the thread's history and does not revert local file changes that have been made by the agent. Clients are responsible for reverting these changes.",
@@ -241,6 +241,24 @@
"null"
]
},
"iconAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"iconDarkAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"id": {
"type": "string"
},
@@ -450,7 +468,6 @@
{
"enum": [
"untrusted",
"on-failure",
"on-request",
"never"
],
@@ -574,6 +591,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -2352,6 +2370,12 @@
},
"success": {
"type": "boolean"
},
"threadId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -2360,6 +2384,12 @@
],
"type": "object"
},
"McpServerStartupFailureReason": {
"enum": [
"reauthenticationRequired"
],
"type": "string"
},
"McpServerStartupState": {
"enum": [
"starting",
@@ -2377,6 +2407,16 @@
"null"
]
},
"failureReason": {
"anyOf": [
{
"$ref": "#/definitions/McpServerStartupFailureReason"
},
{
"type": "null"
}
]
},
"name": {
"type": "string"
},
@@ -2398,6 +2438,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -2412,6 +2464,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -2585,6 +2643,12 @@
},
"ModelSafetyBufferingUpdatedNotification": {
"properties": {
"fasterModel": {
"type": [
"string",
"null"
]
},
"model": {
"type": "string"
},
@@ -2594,6 +2658,9 @@
},
"type": "array"
},
"showBufferingUi": {
"type": "boolean"
},
"threadId": {
"type": "string"
},
@@ -2610,6 +2677,7 @@
"required": [
"model",
"reasons",
"showBufferingUi",
"threadId",
"turnId",
"useCases"
@@ -3616,6 +3684,7 @@
"description": "Optional Git metadata captured when the thread was created."
},
"id": {
"description": "Identifier for this thread. Codex-generated thread IDs are UUIDv7.",
"type": "string"
},
"modelProvider": {
@@ -3755,6 +3824,10 @@
],
"type": "object"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadGoal": {
"properties": {
"createdAt": {
@@ -3844,6 +3917,13 @@
],
"type": "object"
},
"ThreadHistoryMode": {
"enum": [
"legacy",
"paginated"
],
"type": "string"
},
"ThreadId": {
"type": "string"
},
@@ -4430,7 +4510,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -5101,6 +5181,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -5900,7 +5900,10 @@
{
"properties": {
"email": {
"type": "string"
"type": [
"string",
"null"
]
},
"planType": {
"$ref": "#/definitions/v2/PlanType"
@@ -6403,6 +6406,24 @@
"null"
]
},
"iconAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"iconDarkAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"id": {
"type": "string"
},
@@ -6861,7 +6882,6 @@
{
"enum": [
"untrusted",
"on-failure",
"on-request",
"never"
],
@@ -7041,6 +7061,7 @@
"type": "string"
},
"path": {
"description": "Absolute path for the root in the selected environment.",
"type": "string"
},
"type": {
@@ -7067,6 +7088,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -8392,6 +8414,16 @@
"object",
"null"
]
},
"models": {
"anyOf": [
{
"$ref": "#/definitions/v2/ModelsRequirements"
},
{
"type": "null"
}
]
}
},
"type": "object"
@@ -12004,6 +12036,12 @@
},
"success": {
"type": "boolean"
},
"threadId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -12028,6 +12066,12 @@
"null"
]
},
"threadId": {
"type": [
"string",
"null"
]
},
"timeoutSecs": {
"format": "int64",
"type": [
@@ -12060,6 +12104,12 @@
"title": "McpServerRefreshResponse",
"type": "object"
},
"McpServerStartupFailureReason": {
"enum": [
"reauthenticationRequired"
],
"type": "string"
},
"McpServerStartupState": {
"enum": [
"starting",
@@ -12131,6 +12181,16 @@
"null"
]
},
"failureReason": {
"anyOf": [
{
"$ref": "#/definitions/v2/McpServerStartupFailureReason"
},
{
"type": "null"
}
]
},
"name": {
"type": "string"
},
@@ -12198,6 +12258,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -12212,6 +12284,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -12388,6 +12466,13 @@
},
"type": "array"
},
"skills": {
"default": [],
"items": {
"$ref": "#/definitions/v2/SkillMigration"
},
"type": "array"
},
"subagents": {
"default": [],
"items": {
@@ -12639,6 +12724,12 @@
"ModelSafetyBufferingUpdatedNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"fasterModel": {
"type": [
"string",
"null"
]
},
"model": {
"type": "string"
},
@@ -12648,6 +12739,9 @@
},
"type": "array"
},
"showBufferingUi": {
"type": "boolean"
},
"threadId": {
"type": "string"
},
@@ -12664,6 +12758,7 @@
"required": [
"model",
"reasons",
"showBufferingUi",
"threadId",
"turnId",
"useCases"
@@ -12749,6 +12844,21 @@
"title": "ModelVerificationNotification",
"type": "object"
},
"ModelsRequirements": {
"properties": {
"newThread": {
"anyOf": [
{
"$ref": "#/definitions/v2/NewThreadModelDefaults"
},
{
"type": "null"
}
]
}
},
"type": "object"
},
"MultiAgentMode": {
"description": "Controls whether the model receives multi-agent delegation instructions and, when it does, whether it should only spawn sub-agents after an explicit user request or may delegate proactively when doing so would help. `none` leaves the multi-agent tools available without injecting delegation instructions.",
"enum": [
@@ -12896,6 +13006,33 @@
],
"type": "string"
},
"NewThreadModelDefaults": {
"properties": {
"model": {
"type": [
"string",
"null"
]
},
"modelReasoningEffort": {
"anyOf": [
{
"$ref": "#/definitions/v2/ReasoningEffort"
},
{
"type": "null"
}
]
},
"serviceTier": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"NonSteerableTurnKind": {
"enum": [
"review",
@@ -13042,6 +13179,10 @@
},
"PermissionProfileSummary": {
"properties": {
"allowed": {
"description": "Whether the effective requirements allow selecting this profile.",
"type": "boolean"
},
"description": {
"description": "Optional user-facing description for display in clients.",
"type": [
@@ -13055,6 +13196,7 @@
}
},
"required": [
"allowed",
"id"
],
"type": "object"
@@ -13399,6 +13541,17 @@
],
"description": "Local logo path, resolved from the installed plugin package."
},
"logoDark": {
"anyOf": [
{
"$ref": "#/definitions/v2/AbsolutePathBuf"
},
{
"type": "null"
}
],
"description": "Local dark-mode logo path, resolved from the installed plugin package."
},
"logoUrl": {
"description": "Remote logo URL from the plugin catalog.",
"type": [
@@ -13406,6 +13559,13 @@
"null"
]
},
"logoUrlDark": {
"description": "Remote dark-mode logo URL from the plugin catalog.",
"type": [
"string",
"null"
]
},
"longDescription": {
"type": [
"string",
@@ -14047,6 +14207,40 @@
"title": "GitPluginSource",
"type": "object"
},
{
"properties": {
"package": {
"type": "string"
},
"registry": {
"description": "Optional HTTPS registry URL. Authentication stays in the user's npm config.",
"type": [
"string",
"null"
]
},
"type": {
"enum": [
"npm"
],
"title": "NpmPluginSourceType",
"type": "string"
},
"version": {
"description": "Optional npm version or version range.",
"type": [
"string",
"null"
]
}
},
"required": [
"package",
"type"
],
"title": "NpmPluginSource",
"type": "object"
},
{
"description": "The plugin is available in the remote catalog. Download metadata is kept server-side and is not exposed through the app-server API.",
"properties": {
@@ -15316,6 +15510,12 @@
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"status": {
"type": [
"string",
@@ -15568,16 +15768,6 @@
},
{
"properties": {
"internal_chat_message_metadata_passthrough": {
"anyOf": [
{
"$ref": "#/definitions/v2/InternalChatMessageMetadataPassthrough"
},
{
"type": "null"
}
]
},
"type": {
"enum": [
"compaction_trigger"
@@ -16311,6 +16501,17 @@
],
"type": "object"
},
"SkillMigration": {
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"SkillScope": {
"enum": [
"user",
@@ -16805,6 +17006,7 @@
"description": "Optional Git metadata captured when the thread was created."
},
"id": {
"description": "Identifier for this thread. Codex-generated thread IDs are UUIDv7.",
"type": "string"
},
"modelProvider": {
@@ -17026,6 +17228,10 @@
"title": "ThreadDeletedNotification",
"type": "object"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadForkParams": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "There are two ways to fork a thread: 1. By thread_id: load the thread from disk by thread_id and fork it into a new thread. 2. By path: load the thread from disk by path and fork it into a new thread.\n\nIf using a non-empty path, the thread_id param will be ignored. Empty string path values are treated as absent.\n\nPrefer using thread_id whenever possible.",
@@ -17079,6 +17285,13 @@
"ephemeral": {
"type": "boolean"
},
"lastTurnId": {
"description": "Optional last turn id to fork through, inclusive.\n\nWhen specified, turns after `last_turn_id` are omitted from the fork. The referenced turn cannot be in progress.",
"type": [
"string",
"null"
]
},
"model": {
"description": "Configuration overrides for the forked thread, if any.",
"type": [
@@ -17398,6 +17611,13 @@
"title": "ThreadGoalUpdatedNotification",
"type": "object"
},
"ThreadHistoryMode": {
"enum": [
"legacy",
"paginated"
],
"type": "string"
},
"ThreadId": {
"type": "string"
},
@@ -18008,7 +18228,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/v2/AbsolutePathBuf"
"$ref": "#/definitions/v2/LegacyAppPathString"
},
"type": {
"enum": [
@@ -18917,6 +19137,7 @@
},
"ThreadRollbackParams": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "DEPRECATED: `thread/rollback` will be removed soon.",
"properties": {
"numTurns": {
"description": "The number of turns to drop from the end of the thread. Must be >= 1.\n\nThis only modifies the thread's history and does not revert local file changes that have been made by the agent. Clients are responsible for reverting these changes.",
@@ -19673,6 +19894,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -26,7 +26,10 @@
{
"properties": {
"email": {
"type": "string"
"type": [
"string",
"null"
]
},
"planType": {
"$ref": "#/definitions/PlanType"
@@ -529,6 +532,24 @@
"null"
]
},
"iconAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"iconDarkAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"id": {
"type": "string"
},
@@ -987,7 +1008,6 @@
{
"enum": [
"untrusted",
"on-failure",
"on-request",
"never"
],
@@ -1167,6 +1187,7 @@
"type": "string"
},
"path": {
"description": "Absolute path for the root in the selected environment.",
"type": "string"
},
"type": {
@@ -3307,6 +3328,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -4632,6 +4654,16 @@
"object",
"null"
]
},
"models": {
"anyOf": [
{
"$ref": "#/definitions/ModelsRequirements"
},
{
"type": "null"
}
]
}
},
"type": "object"
@@ -8408,6 +8440,12 @@
},
"success": {
"type": "boolean"
},
"threadId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -8432,6 +8470,12 @@
"null"
]
},
"threadId": {
"type": [
"string",
"null"
]
},
"timeoutSecs": {
"format": "int64",
"type": [
@@ -8464,6 +8508,12 @@
"title": "McpServerRefreshResponse",
"type": "object"
},
"McpServerStartupFailureReason": {
"enum": [
"reauthenticationRequired"
],
"type": "string"
},
"McpServerStartupState": {
"enum": [
"starting",
@@ -8535,6 +8585,16 @@
"null"
]
},
"failureReason": {
"anyOf": [
{
"$ref": "#/definitions/McpServerStartupFailureReason"
},
{
"type": "null"
}
]
},
"name": {
"type": "string"
},
@@ -8602,6 +8662,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -8616,6 +8688,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -8792,6 +8870,13 @@
},
"type": "array"
},
"skills": {
"default": [],
"items": {
"$ref": "#/definitions/SkillMigration"
},
"type": "array"
},
"subagents": {
"default": [],
"items": {
@@ -9043,6 +9128,12 @@
"ModelSafetyBufferingUpdatedNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"fasterModel": {
"type": [
"string",
"null"
]
},
"model": {
"type": "string"
},
@@ -9052,6 +9143,9 @@
},
"type": "array"
},
"showBufferingUi": {
"type": "boolean"
},
"threadId": {
"type": "string"
},
@@ -9068,6 +9162,7 @@
"required": [
"model",
"reasons",
"showBufferingUi",
"threadId",
"turnId",
"useCases"
@@ -9153,6 +9248,21 @@
"title": "ModelVerificationNotification",
"type": "object"
},
"ModelsRequirements": {
"properties": {
"newThread": {
"anyOf": [
{
"$ref": "#/definitions/NewThreadModelDefaults"
},
{
"type": "null"
}
]
}
},
"type": "object"
},
"MultiAgentMode": {
"description": "Controls whether the model receives multi-agent delegation instructions and, when it does, whether it should only spawn sub-agents after an explicit user request or may delegate proactively when doing so would help. `none` leaves the multi-agent tools available without injecting delegation instructions.",
"enum": [
@@ -9300,6 +9410,33 @@
],
"type": "string"
},
"NewThreadModelDefaults": {
"properties": {
"model": {
"type": [
"string",
"null"
]
},
"modelReasoningEffort": {
"anyOf": [
{
"$ref": "#/definitions/ReasoningEffort"
},
{
"type": "null"
}
]
},
"serviceTier": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"NonSteerableTurnKind": {
"enum": [
"review",
@@ -9446,6 +9583,10 @@
},
"PermissionProfileSummary": {
"properties": {
"allowed": {
"description": "Whether the effective requirements allow selecting this profile.",
"type": "boolean"
},
"description": {
"description": "Optional user-facing description for display in clients.",
"type": [
@@ -9459,6 +9600,7 @@
}
},
"required": [
"allowed",
"id"
],
"type": "object"
@@ -9803,6 +9945,17 @@
],
"description": "Local logo path, resolved from the installed plugin package."
},
"logoDark": {
"anyOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
},
{
"type": "null"
}
],
"description": "Local dark-mode logo path, resolved from the installed plugin package."
},
"logoUrl": {
"description": "Remote logo URL from the plugin catalog.",
"type": [
@@ -9810,6 +9963,13 @@
"null"
]
},
"logoUrlDark": {
"description": "Remote dark-mode logo URL from the plugin catalog.",
"type": [
"string",
"null"
]
},
"longDescription": {
"type": [
"string",
@@ -10451,6 +10611,40 @@
"title": "GitPluginSource",
"type": "object"
},
{
"properties": {
"package": {
"type": "string"
},
"registry": {
"description": "Optional HTTPS registry URL. Authentication stays in the user's npm config.",
"type": [
"string",
"null"
]
},
"type": {
"enum": [
"npm"
],
"title": "NpmPluginSourceType",
"type": "string"
},
"version": {
"description": "Optional npm version or version range.",
"type": [
"string",
"null"
]
}
},
"required": [
"package",
"type"
],
"title": "NpmPluginSource",
"type": "object"
},
{
"description": "The plugin is available in the remote catalog. Download metadata is kept server-side and is not exposed through the app-server API.",
"properties": {
@@ -11720,6 +11914,12 @@
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"status": {
"type": [
"string",
@@ -11972,16 +12172,6 @@
},
{
"properties": {
"internal_chat_message_metadata_passthrough": {
"anyOf": [
{
"$ref": "#/definitions/InternalChatMessageMetadataPassthrough"
},
{
"type": "null"
}
]
},
"type": {
"enum": [
"compaction_trigger"
@@ -14090,6 +14280,17 @@
],
"type": "object"
},
"SkillMigration": {
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"SkillScope": {
"enum": [
"user",
@@ -14584,6 +14785,7 @@
"description": "Optional Git metadata captured when the thread was created."
},
"id": {
"description": "Identifier for this thread. Codex-generated thread IDs are UUIDv7.",
"type": "string"
},
"modelProvider": {
@@ -14805,6 +15007,10 @@
"title": "ThreadDeletedNotification",
"type": "object"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadForkParams": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "There are two ways to fork a thread: 1. By thread_id: load the thread from disk by thread_id and fork it into a new thread. 2. By path: load the thread from disk by path and fork it into a new thread.\n\nIf using a non-empty path, the thread_id param will be ignored. Empty string path values are treated as absent.\n\nPrefer using thread_id whenever possible.",
@@ -14858,6 +15064,13 @@
"ephemeral": {
"type": "boolean"
},
"lastTurnId": {
"description": "Optional last turn id to fork through, inclusive.\n\nWhen specified, turns after `last_turn_id` are omitted from the fork. The referenced turn cannot be in progress.",
"type": [
"string",
"null"
]
},
"model": {
"description": "Configuration overrides for the forked thread, if any.",
"type": [
@@ -15177,6 +15390,13 @@
"title": "ThreadGoalUpdatedNotification",
"type": "object"
},
"ThreadHistoryMode": {
"enum": [
"legacy",
"paginated"
],
"type": "string"
},
"ThreadId": {
"type": "string"
},
@@ -15787,7 +16007,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -16696,6 +16916,7 @@
},
"ThreadRollbackParams": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "DEPRECATED: `thread/rollback` will be removed soon.",
"properties": {
"numTurns": {
"description": "The number of turns to drop from the end of the thread. Must be >= 1.\n\nThis only modifies the thread's history and does not revert local file changes that have been made by the agent. Clients are responsible for reverting these changes.",
@@ -17452,6 +17673,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -78,6 +78,24 @@
"null"
]
},
"iconAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"iconDarkAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"id": {
"type": "string"
},
@@ -78,6 +78,24 @@
"null"
]
},
"iconAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"iconDarkAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"id": {
"type": "string"
},
@@ -173,7 +173,6 @@
{
"enum": [
"untrusted",
"on-failure",
"on-request",
"never"
],
@@ -15,7 +15,6 @@
{
"enum": [
"untrusted",
"on-failure",
"on-request",
"never"
],
@@ -170,6 +169,16 @@
"object",
"null"
]
},
"models": {
"anyOf": [
{
"$ref": "#/definitions/ModelsRequirements"
},
{
"type": "null"
}
]
}
},
"type": "object"
@@ -363,6 +372,21 @@
],
"type": "object"
},
"ModelsRequirements": {
"properties": {
"newThread": {
"anyOf": [
{
"$ref": "#/definitions/NewThreadModelDefaults"
},
{
"type": "null"
}
]
}
},
"type": "object"
},
"NetworkDomainPermission": {
"enum": [
"allow",
@@ -485,6 +509,38 @@
],
"type": "string"
},
"NewThreadModelDefaults": {
"properties": {
"model": {
"type": [
"string",
"null"
]
},
"modelReasoningEffort": {
"anyOf": [
{
"$ref": "#/definitions/ReasoningEffort"
},
{
"type": "null"
}
]
},
"serviceTier": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"ReasoningEffort": {
"description": "A non-empty reasoning effort value advertised by the model.",
"minLength": 1,
"type": "string"
},
"ResidencyRequirement": {
"enum": [
"us"
@@ -7,6 +7,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -117,6 +117,13 @@
},
"type": "array"
},
"skills": {
"default": [],
"items": {
"$ref": "#/definitions/SkillMigration"
},
"type": "array"
},
"subagents": {
"default": [],
"items": {
@@ -166,6 +173,17 @@
],
"type": "object"
},
"SkillMigration": {
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"SubagentMigration": {
"properties": {
"name": {
@@ -117,6 +117,13 @@
},
"type": "array"
},
"skills": {
"default": [],
"items": {
"$ref": "#/definitions/SkillMigration"
},
"type": "array"
},
"subagents": {
"default": [],
"items": {
@@ -166,6 +173,17 @@
],
"type": "object"
},
"SkillMigration": {
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"SubagentMigration": {
"properties": {
"name": {
@@ -22,7 +22,10 @@
{
"properties": {
"email": {
"type": "string"
"type": [
"string",
"null"
]
},
"planType": {
"$ref": "#/definitions/PlanType"
@@ -299,6 +299,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -313,6 +325,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -1106,7 +1124,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -299,6 +299,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -313,6 +325,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -1106,7 +1124,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -12,6 +12,12 @@
},
"success": {
"type": "boolean"
},
"threadId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -13,6 +13,12 @@
"null"
]
},
"threadId": {
"type": [
"string",
"null"
]
},
"timeoutSecs": {
"format": "int64",
"type": [
@@ -1,6 +1,12 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"McpServerStartupFailureReason": {
"enum": [
"reauthenticationRequired"
],
"type": "string"
},
"McpServerStartupState": {
"enum": [
"starting",
@@ -18,6 +24,16 @@
"null"
]
},
"failureReason": {
"anyOf": [
{
"$ref": "#/definitions/McpServerStartupFailureReason"
},
{
"type": "null"
}
]
},
"name": {
"type": "string"
},
@@ -1,6 +1,12 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"fasterModel": {
"type": [
"string",
"null"
]
},
"model": {
"type": "string"
},
@@ -10,6 +16,9 @@
},
"type": "array"
},
"showBufferingUi": {
"type": "boolean"
},
"threadId": {
"type": "string"
},
@@ -26,6 +35,7 @@
"required": [
"model",
"reasons",
"showBufferingUi",
"threadId",
"turnId",
"useCases"
@@ -3,6 +3,10 @@
"definitions": {
"PermissionProfileSummary": {
"properties": {
"allowed": {
"description": "Whether the effective requirements allow selecting this profile.",
"type": "boolean"
},
"description": {
"description": "Optional user-facing description for display in clients.",
"type": [
@@ -16,6 +20,7 @@
}
},
"required": [
"allowed",
"id"
],
"type": "object"
@@ -134,6 +134,17 @@
],
"description": "Local logo path, resolved from the installed plugin package."
},
"logoDark": {
"anyOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
},
{
"type": "null"
}
],
"description": "Local dark-mode logo path, resolved from the installed plugin package."
},
"logoUrl": {
"description": "Remote logo URL from the plugin catalog.",
"type": [
@@ -141,6 +152,13 @@
"null"
]
},
"logoUrlDark": {
"description": "Remote dark-mode logo URL from the plugin catalog.",
"type": [
"string",
"null"
]
},
"longDescription": {
"type": [
"string",
@@ -395,6 +413,40 @@
"title": "GitPluginSource",
"type": "object"
},
{
"properties": {
"package": {
"type": "string"
},
"registry": {
"description": "Optional HTTPS registry URL. Authentication stays in the user's npm config.",
"type": [
"string",
"null"
]
},
"type": {
"enum": [
"npm"
],
"title": "NpmPluginSourceType",
"type": "string"
},
"version": {
"description": "Optional npm version or version range.",
"type": [
"string",
"null"
]
}
},
"required": [
"package",
"type"
],
"title": "NpmPluginSource",
"type": "object"
},
{
"description": "The plugin is available in the remote catalog. Download metadata is kept server-side and is not exposed through the app-server API.",
"properties": {
@@ -134,6 +134,17 @@
],
"description": "Local logo path, resolved from the installed plugin package."
},
"logoDark": {
"anyOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
},
{
"type": "null"
}
],
"description": "Local dark-mode logo path, resolved from the installed plugin package."
},
"logoUrl": {
"description": "Remote logo URL from the plugin catalog.",
"type": [
@@ -141,6 +152,13 @@
"null"
]
},
"logoUrlDark": {
"description": "Remote dark-mode logo URL from the plugin catalog.",
"type": [
"string",
"null"
]
},
"longDescription": {
"type": [
"string",
@@ -395,6 +413,40 @@
"title": "GitPluginSource",
"type": "object"
},
{
"properties": {
"package": {
"type": "string"
},
"registry": {
"description": "Optional HTTPS registry URL. Authentication stays in the user's npm config.",
"type": [
"string",
"null"
]
},
"type": {
"enum": [
"npm"
],
"title": "NpmPluginSourceType",
"type": "string"
},
"version": {
"description": "Optional npm version or version range.",
"type": [
"string",
"null"
]
}
},
"required": [
"package",
"type"
],
"title": "NpmPluginSource",
"type": "object"
},
{
"description": "The plugin is available in the remote catalog. Download metadata is kept server-side and is not exposed through the app-server API.",
"properties": {
@@ -313,6 +313,17 @@
],
"description": "Local logo path, resolved from the installed plugin package."
},
"logoDark": {
"anyOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
},
{
"type": "null"
}
],
"description": "Local dark-mode logo path, resolved from the installed plugin package."
},
"logoUrl": {
"description": "Remote logo URL from the plugin catalog.",
"type": [
@@ -320,6 +331,13 @@
"null"
]
},
"logoUrlDark": {
"description": "Remote dark-mode logo URL from the plugin catalog.",
"type": [
"string",
"null"
]
},
"longDescription": {
"type": [
"string",
@@ -535,6 +553,40 @@
"title": "GitPluginSource",
"type": "object"
},
{
"properties": {
"package": {
"type": "string"
},
"registry": {
"description": "Optional HTTPS registry URL. Authentication stays in the user's npm config.",
"type": [
"string",
"null"
]
},
"type": {
"enum": [
"npm"
],
"title": "NpmPluginSourceType",
"type": "string"
},
"version": {
"description": "Optional npm version or version range.",
"type": [
"string",
"null"
]
}
},
"required": [
"package",
"type"
],
"title": "NpmPluginSource",
"type": "object"
},
{
"description": "The plugin is available in the remote catalog. Download metadata is kept server-side and is not exposed through the app-server API.",
"properties": {
@@ -108,6 +108,17 @@
],
"description": "Local logo path, resolved from the installed plugin package."
},
"logoDark": {
"anyOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
},
{
"type": "null"
}
],
"description": "Local dark-mode logo path, resolved from the installed plugin package."
},
"logoUrl": {
"description": "Remote logo URL from the plugin catalog.",
"type": [
@@ -115,6 +126,13 @@
"null"
]
},
"logoUrlDark": {
"description": "Remote dark-mode logo URL from the plugin catalog.",
"type": [
"string",
"null"
]
},
"longDescription": {
"type": [
"string",
@@ -351,6 +369,40 @@
"title": "GitPluginSource",
"type": "object"
},
{
"properties": {
"package": {
"type": "string"
},
"registry": {
"description": "Optional HTTPS registry URL. Authentication stays in the user's npm config.",
"type": [
"string",
"null"
]
},
"type": {
"enum": [
"npm"
],
"title": "NpmPluginSourceType",
"type": "string"
},
"version": {
"description": "Optional npm version or version range.",
"type": [
"string",
"null"
]
}
},
"required": [
"package",
"type"
],
"title": "NpmPluginSource",
"type": "object"
},
{
"description": "The plugin is available in the remote catalog. Download metadata is kept server-side and is not exposed through the app-server API.",
"properties": {
@@ -751,6 +751,12 @@
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"status": {
"type": [
"string",
@@ -1003,16 +1009,6 @@
},
{
"properties": {
"internal_chat_message_metadata_passthrough": {
"anyOf": [
{
"$ref": "#/definitions/InternalChatMessageMetadataPassthrough"
},
{
"type": "null"
}
]
},
"type": {
"enum": [
"compaction_trigger"
@@ -30,6 +30,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -436,6 +437,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -450,6 +463,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -1250,7 +1269,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -1438,6 +1457,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -19,7 +19,6 @@
{
"enum": [
"untrusted",
"on-failure",
"on-request",
"never"
],
@@ -127,6 +126,13 @@
"ephemeral": {
"type": "boolean"
},
"lastTurnId": {
"description": "Optional last turn id to fork through, inclusive.\n\nWhen specified, turns after `last_turn_id` are omitted from the fork. The referenced turn cannot be in progress.",
"type": [
"string",
"null"
]
},
"model": {
"description": "Configuration overrides for the forked thread, if any.",
"type": [
@@ -42,7 +42,6 @@
{
"enum": [
"untrusted",
"on-failure",
"on-request",
"never"
],
@@ -112,6 +111,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -541,6 +541,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -555,6 +567,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -1059,6 +1077,7 @@
"description": "Optional Git metadata captured when the thread was created."
},
"id": {
"description": "Identifier for this thread. Codex-generated thread IDs are UUIDv7.",
"type": "string"
},
"modelProvider": {
@@ -1165,6 +1184,17 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadHistoryMode": {
"enum": [
"legacy",
"paginated"
],
"type": "string"
},
"ThreadId": {
"type": "string"
},
@@ -1751,7 +1781,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -2017,6 +2047,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -33,6 +33,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -462,6 +463,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -476,6 +489,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -865,6 +884,7 @@
"description": "Optional Git metadata captured when the thread was created."
},
"id": {
"description": "Identifier for this thread. Codex-generated thread IDs are UUIDv7.",
"type": "string"
},
"modelProvider": {
@@ -971,6 +991,17 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadHistoryMode": {
"enum": [
"legacy",
"paginated"
],
"type": "string"
},
"ThreadId": {
"type": "string"
},
@@ -1557,7 +1588,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -1823,6 +1854,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -33,6 +33,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -462,6 +463,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -476,6 +489,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -865,6 +884,7 @@
"description": "Optional Git metadata captured when the thread was created."
},
"id": {
"description": "Identifier for this thread. Codex-generated thread IDs are UUIDv7.",
"type": "string"
},
"modelProvider": {
@@ -971,6 +991,17 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadHistoryMode": {
"enum": [
"legacy",
"paginated"
],
"type": "string"
},
"ThreadId": {
"type": "string"
},
@@ -1557,7 +1588,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -1823,6 +1854,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -33,6 +33,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -462,6 +463,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -476,6 +489,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -865,6 +884,7 @@
"description": "Optional Git metadata captured when the thread was created."
},
"id": {
"description": "Identifier for this thread. Codex-generated thread IDs are UUIDv7.",
"type": "string"
},
"modelProvider": {
@@ -971,6 +991,17 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadHistoryMode": {
"enum": [
"legacy",
"paginated"
],
"type": "string"
},
"ThreadId": {
"type": "string"
},
@@ -1557,7 +1588,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -1823,6 +1854,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -63,7 +63,6 @@
{
"enum": [
"untrusted",
"on-failure",
"on-request",
"never"
],
@@ -822,6 +821,12 @@
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"status": {
"type": [
"string",
@@ -1074,16 +1079,6 @@
},
{
"properties": {
"internal_chat_message_metadata_passthrough": {
"anyOf": [
{
"$ref": "#/definitions/InternalChatMessageMetadataPassthrough"
},
{
"type": "null"
}
]
},
"type": {
"enum": [
"compaction_trigger"
@@ -42,7 +42,6 @@
{
"enum": [
"untrusted",
"on-failure",
"on-request",
"never"
],
@@ -112,6 +111,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -541,6 +541,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -555,6 +567,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -1059,6 +1077,7 @@
"description": "Optional Git metadata captured when the thread was created."
},
"id": {
"description": "Identifier for this thread. Codex-generated thread IDs are UUIDv7.",
"type": "string"
},
"modelProvider": {
@@ -1165,6 +1184,17 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadHistoryMode": {
"enum": [
"legacy",
"paginated"
],
"type": "string"
},
"ThreadId": {
"type": "string"
},
@@ -1751,7 +1781,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -2017,6 +2047,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -1,5 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "DEPRECATED: `thread/rollback` will be removed soon.",
"properties": {
"numTurns": {
"description": "The number of turns to drop from the end of the thread. Must be >= 1.\n\nThis only modifies the thread's history and does not revert local file changes that have been made by the agent. Clients are responsible for reverting these changes.",
@@ -33,6 +33,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -462,6 +463,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -476,6 +489,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -865,6 +884,7 @@
"description": "Optional Git metadata captured when the thread was created."
},
"id": {
"description": "Identifier for this thread. Codex-generated thread IDs are UUIDv7.",
"type": "string"
},
"modelProvider": {
@@ -971,6 +991,17 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadHistoryMode": {
"enum": [
"legacy",
"paginated"
],
"type": "string"
},
"ThreadId": {
"type": "string"
},
@@ -1557,7 +1588,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -1823,6 +1854,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -39,7 +39,6 @@
{
"enum": [
"untrusted",
"on-failure",
"on-request",
"never"
],
@@ -19,7 +19,6 @@
{
"enum": [
"untrusted",
"on-failure",
"on-request",
"never"
],
@@ -74,6 +73,7 @@
"type": "string"
},
"path": {
"description": "Absolute path for the root in the selected environment.",
"type": "string"
},
"type": {
@@ -241,6 +241,13 @@
],
"type": "object"
},
"ThreadHistoryMode": {
"enum": [
"legacy",
"paginated"
],
"type": "string"
},
"ThreadSource": {
"type": "string"
},
@@ -42,7 +42,6 @@
{
"enum": [
"untrusted",
"on-failure",
"on-request",
"never"
],
@@ -112,6 +111,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -541,6 +541,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -555,6 +567,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -1059,6 +1077,7 @@
"description": "Optional Git metadata captured when the thread was created."
},
"id": {
"description": "Identifier for this thread. Codex-generated thread IDs are UUIDv7.",
"type": "string"
},
"modelProvider": {
@@ -1165,6 +1184,17 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadHistoryMode": {
"enum": [
"legacy",
"paginated"
],
"type": "string"
},
"ThreadId": {
"type": "string"
},
@@ -1751,7 +1781,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -2017,6 +2047,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -33,6 +33,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -462,6 +463,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -476,6 +489,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -865,6 +884,7 @@
"description": "Optional Git metadata captured when the thread was created."
},
"id": {
"description": "Identifier for this thread. Codex-generated thread IDs are UUIDv7.",
"type": "string"
},
"modelProvider": {
@@ -971,6 +991,17 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadHistoryMode": {
"enum": [
"legacy",
"paginated"
],
"type": "string"
},
"ThreadId": {
"type": "string"
},
@@ -1557,7 +1588,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -1823,6 +1854,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -33,6 +33,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -462,6 +463,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -476,6 +489,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -865,6 +884,7 @@
"description": "Optional Git metadata captured when the thread was created."
},
"id": {
"description": "Identifier for this thread. Codex-generated thread IDs are UUIDv7.",
"type": "string"
},
"modelProvider": {
@@ -971,6 +991,17 @@
],
"type": "string"
},
"ThreadExtra": {
"description": "Extra app-server data for a thread.",
"type": "object"
},
"ThreadHistoryMode": {
"enum": [
"legacy",
"paginated"
],
"type": "string"
},
"ThreadId": {
"type": "string"
},
@@ -1557,7 +1588,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -1823,6 +1854,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -30,6 +30,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -436,6 +437,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -450,6 +463,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -1250,7 +1269,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -1438,6 +1457,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -41,7 +41,6 @@
{
"enum": [
"untrusted",
"on-failure",
"on-request",
"never"
],
@@ -30,6 +30,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -436,6 +437,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -450,6 +463,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -1250,7 +1269,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -1438,6 +1457,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -30,6 +30,7 @@
{
"enum": [
"contextWindowExceeded",
"sessionBudgetExceeded",
"usageLimitExceeded",
"serverOverloaded",
"cyberPolicy",
@@ -436,6 +437,18 @@
},
"McpToolCallAppContext": {
"properties": {
"actionName": {
"type": [
"string",
"null"
]
},
"appName": {
"type": [
"string",
"null"
]
},
"connectorId": {
"type": "string"
},
@@ -450,6 +463,12 @@
"string",
"null"
]
},
"templateId": {
"type": [
"string",
"null"
]
}
},
"required": [
@@ -1250,7 +1269,7 @@
"type": "string"
},
"path": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": {
"enum": [
@@ -1438,6 +1457,7 @@
"description": "Only populated when the Turn's status is failed."
},
"id": {
"description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
"type": "string"
},
"items": {
@@ -11,10 +11,10 @@
*
* When converting from [`PathUri`], "native" refers to the supplied
* [`PathConvention`], which may be foreign to the operating system running
* this process. The inner string is private so path-producing code must convert
* from [`AbsolutePathBuf`] or use [`Self::from_path_uri`] instead of bypassing
* the intended conversion boundary. Non-UTF-8 paths are converted to UTF-8
* lossily because this API value is serialized as a JSON string.
* this process. The inner string is private so path-producing code must use a
* path conversion method instead of bypassing the intended conversion
* boundary. Non-UTF-8 paths are converted to UTF-8 lossily because this API
* value is serialized as a JSON string.
*
* Deserialization accepts any UTF-8 string without interpreting or validating
* it. That unrestricted construction path is intentionally available only to
@@ -20,4 +20,4 @@ id?: string,
/**
* Set when using the Responses API.
*/
call_id: string | null, status: LocalShellStatus, action: LocalShellAction, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "function_call", id?: string, name: string, namespace?: string, arguments: string, call_id: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "tool_search_call", id?: string, call_id: string | null, status?: string, execution: string, arguments: unknown, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "function_call_output", id?: string, call_id: string, output: FunctionCallOutputBody, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "custom_tool_call", id?: string, status?: string, call_id: string, name: string, input: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "custom_tool_call_output", id?: string, call_id: string, name?: string, output: FunctionCallOutputBody, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "tool_search_output", id?: string, call_id: string | null, status: string, execution: string, tools: unknown[], internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "web_search_call", id?: string, status?: string, action?: WebSearchAction, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "image_generation_call", id?: string, status: string, revised_prompt?: string, result: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "compaction", id?: string, encrypted_content: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "compaction_trigger", internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "context_compaction", id?: string, encrypted_content?: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "other" };
call_id: string | null, status: LocalShellStatus, action: LocalShellAction, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "function_call", id?: string, name: string, namespace?: string, arguments: string, call_id: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "tool_search_call", id?: string, call_id: string | null, status?: string, execution: string, arguments: unknown, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "function_call_output", id?: string, call_id: string, output: FunctionCallOutputBody, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "custom_tool_call", id?: string, status?: string, call_id: string, name: string, namespace?: string, input: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "custom_tool_call_output", id?: string, call_id: string, name?: string, output: FunctionCallOutputBody, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "tool_search_output", id?: string, call_id: string | null, status: string, execution: string, tools: unknown[], internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "web_search_call", id?: string, status?: string, action?: WebSearchAction, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "image_generation_call", id?: string, status: string, revised_prompt?: string, result: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "compaction", id?: string, encrypted_content: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "compaction_trigger", } | { "type": "context_compaction", id?: string, encrypted_content?: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "other" };
@@ -2,4 +2,9 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
/**
* Identifier for a Codex thread.
*
* Codex-generated thread IDs are UUIDv7, and some use cases rely on that.
*/
export type ThreadId = string;
@@ -4,4 +4,4 @@
import type { AmazonBedrockCredentialSource } from "../AmazonBedrockCredentialSource";
import type { PlanType } from "../PlanType";
export type Account = { "type": "apiKey", } | { "type": "chatgpt", email: string, planType: PlanType, } | { "type": "amazonBedrock", credentialSource: AmazonBedrockCredentialSource, };
export type Account = { "type": "apiKey", } | { "type": "chatgpt", email: string | null, planType: PlanType, } | { "type": "amazonBedrock", credentialSource: AmazonBedrockCredentialSource, };
@@ -7,7 +7,7 @@ import type { AppMetadata } from "./AppMetadata";
/**
* EXPERIMENTAL - app metadata returned by app-list APIs.
*/
export type AppInfo = { id: string, name: string, description: string | null, logoUrl: string | null, logoUrlDark: string | null, distributionChannel: string | null, branding: AppBranding | null, appMetadata: AppMetadata | null, labels: { [key in string]?: string } | null, installUrl: string | null, isAccessible: boolean,
export type AppInfo = { id: string, name: string, description: string | null, logoUrl: string | null, logoUrlDark: string | null, iconAssets: { [key in string]?: string } | null, iconDarkAssets: { [key in string]?: string } | null, distributionChannel: string | null, branding: AppBranding | null, appMetadata: AppMetadata | null, labels: { [key in string]?: string } | null, installUrl: string | null, isAccessible: boolean,
/**
* Whether this app is enabled in config.toml.
* Example:
@@ -2,4 +2,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type AskForApproval = "untrusted" | "on-failure" | "on-request" | { "granular": { sandbox_approval: boolean, rules: boolean, skill_approval: boolean, request_permissions: boolean, mcp_elicitations: boolean, } } | "never";
export type AskForApproval = "untrusted" | "on-request" | { "granular": { sandbox_approval: boolean, rules: boolean, skill_approval: boolean, request_permissions: boolean, mcp_elicitations: boolean, } } | "never";
@@ -5,4 +5,8 @@
/**
* Location used to resolve a selected capability root.
*/
export type CapabilityRootLocation = { "type": "environment", environmentId: string, path: string, };
export type CapabilityRootLocation = { "type": "environment", environmentId: string,
/**
* Absolute path for the root in the selected environment.
*/
path: string, };
@@ -9,4 +9,4 @@ import type { NonSteerableTurnKind } from "./NonSteerableTurnKind";
* When an upstream HTTP status is available (for example, from the Responses API or a provider),
* it is forwarded in `httpStatusCode` on the relevant `codexErrorInfo` variant.
*/
export type CodexErrorInfo = "contextWindowExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" | { "httpConnectionFailed": { httpStatusCode: number | null, } } | { "responseStreamConnectionFailed": { httpStatusCode: number | null, } } | "internalServerError" | "unauthorized" | "badRequest" | "threadRollbackFailed" | "sandboxError" | { "responseStreamDisconnected": { httpStatusCode: number | null, } } | { "responseTooManyFailedAttempts": { httpStatusCode: number | null, } } | { "activeTurnNotSteerable": { turnKind: NonSteerableTurnKind, } } | "other";
export type CodexErrorInfo = "contextWindowExceeded" | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" | { "httpConnectionFailed": { httpStatusCode: number | null, } } | { "responseStreamConnectionFailed": { httpStatusCode: number | null, } } | "internalServerError" | "unauthorized" | "badRequest" | "threadRollbackFailed" | "sandboxError" | { "responseStreamDisconnected": { httpStatusCode: number | null, } } | { "responseTooManyFailedAttempts": { httpStatusCode: number | null, } } | { "activeTurnNotSteerable": { turnKind: NonSteerableTurnKind, } } | "other";
@@ -4,8 +4,9 @@
import type { WebSearchMode } from "../WebSearchMode";
import type { AskForApproval } from "./AskForApproval";
import type { ComputerUseRequirements } from "./ComputerUseRequirements";
import type { ModelsRequirements } from "./ModelsRequirements";
import type { ResidencyRequirement } from "./ResidencyRequirement";
import type { SandboxMode } from "./SandboxMode";
import type { WindowsSandboxSetupMode } from "./WindowsSandboxSetupMode";
export type ConfigRequirements = {allowedApprovalPolicies: Array<AskForApproval> | null, allowedSandboxModes: Array<SandboxMode> | null, allowedWindowsSandboxImplementations: Array<WindowsSandboxSetupMode> | null, allowedPermissionProfiles: { [key in string]?: boolean } | null, defaultPermissions: string | null, allowedWebSearchModes: Array<WebSearchMode> | null, allowManagedHooksOnly: boolean | null, allowAppshots: boolean | null, allowRemoteControl: boolean | null, computerUse: ComputerUseRequirements | null, featureRequirements: { [key in string]?: boolean } | null, enforceResidency: ResidencyRequirement | null};
export type ConfigRequirements = {allowedApprovalPolicies: Array<AskForApproval> | null, allowedSandboxModes: Array<SandboxMode> | null, allowedWindowsSandboxImplementations: Array<WindowsSandboxSetupMode> | null, allowedPermissionProfiles: { [key in string]?: boolean } | null, defaultPermissions: string | null, allowedWebSearchModes: Array<WebSearchMode> | null, allowManagedHooksOnly: boolean | null, allowAppshots: boolean | null, allowRemoteControl: boolean | null, computerUse: ComputerUseRequirements | null, featureRequirements: { [key in string]?: boolean } | null, enforceResidency: ResidencyRequirement | null, models: ModelsRequirements | null};
@@ -2,4 +2,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type McpServerOauthLoginCompletedNotification = { name: string, success: boolean, error?: string, };
export type McpServerOauthLoginCompletedNotification = { name: string, threadId: string | null, success: boolean, error?: string, };
@@ -2,4 +2,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type McpServerOauthLoginParams = { name: string, scopes?: Array<string> | null, timeoutSecs?: bigint | null, };
export type McpServerOauthLoginParams = { name: string, threadId?: string | null, scopes?: Array<string> | null, timeoutSecs?: bigint | null, };
@@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type McpServerStartupFailureReason = "reauthenticationRequired";
@@ -1,6 +1,7 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { McpServerStartupFailureReason } from "./McpServerStartupFailureReason";
import type { McpServerStartupState } from "./McpServerStartupState";
export type McpServerStatusUpdatedNotification = { threadId: string | null, name: string, status: McpServerStartupState, error: string | null, };
export type McpServerStatusUpdatedNotification = { threadId: string | null, name: string, status: McpServerStartupState, error: string | null, failureReason: McpServerStartupFailureReason | null, };

Some files were not shown because too many files have changed in this diff Show More