mirror of
https://github.com/openai/codex.git
synced 2026-03-19 05:03:51 +00:00
Compare commits
81 Commits
dev/steve/
...
dev/cc/ref
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7d64631b0 | ||
|
|
e5de13644d | ||
|
|
5cada46ddf | ||
|
|
88e5382fc4 | ||
|
|
392347d436 | ||
|
|
334164a6f7 | ||
|
|
580f32ad2a | ||
|
|
606d85055f | ||
|
|
7ae99576a6 | ||
|
|
347c6b12ec | ||
|
|
58ac2a8773 | ||
|
|
a265d6043e | ||
|
|
0f9484dc8a | ||
|
|
40a7d1d15b | ||
|
|
84f4e7b39d | ||
|
|
a3613035f3 | ||
|
|
6fef421654 | ||
|
|
226241f035 | ||
|
|
3ce879c646 | ||
|
|
770616414a | ||
|
|
d950543e65 | ||
|
|
6fe8a05dcb | ||
|
|
83a60fdb94 | ||
|
|
19b887128e | ||
|
|
a5d3114e97 | ||
|
|
fc75d07504 | ||
|
|
0d1539e74c | ||
|
|
98be562fd3 | ||
|
|
c6ab4ee537 | ||
|
|
1a9555eda9 | ||
|
|
43ee72a9b9 | ||
|
|
0d2ff40a58 | ||
|
|
ee756eb80f | ||
|
|
2cc4ee413f | ||
|
|
4d9d4b7b0f | ||
|
|
23a44ddbe8 | ||
|
|
b02388672f | ||
|
|
683c37ce75 | ||
|
|
49e7dda2df | ||
|
|
95bdea93d2 | ||
|
|
904dbd414f | ||
|
|
0d531c05f2 | ||
|
|
d484bb57d9 | ||
|
|
f26ad3c92c | ||
|
|
78e8ee4591 | ||
|
|
8e258eb3f5 | ||
|
|
6ea041032b | ||
|
|
e8add54e5d | ||
|
|
ef36d39199 | ||
|
|
4ed19b0766 | ||
|
|
31648563c8 | ||
|
|
603b6493a9 | ||
|
|
d37dcca7e0 | ||
|
|
57f865c069 | ||
|
|
db7e02c739 | ||
|
|
32e4a5d5d9 | ||
|
|
79f476e47d | ||
|
|
15ede607a0 | ||
|
|
8e34caffcc | ||
|
|
e5a28ba0c2 | ||
|
|
fbd7f9b986 | ||
|
|
1d85fe79ed | ||
|
|
49c2b66ece | ||
|
|
59533a2c26 | ||
|
|
b77fe8fefe | ||
|
|
6f05d8d735 | ||
|
|
a3ba10b44b | ||
|
|
d0a693e541 | ||
|
|
4c9dbc1f88 | ||
|
|
663dd3f935 | ||
|
|
a0e41f4ff9 | ||
|
|
7a6e30b55b | ||
|
|
db89b73a9c | ||
|
|
c04a0a7454 | ||
|
|
3f266bcd68 | ||
|
|
18ad67549c | ||
|
|
33acc1e65f | ||
|
|
029aab5563 | ||
|
|
6fdeb1d602 | ||
|
|
ba463a9dc7 | ||
|
|
d4af6053e2 |
3
.github/actions/linux-code-sign/action.yml
vendored
3
.github/actions/linux-code-sign/action.yml
vendored
@@ -17,6 +17,7 @@ runs:
|
||||
- name: Cosign Linux artifacts
|
||||
shell: bash
|
||||
env:
|
||||
ARTIFACTS_DIR: ${{ inputs.artifacts-dir }}
|
||||
COSIGN_EXPERIMENTAL: "1"
|
||||
COSIGN_YES: "true"
|
||||
COSIGN_OIDC_CLIENT_ID: "sigstore"
|
||||
@@ -24,7 +25,7 @@ runs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
dest="${{ inputs.artifacts-dir }}"
|
||||
dest="$ARTIFACTS_DIR"
|
||||
if [[ ! -d "$dest" ]]; then
|
||||
echo "Destination $dest does not exist"
|
||||
exit 1
|
||||
|
||||
13
.github/actions/macos-code-sign/action.yml
vendored
13
.github/actions/macos-code-sign/action.yml
vendored
@@ -117,6 +117,8 @@ runs:
|
||||
- name: Sign macOS binaries
|
||||
if: ${{ inputs.sign-binaries == 'true' }}
|
||||
shell: bash
|
||||
env:
|
||||
TARGET: ${{ inputs.target }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
@@ -131,7 +133,7 @@ runs:
|
||||
fi
|
||||
|
||||
for binary in codex codex-responses-api-proxy; do
|
||||
path="codex-rs/target/${{ inputs.target }}/release/${binary}"
|
||||
path="codex-rs/target/${TARGET}/release/${binary}"
|
||||
codesign --force --options runtime --timestamp --sign "$APPLE_CODESIGN_IDENTITY" "${keychain_args[@]}" "$path"
|
||||
done
|
||||
|
||||
@@ -139,6 +141,7 @@ runs:
|
||||
if: ${{ inputs.sign-binaries == 'true' }}
|
||||
shell: bash
|
||||
env:
|
||||
TARGET: ${{ inputs.target }}
|
||||
APPLE_NOTARIZATION_KEY_P8: ${{ inputs.apple-notarization-key-p8 }}
|
||||
APPLE_NOTARIZATION_KEY_ID: ${{ inputs.apple-notarization-key-id }}
|
||||
APPLE_NOTARIZATION_ISSUER_ID: ${{ inputs.apple-notarization-issuer-id }}
|
||||
@@ -163,7 +166,7 @@ runs:
|
||||
|
||||
notarize_binary() {
|
||||
local binary="$1"
|
||||
local source_path="codex-rs/target/${{ inputs.target }}/release/${binary}"
|
||||
local source_path="codex-rs/target/${TARGET}/release/${binary}"
|
||||
local archive_path="${RUNNER_TEMP}/${binary}.zip"
|
||||
|
||||
if [[ ! -f "$source_path" ]]; then
|
||||
@@ -184,6 +187,7 @@ runs:
|
||||
if: ${{ inputs.sign-dmg == 'true' }}
|
||||
shell: bash
|
||||
env:
|
||||
TARGET: ${{ inputs.target }}
|
||||
APPLE_NOTARIZATION_KEY_P8: ${{ inputs.apple-notarization-key-p8 }}
|
||||
APPLE_NOTARIZATION_KEY_ID: ${{ inputs.apple-notarization-key-id }}
|
||||
APPLE_NOTARIZATION_ISSUER_ID: ${{ inputs.apple-notarization-issuer-id }}
|
||||
@@ -206,7 +210,8 @@ runs:
|
||||
|
||||
source "$GITHUB_ACTION_PATH/notary_helpers.sh"
|
||||
|
||||
dmg_path="codex-rs/target/${{ inputs.target }}/release/codex-${{ inputs.target }}.dmg"
|
||||
dmg_name="codex-${TARGET}.dmg"
|
||||
dmg_path="codex-rs/target/${TARGET}/release/${dmg_name}"
|
||||
|
||||
if [[ ! -f "$dmg_path" ]]; then
|
||||
echo "dmg $dmg_path not found"
|
||||
@@ -219,7 +224,7 @@ runs:
|
||||
fi
|
||||
|
||||
codesign --force --timestamp --sign "$APPLE_CODESIGN_IDENTITY" "${keychain_args[@]}" "$dmg_path"
|
||||
notarize_submission "codex-${{ inputs.target }}.dmg" "$dmg_path" "$notary_key_path"
|
||||
notarize_submission "$dmg_name" "$dmg_path" "$notary_key_path"
|
||||
xcrun stapler staple "$dmg_path"
|
||||
|
||||
- name: Remove signing keychain
|
||||
|
||||
1
.github/blob-size-allowlist.txt
vendored
1
.github/blob-size-allowlist.txt
vendored
@@ -6,3 +6,4 @@ MODULE.bazel.lock
|
||||
codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json
|
||||
codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json
|
||||
codex-rs/tui/tests/fixtures/oss-story.jsonl
|
||||
codex-rs/tui_app_server/tests/fixtures/oss-story.jsonl
|
||||
|
||||
7
.github/workflows/blob-size-policy.yml
vendored
7
.github/workflows/blob-size-policy.yml
vendored
@@ -21,9 +21,12 @@ jobs:
|
||||
echo "head=$(git rev-parse HEAD^2)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Check changed blob sizes
|
||||
env:
|
||||
BASE_SHA: ${{ steps.range.outputs.base }}
|
||||
HEAD_SHA: ${{ steps.range.outputs.head }}
|
||||
run: |
|
||||
python3 scripts/check_blob_size.py \
|
||||
--base "${{ steps.range.outputs.base }}" \
|
||||
--head "${{ steps.range.outputs.head }}" \
|
||||
--base "$BASE_SHA" \
|
||||
--head "$HEAD_SHA" \
|
||||
--max-bytes 512000 \
|
||||
--allowlist .github/blob-size-allowlist.txt
|
||||
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Use a rust-release version that includes all native binaries.
|
||||
CODEX_VERSION=0.74.0
|
||||
CODEX_VERSION=0.115.0
|
||||
OUTPUT_DIR="${RUNNER_TEMP}"
|
||||
python3 ./scripts/stage_npm_packages.py \
|
||||
--release-version "$CODEX_VERSION" \
|
||||
|
||||
3
.github/workflows/issue-deduplicator.yml
vendored
3
.github/workflows/issue-deduplicator.yml
vendored
@@ -396,6 +396,7 @@ jobs:
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||
run: |
|
||||
gh issue edit "${{ github.event.issue.number }}" --remove-label codex-deduplicate || true
|
||||
gh issue edit "$ISSUE_NUMBER" --remove-label codex-deduplicate || true
|
||||
echo "Attempted to remove label: codex-deduplicate"
|
||||
|
||||
69
.github/workflows/rust-ci.yml
vendored
69
.github/workflows/rust-ci.yml
vendored
@@ -14,6 +14,8 @@ jobs:
|
||||
name: Detect changed areas
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
argument_comment_lint: ${{ steps.detect.outputs.argument_comment_lint }}
|
||||
argument_comment_lint_package: ${{ steps.detect.outputs.argument_comment_lint_package }}
|
||||
codex: ${{ steps.detect.outputs.codex }}
|
||||
workflows: ${{ steps.detect.outputs.workflows }}
|
||||
steps:
|
||||
@@ -39,12 +41,18 @@ jobs:
|
||||
fi
|
||||
|
||||
codex=false
|
||||
argument_comment_lint=false
|
||||
argument_comment_lint_package=false
|
||||
workflows=false
|
||||
for f in "${files[@]}"; do
|
||||
[[ $f == codex-rs/* ]] && codex=true
|
||||
[[ $f == codex-rs/* || $f == tools/argument-comment-lint/* || $f == justfile ]] && argument_comment_lint=true
|
||||
[[ $f == tools/argument-comment-lint/* || $f == .github/workflows/rust-ci.yml ]] && argument_comment_lint_package=true
|
||||
[[ $f == .github/* ]] && workflows=true
|
||||
done
|
||||
|
||||
echo "argument_comment_lint=$argument_comment_lint" >> "$GITHUB_OUTPUT"
|
||||
echo "argument_comment_lint_package=$argument_comment_lint_package" >> "$GITHUB_OUTPUT"
|
||||
echo "codex=$codex" >> "$GITHUB_OUTPUT"
|
||||
echo "workflows=$workflows" >> "$GITHUB_OUTPUT"
|
||||
|
||||
@@ -83,6 +91,44 @@ jobs:
|
||||
- name: cargo shear
|
||||
run: cargo shear
|
||||
|
||||
argument_comment_lint:
|
||||
name: Argument comment lint
|
||||
runs-on: ubuntu-24.04
|
||||
needs: changed
|
||||
if: ${{ needs.changed.outputs.argument_comment_lint == 'true' || needs.changed.outputs.workflows == 'true' || github.event_name == 'push' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Install Linux sandbox build dependencies
|
||||
run: |
|
||||
sudo DEBIAN_FRONTEND=noninteractive apt-get update
|
||||
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends pkg-config libcap-dev
|
||||
- uses: dtolnay/rust-toolchain@1.93.0
|
||||
with:
|
||||
toolchain: nightly-2025-09-18
|
||||
components: llvm-tools-preview, rustc-dev, rust-src
|
||||
- name: Cache cargo-dylint tooling
|
||||
id: cargo_dylint_cache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/cargo-dylint
|
||||
~/.cargo/bin/dylint-link
|
||||
~/.cargo/registry/index
|
||||
~/.cargo/registry/cache
|
||||
~/.cargo/git/db
|
||||
key: argument-comment-lint-${{ runner.os }}-${{ hashFiles('tools/argument-comment-lint/Cargo.lock', 'tools/argument-comment-lint/rust-toolchain', '.github/workflows/rust-ci.yml') }}
|
||||
- name: Install cargo-dylint tooling
|
||||
if: ${{ steps.cargo_dylint_cache.outputs.cache-hit != 'true' }}
|
||||
run: cargo install --locked cargo-dylint dylint-link
|
||||
- name: Test argument comment lint package
|
||||
if: ${{ needs.changed.outputs.argument_comment_lint_package == 'true' || github.event_name == 'push' }}
|
||||
working-directory: tools/argument-comment-lint
|
||||
run: cargo test
|
||||
- name: Run argument comment lint on codex-rs
|
||||
run: |
|
||||
bash -n tools/argument-comment-lint/run.sh
|
||||
./tools/argument-comment-lint/run.sh
|
||||
|
||||
# --- CI to validate on different os/targets --------------------------------
|
||||
lint_build:
|
||||
name: Lint/Build — ${{ matrix.runner }} - ${{ matrix.target }}${{ matrix.profile == 'release' && ' (release)' || '' }}
|
||||
@@ -305,7 +351,7 @@ jobs:
|
||||
|
||||
- if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl'}}
|
||||
name: Install Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2
|
||||
with:
|
||||
version: 0.14.0
|
||||
|
||||
@@ -657,13 +703,15 @@ jobs:
|
||||
# --- Gatherer job that you mark as the ONLY required status -----------------
|
||||
results:
|
||||
name: CI results (required)
|
||||
needs: [changed, general, cargo_shear, lint_build, tests]
|
||||
needs:
|
||||
[changed, general, cargo_shear, argument_comment_lint, lint_build, tests]
|
||||
if: always()
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Summarize
|
||||
shell: bash
|
||||
run: |
|
||||
echo "arglint: ${{ needs.argument_comment_lint.result }}"
|
||||
echo "general: ${{ needs.general.result }}"
|
||||
echo "shear : ${{ needs.cargo_shear.result }}"
|
||||
echo "lint : ${{ needs.lint_build.result }}"
|
||||
@@ -671,16 +719,21 @@ jobs:
|
||||
|
||||
# If nothing relevant changed (PR touching only root README, etc.),
|
||||
# declare success regardless of other jobs.
|
||||
if [[ '${{ needs.changed.outputs.codex }}' != 'true' && '${{ needs.changed.outputs.workflows }}' != 'true' && '${{ github.event_name }}' != 'push' ]]; then
|
||||
if [[ '${{ needs.changed.outputs.argument_comment_lint }}' != 'true' && '${{ needs.changed.outputs.codex }}' != 'true' && '${{ needs.changed.outputs.workflows }}' != 'true' && '${{ github.event_name }}' != 'push' ]]; then
|
||||
echo 'No relevant changes -> CI not required.'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Otherwise require the jobs to have succeeded
|
||||
[[ '${{ needs.general.result }}' == 'success' ]] || { echo 'general failed'; exit 1; }
|
||||
[[ '${{ needs.cargo_shear.result }}' == 'success' ]] || { echo 'cargo_shear failed'; exit 1; }
|
||||
[[ '${{ needs.lint_build.result }}' == 'success' ]] || { echo 'lint_build failed'; exit 1; }
|
||||
[[ '${{ needs.tests.result }}' == 'success' ]] || { echo 'tests failed'; exit 1; }
|
||||
if [[ '${{ needs.changed.outputs.argument_comment_lint }}' == 'true' || '${{ needs.changed.outputs.workflows }}' == 'true' || '${{ github.event_name }}' == 'push' ]]; then
|
||||
[[ '${{ needs.argument_comment_lint.result }}' == 'success' ]] || { echo 'argument_comment_lint failed'; exit 1; }
|
||||
fi
|
||||
|
||||
if [[ '${{ needs.changed.outputs.codex }}' == 'true' || '${{ needs.changed.outputs.workflows }}' == 'true' || '${{ github.event_name }}' == 'push' ]]; then
|
||||
[[ '${{ needs.general.result }}' == 'success' ]] || { echo 'general failed'; exit 1; }
|
||||
[[ '${{ needs.cargo_shear.result }}' == 'success' ]] || { echo 'cargo_shear failed'; exit 1; }
|
||||
[[ '${{ needs.lint_build.result }}' == 'success' ]] || { echo 'lint_build failed'; exit 1; }
|
||||
[[ '${{ needs.tests.result }}' == 'success' ]] || { echo 'tests failed'; exit 1; }
|
||||
fi
|
||||
|
||||
- name: sccache summary note
|
||||
if: always()
|
||||
|
||||
11
.github/workflows/rust-release.yml
vendored
11
.github/workflows/rust-release.yml
vendored
@@ -142,7 +142,7 @@ jobs:
|
||||
|
||||
- if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl'}}
|
||||
name: Install Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2
|
||||
with:
|
||||
version: 0.14.0
|
||||
|
||||
@@ -490,9 +490,10 @@ jobs:
|
||||
- name: Stage npm packages
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RELEASE_VERSION: ${{ steps.release_name.outputs.name }}
|
||||
run: |
|
||||
./scripts/stage_npm_packages.py \
|
||||
--release-version "${{ steps.release_name.outputs.name }}" \
|
||||
--release-version "$RELEASE_VERSION" \
|
||||
--package codex \
|
||||
--package codex-responses-api-proxy \
|
||||
--package codex-sdk
|
||||
@@ -561,10 +562,12 @@ jobs:
|
||||
- name: Download npm tarballs from release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RELEASE_TAG: ${{ needs.release.outputs.tag }}
|
||||
RELEASE_VERSION: ${{ needs.release.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
version="${{ needs.release.outputs.version }}"
|
||||
tag="${{ needs.release.outputs.tag }}"
|
||||
version="$RELEASE_VERSION"
|
||||
tag="$RELEASE_TAG"
|
||||
mkdir -p dist/npm
|
||||
patterns=(
|
||||
"codex-npm-${version}.tgz"
|
||||
|
||||
19
.github/workflows/shell-tool-mcp.yml
vendored
19
.github/workflows/shell-tool-mcp.yml
vendored
@@ -31,11 +31,14 @@ jobs:
|
||||
steps:
|
||||
- name: Compute version and tags
|
||||
id: compute
|
||||
env:
|
||||
RELEASE_TAG_INPUT: ${{ inputs.release-tag }}
|
||||
RELEASE_VERSION_INPUT: ${{ inputs.release-version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
version="${{ inputs.release-version }}"
|
||||
release_tag="${{ inputs.release-tag }}"
|
||||
version="$RELEASE_VERSION_INPUT"
|
||||
release_tag="$RELEASE_TAG_INPUT"
|
||||
|
||||
if [[ -z "$version" ]]; then
|
||||
if [[ -n "$release_tag" && "$release_tag" =~ ^rust-v.+ ]]; then
|
||||
@@ -483,20 +486,22 @@ jobs:
|
||||
STAGING_DIR: ${{ runner.temp }}/shell-tool-mcp
|
||||
|
||||
- name: Ensure binaries are executable
|
||||
env:
|
||||
STAGING_DIR: ${{ steps.staging.outputs.dir }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
staging="${{ steps.staging.outputs.dir }}"
|
||||
chmod +x \
|
||||
"$staging"/vendor/*/bash/*/bash \
|
||||
"$staging"/vendor/*/zsh/*/zsh
|
||||
"$STAGING_DIR"/vendor/*/bash/*/bash \
|
||||
"$STAGING_DIR"/vendor/*/zsh/*/zsh
|
||||
|
||||
- name: Create npm tarball
|
||||
shell: bash
|
||||
env:
|
||||
STAGING_DIR: ${{ steps.staging.outputs.dir }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p dist/npm
|
||||
staging="${{ steps.staging.outputs.dir }}"
|
||||
pack_info=$(cd "$staging" && npm pack --ignore-scripts --json --pack-destination "${GITHUB_WORKSPACE}/dist/npm")
|
||||
pack_info=$(cd "$STAGING_DIR" && npm pack --ignore-scripts --json --pack-destination "${GITHUB_WORKSPACE}/dist/npm")
|
||||
filename=$(PACK_INFO="$pack_info" node -e 'const data = JSON.parse(process.env.PACK_INFO); console.log(data[0].filename);')
|
||||
mv "dist/npm/${filename}" "dist/npm/codex-shell-tool-mcp-npm-${PACKAGE_VERSION}.tgz"
|
||||
|
||||
|
||||
@@ -54,6 +54,8 @@ See `codex-rs/tui/styles.md`.
|
||||
|
||||
## TUI code conventions
|
||||
|
||||
- When a change lands in `codex-rs/tui` and `codex-rs/tui_app_server` has a parallel implementation of the same behavior, reflect the change in `codex-rs/tui_app_server` too unless there is a documented reason not to.
|
||||
|
||||
- Use concise styling helpers from ratatui’s Stylize trait.
|
||||
- Basic spans: use "text".into()
|
||||
- Styled spans: use "text".red(), "text".green(), "text".magenta(), "text".dim(), etc.
|
||||
|
||||
117
codex-rs/Cargo.lock
generated
117
codex-rs/Cargo.lock
generated
@@ -1427,6 +1427,7 @@ dependencies = [
|
||||
"codex-chatgpt",
|
||||
"codex-cloud-requirements",
|
||||
"codex-core",
|
||||
"codex-environment",
|
||||
"codex-feedback",
|
||||
"codex-file-search",
|
||||
"codex-login",
|
||||
@@ -1462,7 +1463,6 @@ dependencies = [
|
||||
"tracing-opentelemetry",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
"walkdir",
|
||||
"wiremock",
|
||||
]
|
||||
|
||||
@@ -1476,12 +1476,15 @@ dependencies = [
|
||||
"codex-core",
|
||||
"codex-feedback",
|
||||
"codex-protocol",
|
||||
"futures",
|
||||
"pretty_assertions",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"toml 0.9.11+spec-1.1.0",
|
||||
"tracing",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1567,11 +1570,13 @@ name = "codex-artifacts"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-package-manager",
|
||||
"flate2",
|
||||
"pretty_assertions",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"tar",
|
||||
"tempfile",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
@@ -1660,6 +1665,7 @@ dependencies = [
|
||||
"codex-state",
|
||||
"codex-stdio-to-uds",
|
||||
"codex-tui",
|
||||
"codex-tui-app-server",
|
||||
"codex-utils-cargo-bin",
|
||||
"codex-utils-cli",
|
||||
"codex-windows-sandbox",
|
||||
@@ -1837,6 +1843,7 @@ dependencies = [
|
||||
"codex-client",
|
||||
"codex-config",
|
||||
"codex-connectors",
|
||||
"codex-environment",
|
||||
"codex-execpolicy",
|
||||
"codex-file-search",
|
||||
"codex-git",
|
||||
@@ -1940,6 +1947,17 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-environment"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"codex-utils-absolute-path",
|
||||
"pretty_assertions",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-exec"
|
||||
version = "0.0.0"
|
||||
@@ -2309,7 +2327,6 @@ dependencies = [
|
||||
"icu_decimal",
|
||||
"icu_locale_core",
|
||||
"icu_provider",
|
||||
"mime_guess",
|
||||
"pretty_assertions",
|
||||
"schemars 0.8.22",
|
||||
"serde",
|
||||
@@ -2496,7 +2513,6 @@ dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"codex-ansi-escape",
|
||||
"codex-app-server-client",
|
||||
"codex-app-server-protocol",
|
||||
"codex-arg0",
|
||||
"codex-backend-client",
|
||||
@@ -2512,6 +2528,97 @@ dependencies = [
|
||||
"codex-protocol",
|
||||
"codex-shell-command",
|
||||
"codex-state",
|
||||
"codex-tui-app-server",
|
||||
"codex-utils-absolute-path",
|
||||
"codex-utils-approval-presets",
|
||||
"codex-utils-cargo-bin",
|
||||
"codex-utils-cli",
|
||||
"codex-utils-elapsed",
|
||||
"codex-utils-fuzzy-match",
|
||||
"codex-utils-oss",
|
||||
"codex-utils-pty",
|
||||
"codex-utils-sandbox-summary",
|
||||
"codex-utils-sleep-inhibitor",
|
||||
"codex-utils-string",
|
||||
"codex-windows-sandbox",
|
||||
"color-eyre",
|
||||
"cpal",
|
||||
"crossterm",
|
||||
"derive_more 2.1.1",
|
||||
"diffy",
|
||||
"dirs",
|
||||
"dunce",
|
||||
"hound",
|
||||
"image",
|
||||
"insta",
|
||||
"itertools 0.14.0",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"pathdiff",
|
||||
"pretty_assertions",
|
||||
"pulldown-cmark",
|
||||
"rand 0.9.2",
|
||||
"ratatui",
|
||||
"ratatui-macros",
|
||||
"regex-lite",
|
||||
"reqwest",
|
||||
"rmcp",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serial_test",
|
||||
"shlex",
|
||||
"strum 0.27.2",
|
||||
"strum_macros 0.28.0",
|
||||
"supports-color 3.0.2",
|
||||
"syntect",
|
||||
"tempfile",
|
||||
"textwrap 0.16.2",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
"toml 0.9.11+spec-1.1.0",
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
"tracing-subscriber",
|
||||
"two-face",
|
||||
"unicode-segmentation",
|
||||
"unicode-width 0.2.1",
|
||||
"url",
|
||||
"uuid",
|
||||
"vt100",
|
||||
"webbrowser",
|
||||
"which",
|
||||
"windows-sys 0.52.0",
|
||||
"winsplit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-tui-app-server"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arboard",
|
||||
"assert_matches",
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"clap",
|
||||
"codex-ansi-escape",
|
||||
"codex-app-server-client",
|
||||
"codex-app-server-protocol",
|
||||
"codex-arg0",
|
||||
"codex-chatgpt",
|
||||
"codex-cli",
|
||||
"codex-client",
|
||||
"codex-cloud-requirements",
|
||||
"codex-core",
|
||||
"codex-feedback",
|
||||
"codex-file-search",
|
||||
"codex-login",
|
||||
"codex-otel",
|
||||
"codex-protocol",
|
||||
"codex-shell-command",
|
||||
"codex-state",
|
||||
"codex-utils-absolute-path",
|
||||
"codex-utils-approval-presets",
|
||||
"codex-utils-cargo-bin",
|
||||
@@ -2650,7 +2757,7 @@ dependencies = [
|
||||
"base64 0.22.1",
|
||||
"codex-utils-cache",
|
||||
"image",
|
||||
"tempfile",
|
||||
"mime_guess",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
]
|
||||
@@ -2751,6 +2858,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"codex-protocol",
|
||||
"codex-utils-absolute-path",
|
||||
"codex-utils-pty",
|
||||
"codex-utils-string",
|
||||
"dirs-next",
|
||||
"dunce",
|
||||
@@ -2759,6 +2867,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"windows 0.58.0",
|
||||
"windows-sys 0.52.0",
|
||||
"winres",
|
||||
|
||||
@@ -22,6 +22,7 @@ members = [
|
||||
"shell-escalation",
|
||||
"skills",
|
||||
"core",
|
||||
"environment",
|
||||
"hooks",
|
||||
"secrets",
|
||||
"exec",
|
||||
@@ -42,6 +43,7 @@ members = [
|
||||
"stdio-to-uds",
|
||||
"otel",
|
||||
"tui",
|
||||
"tui_app_server",
|
||||
"utils/absolute-path",
|
||||
"utils/cargo-bin",
|
||||
"utils/git",
|
||||
@@ -102,6 +104,7 @@ codex-cloud-requirements = { path = "cloud-requirements" }
|
||||
codex-connectors = { path = "connectors" }
|
||||
codex-config = { path = "config" }
|
||||
codex-core = { path = "core" }
|
||||
codex-environment = { path = "environment" }
|
||||
codex-exec = { path = "exec" }
|
||||
codex-execpolicy = { path = "execpolicy" }
|
||||
codex-experimental-api-macros = { path = "codex-experimental-api-macros" }
|
||||
@@ -129,6 +132,7 @@ codex-state = { path = "state" }
|
||||
codex-stdio-to-uds = { path = "stdio-to-uds" }
|
||||
codex-test-macros = { path = "test-macros" }
|
||||
codex-tui = { path = "tui" }
|
||||
codex-tui-app-server = { path = "tui_app_server" }
|
||||
codex-utils-absolute-path = { path = "utils/absolute-path" }
|
||||
codex-utils-approval-presets = { path = "utils/approval-presets" }
|
||||
codex-utils-cache = { path = "utils/cache" }
|
||||
|
||||
@@ -18,11 +18,14 @@ codex-arg0 = { workspace = true }
|
||||
codex-core = { workspace = true }
|
||||
codex-feedback = { workspace = true }
|
||||
codex-protocol = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true, features = ["sync", "time", "rt"] }
|
||||
tokio-tungstenite = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
url = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = { workspace = true }
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
//! bridging async `mpsc` channels on both sides. Queues are bounded so overload
|
||||
//! surfaces as channel-full errors rather than unbounded memory growth.
|
||||
|
||||
mod remote;
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::io::Error as IoError;
|
||||
@@ -33,8 +35,11 @@ use codex_app_server_protocol::ConfigWarningNotification;
|
||||
use codex_app_server_protocol::InitializeCapabilities;
|
||||
use codex_app_server_protocol::InitializeParams;
|
||||
use codex_app_server_protocol::JSONRPCErrorError;
|
||||
use codex_app_server_protocol::JSONRPCNotification;
|
||||
use codex_app_server_protocol::RequestId;
|
||||
use codex_app_server_protocol::Result as JsonRpcResult;
|
||||
use codex_app_server_protocol::ServerNotification;
|
||||
use codex_app_server_protocol::ServerRequest;
|
||||
use codex_arg0::Arg0DispatchPaths;
|
||||
use codex_core::AuthManager;
|
||||
use codex_core::ThreadManager;
|
||||
@@ -51,6 +56,9 @@ use tokio::time::timeout;
|
||||
use toml::Value as TomlValue;
|
||||
use tracing::warn;
|
||||
|
||||
pub use crate::remote::RemoteAppServerClient;
|
||||
pub use crate::remote::RemoteAppServerConnectArgs;
|
||||
|
||||
const SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
|
||||
/// Raw app-server request result for typed in-process requests.
|
||||
@@ -60,6 +68,30 @@ const SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
/// `MessageProcessor` continues to produce that shape internally.
|
||||
pub type RequestResult = std::result::Result<JsonRpcResult, JSONRPCErrorError>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum AppServerEvent {
|
||||
Lagged { skipped: usize },
|
||||
ServerNotification(ServerNotification),
|
||||
LegacyNotification(JSONRPCNotification),
|
||||
ServerRequest(ServerRequest),
|
||||
Disconnected { message: String },
|
||||
}
|
||||
|
||||
impl From<InProcessServerEvent> for AppServerEvent {
|
||||
fn from(value: InProcessServerEvent) -> Self {
|
||||
match value {
|
||||
InProcessServerEvent::Lagged { skipped } => Self::Lagged { skipped },
|
||||
InProcessServerEvent::ServerNotification(notification) => {
|
||||
Self::ServerNotification(notification)
|
||||
}
|
||||
InProcessServerEvent::LegacyNotification(notification) => {
|
||||
Self::LegacyNotification(notification)
|
||||
}
|
||||
InProcessServerEvent::ServerRequest(request) => Self::ServerRequest(request),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn event_requires_delivery(event: &InProcessServerEvent) -> bool {
|
||||
// These terminal events drive surface shutdown/completion state. Dropping
|
||||
// them under backpressure can leave exec/TUI waiting forever even though
|
||||
@@ -281,6 +313,22 @@ pub struct InProcessAppServerClient {
|
||||
thread_manager: Arc<ThreadManager>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct InProcessAppServerRequestHandle {
|
||||
command_tx: mpsc::Sender<ClientCommand>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum AppServerRequestHandle {
|
||||
InProcess(InProcessAppServerRequestHandle),
|
||||
Remote(crate::remote::RemoteAppServerRequestHandle),
|
||||
}
|
||||
|
||||
pub enum AppServerClient {
|
||||
InProcess(InProcessAppServerClient),
|
||||
Remote(RemoteAppServerClient),
|
||||
}
|
||||
|
||||
impl InProcessAppServerClient {
|
||||
/// Starts the in-process runtime and facade worker task.
|
||||
///
|
||||
@@ -457,6 +505,12 @@ impl InProcessAppServerClient {
|
||||
self.thread_manager.clone()
|
||||
}
|
||||
|
||||
pub fn request_handle(&self) -> InProcessAppServerRequestHandle {
|
||||
InProcessAppServerRequestHandle {
|
||||
command_tx: self.command_tx.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends a typed client request and returns raw JSON-RPC result.
|
||||
///
|
||||
/// Callers that expect a concrete response type should usually prefer
|
||||
@@ -641,9 +695,141 @@ impl InProcessAppServerClient {
|
||||
}
|
||||
}
|
||||
|
||||
impl InProcessAppServerRequestHandle {
|
||||
pub async fn request(&self, request: ClientRequest) -> IoResult<RequestResult> {
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
self.command_tx
|
||||
.send(ClientCommand::Request {
|
||||
request: Box::new(request),
|
||||
response_tx,
|
||||
})
|
||||
.await
|
||||
.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"in-process app-server worker channel is closed",
|
||||
)
|
||||
})?;
|
||||
response_rx.await.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"in-process app-server request channel is closed",
|
||||
)
|
||||
})?
|
||||
}
|
||||
|
||||
pub async fn request_typed<T>(&self, request: ClientRequest) -> Result<T, TypedRequestError>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let method = request_method_name(&request);
|
||||
let response =
|
||||
self.request(request)
|
||||
.await
|
||||
.map_err(|source| TypedRequestError::Transport {
|
||||
method: method.clone(),
|
||||
source,
|
||||
})?;
|
||||
let result = response.map_err(|source| TypedRequestError::Server {
|
||||
method: method.clone(),
|
||||
source,
|
||||
})?;
|
||||
serde_json::from_value(result)
|
||||
.map_err(|source| TypedRequestError::Deserialize { method, source })
|
||||
}
|
||||
}
|
||||
|
||||
impl AppServerRequestHandle {
|
||||
pub async fn request(&self, request: ClientRequest) -> IoResult<RequestResult> {
|
||||
match self {
|
||||
Self::InProcess(handle) => handle.request(request).await,
|
||||
Self::Remote(handle) => handle.request(request).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn request_typed<T>(&self, request: ClientRequest) -> Result<T, TypedRequestError>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
match self {
|
||||
Self::InProcess(handle) => handle.request_typed(request).await,
|
||||
Self::Remote(handle) => handle.request_typed(request).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AppServerClient {
|
||||
pub async fn request(&self, request: ClientRequest) -> IoResult<RequestResult> {
|
||||
match self {
|
||||
Self::InProcess(client) => client.request(request).await,
|
||||
Self::Remote(client) => client.request(request).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn request_typed<T>(&self, request: ClientRequest) -> Result<T, TypedRequestError>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
match self {
|
||||
Self::InProcess(client) => client.request_typed(request).await,
|
||||
Self::Remote(client) => client.request_typed(request).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn notify(&self, notification: ClientNotification) -> IoResult<()> {
|
||||
match self {
|
||||
Self::InProcess(client) => client.notify(notification).await,
|
||||
Self::Remote(client) => client.notify(notification).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn resolve_server_request(
|
||||
&self,
|
||||
request_id: RequestId,
|
||||
result: JsonRpcResult,
|
||||
) -> IoResult<()> {
|
||||
match self {
|
||||
Self::InProcess(client) => client.resolve_server_request(request_id, result).await,
|
||||
Self::Remote(client) => client.resolve_server_request(request_id, result).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn reject_server_request(
|
||||
&self,
|
||||
request_id: RequestId,
|
||||
error: JSONRPCErrorError,
|
||||
) -> IoResult<()> {
|
||||
match self {
|
||||
Self::InProcess(client) => client.reject_server_request(request_id, error).await,
|
||||
Self::Remote(client) => client.reject_server_request(request_id, error).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn next_event(&mut self) -> Option<AppServerEvent> {
|
||||
match self {
|
||||
Self::InProcess(client) => client.next_event().await.map(Into::into),
|
||||
Self::Remote(client) => client.next_event().await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn shutdown(self) -> IoResult<()> {
|
||||
match self {
|
||||
Self::InProcess(client) => client.shutdown().await,
|
||||
Self::Remote(client) => client.shutdown().await,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_handle(&self) -> AppServerRequestHandle {
|
||||
match self {
|
||||
Self::InProcess(client) => AppServerRequestHandle::InProcess(client.request_handle()),
|
||||
Self::Remote(client) => AppServerRequestHandle::Remote(client.request_handle()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts the JSON-RPC method name for diagnostics without extending the
|
||||
/// protocol crate with in-process-only helpers.
|
||||
fn request_method_name(request: &ClientRequest) -> String {
|
||||
pub(crate) fn request_method_name(request: &ClientRequest) -> String {
|
||||
serde_json::to_value(request)
|
||||
.ok()
|
||||
.and_then(|value| {
|
||||
@@ -658,16 +844,29 @@ fn request_method_name(request: &ClientRequest) -> String {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use codex_app_server_protocol::AccountUpdatedNotification;
|
||||
use codex_app_server_protocol::ConfigRequirementsReadResponse;
|
||||
use codex_app_server_protocol::GetAccountResponse;
|
||||
use codex_app_server_protocol::JSONRPCMessage;
|
||||
use codex_app_server_protocol::JSONRPCRequest;
|
||||
use codex_app_server_protocol::JSONRPCResponse;
|
||||
use codex_app_server_protocol::ServerNotification;
|
||||
use codex_app_server_protocol::SessionSource as ApiSessionSource;
|
||||
use codex_app_server_protocol::ThreadStartParams;
|
||||
use codex_app_server_protocol::ThreadStartResponse;
|
||||
use codex_app_server_protocol::ToolRequestUserInputParams;
|
||||
use codex_app_server_protocol::ToolRequestUserInputQuestion;
|
||||
use codex_core::AuthManager;
|
||||
use codex_core::ThreadManager;
|
||||
use codex_core::config::ConfigBuilder;
|
||||
use futures::SinkExt;
|
||||
use futures::StreamExt;
|
||||
use pretty_assertions::assert_eq;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::time::Duration;
|
||||
use tokio::time::timeout;
|
||||
use tokio_tungstenite::accept_async;
|
||||
use tokio_tungstenite::tungstenite::Message;
|
||||
|
||||
async fn build_test_config() -> Config {
|
||||
match ConfigBuilder::default().build().await {
|
||||
@@ -705,6 +904,97 @@ mod tests {
|
||||
start_test_client_with_capacity(session_source, DEFAULT_IN_PROCESS_CHANNEL_CAPACITY).await
|
||||
}
|
||||
|
||||
async fn start_test_remote_server<F, Fut>(handler: F) -> String
|
||||
where
|
||||
F: FnOnce(tokio_tungstenite::WebSocketStream<tokio::net::TcpStream>) -> Fut
|
||||
+ Send
|
||||
+ 'static,
|
||||
Fut: std::future::Future<Output = ()> + Send + 'static,
|
||||
{
|
||||
let listener = TcpListener::bind("127.0.0.1:0")
|
||||
.await
|
||||
.expect("listener should bind");
|
||||
let addr = listener.local_addr().expect("listener address");
|
||||
tokio::spawn(async move {
|
||||
let (stream, _) = listener.accept().await.expect("accept should succeed");
|
||||
let websocket = accept_async(stream)
|
||||
.await
|
||||
.expect("websocket upgrade should succeed");
|
||||
handler(websocket).await;
|
||||
});
|
||||
format!("ws://{addr}")
|
||||
}
|
||||
|
||||
async fn expect_remote_initialize(
|
||||
websocket: &mut tokio_tungstenite::WebSocketStream<tokio::net::TcpStream>,
|
||||
) {
|
||||
let JSONRPCMessage::Request(request) = read_websocket_message(websocket).await else {
|
||||
panic!("expected initialize request");
|
||||
};
|
||||
assert_eq!(request.method, "initialize");
|
||||
write_websocket_message(
|
||||
websocket,
|
||||
JSONRPCMessage::Response(JSONRPCResponse {
|
||||
id: request.id,
|
||||
result: serde_json::json!({}),
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let JSONRPCMessage::Notification(notification) = read_websocket_message(websocket).await
|
||||
else {
|
||||
panic!("expected initialized notification");
|
||||
};
|
||||
assert_eq!(notification.method, "initialized");
|
||||
}
|
||||
|
||||
async fn read_websocket_message(
|
||||
websocket: &mut tokio_tungstenite::WebSocketStream<tokio::net::TcpStream>,
|
||||
) -> JSONRPCMessage {
|
||||
loop {
|
||||
let frame = websocket
|
||||
.next()
|
||||
.await
|
||||
.expect("frame should be available")
|
||||
.expect("frame should decode");
|
||||
match frame {
|
||||
Message::Text(text) => {
|
||||
return serde_json::from_str::<JSONRPCMessage>(&text)
|
||||
.expect("text frame should be valid JSON-RPC");
|
||||
}
|
||||
Message::Binary(_) | Message::Ping(_) | Message::Pong(_) | Message::Frame(_) => {
|
||||
continue;
|
||||
}
|
||||
Message::Close(_) => panic!("unexpected close frame"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn write_websocket_message(
|
||||
websocket: &mut tokio_tungstenite::WebSocketStream<tokio::net::TcpStream>,
|
||||
message: JSONRPCMessage,
|
||||
) {
|
||||
websocket
|
||||
.send(Message::Text(
|
||||
serde_json::to_string(&message)
|
||||
.expect("message should serialize")
|
||||
.into(),
|
||||
))
|
||||
.await
|
||||
.expect("message should send");
|
||||
}
|
||||
|
||||
fn test_remote_connect_args(websocket_url: String) -> RemoteAppServerConnectArgs {
|
||||
RemoteAppServerConnectArgs {
|
||||
websocket_url,
|
||||
client_name: "codex-app-server-client-test".to_string(),
|
||||
client_version: "0.0.0-test".to_string(),
|
||||
experimental_api: true,
|
||||
opt_out_notification_methods: Vec::new(),
|
||||
channel_capacity: 8,
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn typed_request_roundtrip_works() {
|
||||
let client = start_test_client(SessionSource::Exec).await;
|
||||
@@ -743,6 +1033,10 @@ mod tests {
|
||||
for (session_source, expected_source) in [
|
||||
(SessionSource::Exec, ApiSessionSource::Exec),
|
||||
(SessionSource::Cli, ApiSessionSource::Cli),
|
||||
(
|
||||
SessionSource::Custom("atlas".to_string()),
|
||||
ApiSessionSource::Custom("atlas".to_string()),
|
||||
),
|
||||
] {
|
||||
let client = start_test_client(session_source).await;
|
||||
let parsed: ThreadStartResponse = client
|
||||
@@ -802,6 +1096,354 @@ mod tests {
|
||||
client.shutdown().await.expect("shutdown should complete");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remote_typed_request_roundtrip_works() {
|
||||
let websocket_url = start_test_remote_server(|mut websocket| async move {
|
||||
expect_remote_initialize(&mut websocket).await;
|
||||
let JSONRPCMessage::Request(request) = read_websocket_message(&mut websocket).await
|
||||
else {
|
||||
panic!("expected account/read request");
|
||||
};
|
||||
assert_eq!(request.method, "account/read");
|
||||
write_websocket_message(
|
||||
&mut websocket,
|
||||
JSONRPCMessage::Response(JSONRPCResponse {
|
||||
id: request.id,
|
||||
result: serde_json::to_value(GetAccountResponse {
|
||||
account: None,
|
||||
requires_openai_auth: false,
|
||||
})
|
||||
.expect("response should serialize"),
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
})
|
||||
.await;
|
||||
let client = RemoteAppServerClient::connect(test_remote_connect_args(websocket_url))
|
||||
.await
|
||||
.expect("remote client should connect");
|
||||
|
||||
let response: GetAccountResponse = client
|
||||
.request_typed(ClientRequest::GetAccount {
|
||||
request_id: RequestId::Integer(1),
|
||||
params: codex_app_server_protocol::GetAccountParams {
|
||||
refresh_token: false,
|
||||
},
|
||||
})
|
||||
.await
|
||||
.expect("typed request should succeed");
|
||||
assert_eq!(response.account, None);
|
||||
|
||||
client.shutdown().await.expect("shutdown should complete");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remote_duplicate_request_id_keeps_original_waiter() {
|
||||
let (first_request_seen_tx, first_request_seen_rx) = tokio::sync::oneshot::channel();
|
||||
let websocket_url = start_test_remote_server(|mut websocket| async move {
|
||||
expect_remote_initialize(&mut websocket).await;
|
||||
let JSONRPCMessage::Request(request) = read_websocket_message(&mut websocket).await
|
||||
else {
|
||||
panic!("expected account/read request");
|
||||
};
|
||||
assert_eq!(request.method, "account/read");
|
||||
first_request_seen_tx
|
||||
.send(request.id.clone())
|
||||
.expect("request id should send");
|
||||
assert!(
|
||||
timeout(
|
||||
Duration::from_millis(100),
|
||||
read_websocket_message(&mut websocket)
|
||||
)
|
||||
.await
|
||||
.is_err(),
|
||||
"duplicate request should not be forwarded to the server"
|
||||
);
|
||||
write_websocket_message(
|
||||
&mut websocket,
|
||||
JSONRPCMessage::Response(JSONRPCResponse {
|
||||
id: request.id,
|
||||
result: serde_json::to_value(GetAccountResponse {
|
||||
account: None,
|
||||
requires_openai_auth: false,
|
||||
})
|
||||
.expect("response should serialize"),
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
let _ = websocket.next().await;
|
||||
})
|
||||
.await;
|
||||
let client = RemoteAppServerClient::connect(test_remote_connect_args(websocket_url))
|
||||
.await
|
||||
.expect("remote client should connect");
|
||||
let first_request_handle = client.request_handle();
|
||||
let second_request_handle = first_request_handle.clone();
|
||||
|
||||
let first_request = tokio::spawn(async move {
|
||||
first_request_handle
|
||||
.request_typed::<GetAccountResponse>(ClientRequest::GetAccount {
|
||||
request_id: RequestId::Integer(1),
|
||||
params: codex_app_server_protocol::GetAccountParams {
|
||||
refresh_token: false,
|
||||
},
|
||||
})
|
||||
.await
|
||||
});
|
||||
|
||||
let first_request_id = first_request_seen_rx
|
||||
.await
|
||||
.expect("server should observe the first request");
|
||||
assert_eq!(first_request_id, RequestId::Integer(1));
|
||||
|
||||
let second_err = second_request_handle
|
||||
.request_typed::<GetAccountResponse>(ClientRequest::GetAccount {
|
||||
request_id: RequestId::Integer(1),
|
||||
params: codex_app_server_protocol::GetAccountParams {
|
||||
refresh_token: false,
|
||||
},
|
||||
})
|
||||
.await
|
||||
.expect_err("duplicate request id should be rejected");
|
||||
assert_eq!(
|
||||
second_err.to_string(),
|
||||
"account/read transport error: duplicate remote app-server request id `1`"
|
||||
);
|
||||
|
||||
let first_response = first_request
|
||||
.await
|
||||
.expect("first request task should join")
|
||||
.expect("first request should succeed");
|
||||
assert_eq!(
|
||||
first_response,
|
||||
GetAccountResponse {
|
||||
account: None,
|
||||
requires_openai_auth: false,
|
||||
}
|
||||
);
|
||||
|
||||
client.shutdown().await.expect("shutdown should complete");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remote_notifications_arrive_over_websocket() {
|
||||
let websocket_url = start_test_remote_server(|mut websocket| async move {
|
||||
expect_remote_initialize(&mut websocket).await;
|
||||
write_websocket_message(
|
||||
&mut websocket,
|
||||
JSONRPCMessage::Notification(
|
||||
serde_json::from_value(
|
||||
serde_json::to_value(ServerNotification::AccountUpdated(
|
||||
AccountUpdatedNotification {
|
||||
auth_mode: None,
|
||||
plan_type: None,
|
||||
},
|
||||
))
|
||||
.expect("notification should serialize"),
|
||||
)
|
||||
.expect("notification should convert to JSON-RPC"),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
})
|
||||
.await;
|
||||
let mut client = RemoteAppServerClient::connect(test_remote_connect_args(websocket_url))
|
||||
.await
|
||||
.expect("remote client should connect");
|
||||
|
||||
let event = client.next_event().await.expect("event should arrive");
|
||||
assert!(matches!(
|
||||
event,
|
||||
AppServerEvent::ServerNotification(ServerNotification::AccountUpdated(_))
|
||||
));
|
||||
|
||||
client.shutdown().await.expect("shutdown should complete");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remote_server_request_resolution_roundtrip_works() {
|
||||
let websocket_url = start_test_remote_server(|mut websocket| async move {
|
||||
expect_remote_initialize(&mut websocket).await;
|
||||
let request_id = RequestId::String("srv-1".to_string());
|
||||
let server_request = JSONRPCRequest {
|
||||
id: request_id.clone(),
|
||||
method: "item/tool/requestUserInput".to_string(),
|
||||
params: Some(
|
||||
serde_json::to_value(ToolRequestUserInputParams {
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
item_id: "call-1".to_string(),
|
||||
questions: vec![ToolRequestUserInputQuestion {
|
||||
id: "question-1".to_string(),
|
||||
header: "Mode".to_string(),
|
||||
question: "Pick one".to_string(),
|
||||
is_other: false,
|
||||
is_secret: false,
|
||||
options: Some(vec![]),
|
||||
}],
|
||||
})
|
||||
.expect("params should serialize"),
|
||||
),
|
||||
trace: None,
|
||||
};
|
||||
write_websocket_message(&mut websocket, JSONRPCMessage::Request(server_request)).await;
|
||||
|
||||
let JSONRPCMessage::Response(response) = read_websocket_message(&mut websocket).await
|
||||
else {
|
||||
panic!("expected server request response");
|
||||
};
|
||||
assert_eq!(response.id, request_id);
|
||||
})
|
||||
.await;
|
||||
let mut client = RemoteAppServerClient::connect(test_remote_connect_args(websocket_url))
|
||||
.await
|
||||
.expect("remote client should connect");
|
||||
|
||||
let AppServerEvent::ServerRequest(request) = client
|
||||
.next_event()
|
||||
.await
|
||||
.expect("request event should arrive")
|
||||
else {
|
||||
panic!("expected server request event");
|
||||
};
|
||||
client
|
||||
.resolve_server_request(request.id().clone(), serde_json::json!({}))
|
||||
.await
|
||||
.expect("server request should resolve");
|
||||
|
||||
client.shutdown().await.expect("shutdown should complete");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remote_server_request_received_during_initialize_is_delivered() {
|
||||
let websocket_url = start_test_remote_server(|mut websocket| async move {
|
||||
let JSONRPCMessage::Request(request) = read_websocket_message(&mut websocket).await
|
||||
else {
|
||||
panic!("expected initialize request");
|
||||
};
|
||||
assert_eq!(request.method, "initialize");
|
||||
|
||||
let request_id = RequestId::String("srv-init".to_string());
|
||||
write_websocket_message(
|
||||
&mut websocket,
|
||||
JSONRPCMessage::Request(JSONRPCRequest {
|
||||
id: request_id.clone(),
|
||||
method: "item/tool/requestUserInput".to_string(),
|
||||
params: Some(
|
||||
serde_json::to_value(ToolRequestUserInputParams {
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
item_id: "call-1".to_string(),
|
||||
questions: vec![ToolRequestUserInputQuestion {
|
||||
id: "question-1".to_string(),
|
||||
header: "Mode".to_string(),
|
||||
question: "Pick one".to_string(),
|
||||
is_other: false,
|
||||
is_secret: false,
|
||||
options: Some(vec![]),
|
||||
}],
|
||||
})
|
||||
.expect("params should serialize"),
|
||||
),
|
||||
trace: None,
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
write_websocket_message(
|
||||
&mut websocket,
|
||||
JSONRPCMessage::Response(JSONRPCResponse {
|
||||
id: request.id,
|
||||
result: serde_json::json!({}),
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let JSONRPCMessage::Notification(notification) =
|
||||
read_websocket_message(&mut websocket).await
|
||||
else {
|
||||
panic!("expected initialized notification");
|
||||
};
|
||||
assert_eq!(notification.method, "initialized");
|
||||
|
||||
let JSONRPCMessage::Response(response) = read_websocket_message(&mut websocket).await
|
||||
else {
|
||||
panic!("expected server request response");
|
||||
};
|
||||
assert_eq!(response.id, request_id);
|
||||
})
|
||||
.await;
|
||||
let mut client = RemoteAppServerClient::connect(test_remote_connect_args(websocket_url))
|
||||
.await
|
||||
.expect("remote client should connect");
|
||||
|
||||
let AppServerEvent::ServerRequest(request) = client
|
||||
.next_event()
|
||||
.await
|
||||
.expect("request event should arrive")
|
||||
else {
|
||||
panic!("expected server request event");
|
||||
};
|
||||
client
|
||||
.resolve_server_request(request.id().clone(), serde_json::json!({}))
|
||||
.await
|
||||
.expect("server request should resolve");
|
||||
|
||||
client.shutdown().await.expect("shutdown should complete");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remote_unknown_server_request_is_rejected() {
|
||||
let websocket_url = start_test_remote_server(|mut websocket| async move {
|
||||
expect_remote_initialize(&mut websocket).await;
|
||||
let request_id = RequestId::String("srv-unknown".to_string());
|
||||
write_websocket_message(
|
||||
&mut websocket,
|
||||
JSONRPCMessage::Request(JSONRPCRequest {
|
||||
id: request_id.clone(),
|
||||
method: "thread/unknown".to_string(),
|
||||
params: None,
|
||||
trace: None,
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let JSONRPCMessage::Error(response) = read_websocket_message(&mut websocket).await
|
||||
else {
|
||||
panic!("expected JSON-RPC error response");
|
||||
};
|
||||
assert_eq!(response.id, request_id);
|
||||
assert_eq!(response.error.code, -32601);
|
||||
assert_eq!(
|
||||
response.error.message,
|
||||
"unsupported remote app-server request `thread/unknown`"
|
||||
);
|
||||
})
|
||||
.await;
|
||||
let client = RemoteAppServerClient::connect(test_remote_connect_args(websocket_url))
|
||||
.await
|
||||
.expect("remote client should connect");
|
||||
|
||||
client.shutdown().await.expect("shutdown should complete");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remote_disconnect_surfaces_as_event() {
|
||||
let websocket_url = start_test_remote_server(|mut websocket| async move {
|
||||
expect_remote_initialize(&mut websocket).await;
|
||||
websocket.close(None).await.expect("close should succeed");
|
||||
})
|
||||
.await;
|
||||
let mut client = RemoteAppServerClient::connect(test_remote_connect_args(websocket_url))
|
||||
.await
|
||||
.expect("remote client should connect");
|
||||
|
||||
let event = client
|
||||
.next_event()
|
||||
.await
|
||||
.expect("disconnect event should arrive");
|
||||
assert!(matches!(event, AppServerEvent::Disconnected { .. }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn typed_request_error_exposes_sources() {
|
||||
let transport = TypedRequestError::Transport {
|
||||
|
||||
911
codex-rs/app-server-client/src/remote.rs
Normal file
911
codex-rs/app-server-client/src/remote.rs
Normal file
@@ -0,0 +1,911 @@
|
||||
/*
|
||||
This module implements the websocket-backed app-server client transport.
|
||||
|
||||
It owns the remote connection lifecycle, including the initialize/initialized
|
||||
handshake, JSON-RPC request/response routing, server-request resolution, and
|
||||
notification streaming. The rest of the crate uses the same `AppServerEvent`
|
||||
surface for both in-process and remote transports, so callers such as
|
||||
`tui_app_server` can switch between them without changing their higher-level
|
||||
session logic.
|
||||
*/
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::VecDeque;
|
||||
use std::io::Error as IoError;
|
||||
use std::io::ErrorKind;
|
||||
use std::io::Result as IoResult;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::AppServerEvent;
|
||||
use crate::RequestResult;
|
||||
use crate::SHUTDOWN_TIMEOUT;
|
||||
use crate::TypedRequestError;
|
||||
use crate::request_method_name;
|
||||
use codex_app_server_protocol::ClientInfo;
|
||||
use codex_app_server_protocol::ClientNotification;
|
||||
use codex_app_server_protocol::ClientRequest;
|
||||
use codex_app_server_protocol::InitializeCapabilities;
|
||||
use codex_app_server_protocol::InitializeParams;
|
||||
use codex_app_server_protocol::JSONRPCError;
|
||||
use codex_app_server_protocol::JSONRPCErrorError;
|
||||
use codex_app_server_protocol::JSONRPCMessage;
|
||||
use codex_app_server_protocol::JSONRPCNotification;
|
||||
use codex_app_server_protocol::JSONRPCRequest;
|
||||
use codex_app_server_protocol::JSONRPCResponse;
|
||||
use codex_app_server_protocol::RequestId;
|
||||
use codex_app_server_protocol::Result as JsonRpcResult;
|
||||
use codex_app_server_protocol::ServerNotification;
|
||||
use codex_app_server_protocol::ServerRequest;
|
||||
use futures::SinkExt;
|
||||
use futures::StreamExt;
|
||||
use serde::de::DeserializeOwned;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::sync::oneshot;
|
||||
use tokio::time::timeout;
|
||||
use tokio_tungstenite::MaybeTlsStream;
|
||||
use tokio_tungstenite::WebSocketStream;
|
||||
use tokio_tungstenite::connect_async;
|
||||
use tokio_tungstenite::tungstenite::Message;
|
||||
use tracing::warn;
|
||||
use url::Url;
|
||||
|
||||
const CONNECT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const INITIALIZE_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RemoteAppServerConnectArgs {
|
||||
pub websocket_url: String,
|
||||
pub client_name: String,
|
||||
pub client_version: String,
|
||||
pub experimental_api: bool,
|
||||
pub opt_out_notification_methods: Vec<String>,
|
||||
pub channel_capacity: usize,
|
||||
}
|
||||
|
||||
impl RemoteAppServerConnectArgs {
|
||||
fn initialize_params(&self) -> InitializeParams {
|
||||
let capabilities = InitializeCapabilities {
|
||||
experimental_api: self.experimental_api,
|
||||
opt_out_notification_methods: if self.opt_out_notification_methods.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(self.opt_out_notification_methods.clone())
|
||||
},
|
||||
};
|
||||
|
||||
InitializeParams {
|
||||
client_info: ClientInfo {
|
||||
name: self.client_name.clone(),
|
||||
title: None,
|
||||
version: self.client_version.clone(),
|
||||
},
|
||||
capabilities: Some(capabilities),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum RemoteClientCommand {
|
||||
Request {
|
||||
request: Box<ClientRequest>,
|
||||
response_tx: oneshot::Sender<IoResult<RequestResult>>,
|
||||
},
|
||||
Notify {
|
||||
notification: ClientNotification,
|
||||
response_tx: oneshot::Sender<IoResult<()>>,
|
||||
},
|
||||
ResolveServerRequest {
|
||||
request_id: RequestId,
|
||||
result: JsonRpcResult,
|
||||
response_tx: oneshot::Sender<IoResult<()>>,
|
||||
},
|
||||
RejectServerRequest {
|
||||
request_id: RequestId,
|
||||
error: JSONRPCErrorError,
|
||||
response_tx: oneshot::Sender<IoResult<()>>,
|
||||
},
|
||||
Shutdown {
|
||||
response_tx: oneshot::Sender<IoResult<()>>,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct RemoteAppServerClient {
|
||||
command_tx: mpsc::Sender<RemoteClientCommand>,
|
||||
event_rx: mpsc::Receiver<AppServerEvent>,
|
||||
pending_events: VecDeque<AppServerEvent>,
|
||||
worker_handle: tokio::task::JoinHandle<()>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RemoteAppServerRequestHandle {
|
||||
command_tx: mpsc::Sender<RemoteClientCommand>,
|
||||
}
|
||||
|
||||
impl RemoteAppServerClient {
|
||||
pub async fn connect(args: RemoteAppServerConnectArgs) -> IoResult<Self> {
|
||||
let channel_capacity = args.channel_capacity.max(1);
|
||||
let websocket_url = args.websocket_url.clone();
|
||||
let url = Url::parse(&websocket_url).map_err(|err| {
|
||||
IoError::new(
|
||||
ErrorKind::InvalidInput,
|
||||
format!("invalid websocket URL `{websocket_url}`: {err}"),
|
||||
)
|
||||
})?;
|
||||
let stream = timeout(CONNECT_TIMEOUT, connect_async(url.as_str()))
|
||||
.await
|
||||
.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::TimedOut,
|
||||
format!("timed out connecting to remote app server at `{websocket_url}`"),
|
||||
)
|
||||
})?
|
||||
.map(|(stream, _response)| stream)
|
||||
.map_err(|err| {
|
||||
IoError::other(format!(
|
||||
"failed to connect to remote app server at `{websocket_url}`: {err}"
|
||||
))
|
||||
})?;
|
||||
let mut stream = stream;
|
||||
let pending_events = initialize_remote_connection(
|
||||
&mut stream,
|
||||
&websocket_url,
|
||||
args.initialize_params(),
|
||||
INITIALIZE_TIMEOUT,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let (command_tx, mut command_rx) = mpsc::channel::<RemoteClientCommand>(channel_capacity);
|
||||
let (event_tx, event_rx) = mpsc::channel::<AppServerEvent>(channel_capacity);
|
||||
let worker_handle = tokio::spawn(async move {
|
||||
let mut pending_requests =
|
||||
HashMap::<RequestId, oneshot::Sender<IoResult<RequestResult>>>::new();
|
||||
let mut skipped_events = 0usize;
|
||||
loop {
|
||||
tokio::select! {
|
||||
command = command_rx.recv() => {
|
||||
let Some(command) = command else {
|
||||
let _ = stream.close(None).await;
|
||||
break;
|
||||
};
|
||||
match command {
|
||||
RemoteClientCommand::Request { request, response_tx } => {
|
||||
let request_id = request_id_from_client_request(&request);
|
||||
if pending_requests.contains_key(&request_id) {
|
||||
let _ = response_tx.send(Err(IoError::new(
|
||||
ErrorKind::InvalidInput,
|
||||
format!("duplicate remote app-server request id `{request_id}`"),
|
||||
)));
|
||||
continue;
|
||||
}
|
||||
pending_requests.insert(request_id.clone(), response_tx);
|
||||
if let Err(err) = write_jsonrpc_message(
|
||||
&mut stream,
|
||||
JSONRPCMessage::Request(jsonrpc_request_from_client_request(*request)),
|
||||
&websocket_url,
|
||||
)
|
||||
.await
|
||||
{
|
||||
let err_message = err.to_string();
|
||||
if let Some(response_tx) = pending_requests.remove(&request_id) {
|
||||
let _ = response_tx.send(Err(err));
|
||||
}
|
||||
let _ = deliver_event(
|
||||
&event_tx,
|
||||
&mut skipped_events,
|
||||
AppServerEvent::Disconnected {
|
||||
message: format!(
|
||||
"remote app server at `{websocket_url}` write failed: {err_message}"
|
||||
),
|
||||
},
|
||||
&mut stream,
|
||||
)
|
||||
.await;
|
||||
break;
|
||||
}
|
||||
}
|
||||
RemoteClientCommand::Notify { notification, response_tx } => {
|
||||
let result = write_jsonrpc_message(
|
||||
&mut stream,
|
||||
JSONRPCMessage::Notification(
|
||||
jsonrpc_notification_from_client_notification(notification),
|
||||
),
|
||||
&websocket_url,
|
||||
)
|
||||
.await;
|
||||
let _ = response_tx.send(result);
|
||||
}
|
||||
RemoteClientCommand::ResolveServerRequest {
|
||||
request_id,
|
||||
result,
|
||||
response_tx,
|
||||
} => {
|
||||
let result = write_jsonrpc_message(
|
||||
&mut stream,
|
||||
JSONRPCMessage::Response(JSONRPCResponse {
|
||||
id: request_id,
|
||||
result,
|
||||
}),
|
||||
&websocket_url,
|
||||
)
|
||||
.await;
|
||||
let _ = response_tx.send(result);
|
||||
}
|
||||
RemoteClientCommand::RejectServerRequest {
|
||||
request_id,
|
||||
error,
|
||||
response_tx,
|
||||
} => {
|
||||
let result = write_jsonrpc_message(
|
||||
&mut stream,
|
||||
JSONRPCMessage::Error(JSONRPCError {
|
||||
error,
|
||||
id: request_id,
|
||||
}),
|
||||
&websocket_url,
|
||||
)
|
||||
.await;
|
||||
let _ = response_tx.send(result);
|
||||
}
|
||||
RemoteClientCommand::Shutdown { response_tx } => {
|
||||
let close_result = stream.close(None).await.map_err(|err| {
|
||||
IoError::other(format!(
|
||||
"failed to close websocket app server `{websocket_url}`: {err}"
|
||||
))
|
||||
});
|
||||
let _ = response_tx.send(close_result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
message = stream.next() => {
|
||||
match message {
|
||||
Some(Ok(Message::Text(text))) => {
|
||||
match serde_json::from_str::<JSONRPCMessage>(&text) {
|
||||
Ok(JSONRPCMessage::Response(response)) => {
|
||||
if let Some(response_tx) = pending_requests.remove(&response.id) {
|
||||
let _ = response_tx.send(Ok(Ok(response.result)));
|
||||
}
|
||||
}
|
||||
Ok(JSONRPCMessage::Error(error)) => {
|
||||
if let Some(response_tx) = pending_requests.remove(&error.id) {
|
||||
let _ = response_tx.send(Ok(Err(error.error)));
|
||||
}
|
||||
}
|
||||
Ok(JSONRPCMessage::Notification(notification)) => {
|
||||
let event = app_server_event_from_notification(notification);
|
||||
if let Err(err) = deliver_event(
|
||||
&event_tx,
|
||||
&mut skipped_events,
|
||||
event,
|
||||
&mut stream,
|
||||
)
|
||||
.await
|
||||
{
|
||||
warn!(%err, "failed to deliver remote app-server event");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(JSONRPCMessage::Request(request)) => {
|
||||
let request_id = request.id.clone();
|
||||
let method = request.method.clone();
|
||||
match ServerRequest::try_from(request) {
|
||||
Ok(request) => {
|
||||
if let Err(err) = deliver_event(
|
||||
&event_tx,
|
||||
&mut skipped_events,
|
||||
AppServerEvent::ServerRequest(request),
|
||||
&mut stream,
|
||||
)
|
||||
.await
|
||||
{
|
||||
warn!(%err, "failed to deliver remote app-server server request");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(%err, method, "rejecting unknown remote app-server request");
|
||||
if let Err(reject_err) = write_jsonrpc_message(
|
||||
&mut stream,
|
||||
JSONRPCMessage::Error(JSONRPCError {
|
||||
error: JSONRPCErrorError {
|
||||
code: -32601,
|
||||
message: format!(
|
||||
"unsupported remote app-server request `{method}`"
|
||||
),
|
||||
data: None,
|
||||
},
|
||||
id: request_id,
|
||||
}),
|
||||
&websocket_url,
|
||||
)
|
||||
.await
|
||||
{
|
||||
let err_message = reject_err.to_string();
|
||||
let _ = deliver_event(
|
||||
&event_tx,
|
||||
&mut skipped_events,
|
||||
AppServerEvent::Disconnected {
|
||||
message: format!(
|
||||
"remote app server at `{websocket_url}` write failed: {err_message}"
|
||||
),
|
||||
},
|
||||
&mut stream,
|
||||
)
|
||||
.await;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
let _ = deliver_event(
|
||||
&event_tx,
|
||||
&mut skipped_events,
|
||||
AppServerEvent::Disconnected {
|
||||
message: format!(
|
||||
"remote app server at `{websocket_url}` sent invalid JSON-RPC: {err}"
|
||||
),
|
||||
},
|
||||
&mut stream,
|
||||
)
|
||||
.await;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(Ok(Message::Close(frame))) => {
|
||||
let reason = frame
|
||||
.as_ref()
|
||||
.map(|frame| frame.reason.to_string())
|
||||
.filter(|reason| !reason.is_empty())
|
||||
.unwrap_or_else(|| "connection closed".to_string());
|
||||
let _ = deliver_event(
|
||||
&event_tx,
|
||||
&mut skipped_events,
|
||||
AppServerEvent::Disconnected {
|
||||
message: format!(
|
||||
"remote app server at `{websocket_url}` disconnected: {reason}"
|
||||
),
|
||||
},
|
||||
&mut stream,
|
||||
)
|
||||
.await;
|
||||
break;
|
||||
}
|
||||
Some(Ok(Message::Binary(_)))
|
||||
| Some(Ok(Message::Ping(_)))
|
||||
| Some(Ok(Message::Pong(_)))
|
||||
| Some(Ok(Message::Frame(_))) => {}
|
||||
Some(Err(err)) => {
|
||||
let _ = deliver_event(
|
||||
&event_tx,
|
||||
&mut skipped_events,
|
||||
AppServerEvent::Disconnected {
|
||||
message: format!(
|
||||
"remote app server at `{websocket_url}` transport failed: {err}"
|
||||
),
|
||||
},
|
||||
&mut stream,
|
||||
)
|
||||
.await;
|
||||
break;
|
||||
}
|
||||
None => {
|
||||
let _ = deliver_event(
|
||||
&event_tx,
|
||||
&mut skipped_events,
|
||||
AppServerEvent::Disconnected {
|
||||
message: format!(
|
||||
"remote app server at `{websocket_url}` closed the connection"
|
||||
),
|
||||
},
|
||||
&mut stream,
|
||||
)
|
||||
.await;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let err = IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server worker channel is closed",
|
||||
);
|
||||
for (_, response_tx) in pending_requests {
|
||||
let _ = response_tx.send(Err(IoError::new(err.kind(), err.to_string())));
|
||||
}
|
||||
});
|
||||
|
||||
Ok(Self {
|
||||
command_tx,
|
||||
event_rx,
|
||||
pending_events: pending_events.into(),
|
||||
worker_handle,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn request_handle(&self) -> RemoteAppServerRequestHandle {
|
||||
RemoteAppServerRequestHandle {
|
||||
command_tx: self.command_tx.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn request(&self, request: ClientRequest) -> IoResult<RequestResult> {
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
self.command_tx
|
||||
.send(RemoteClientCommand::Request {
|
||||
request: Box::new(request),
|
||||
response_tx,
|
||||
})
|
||||
.await
|
||||
.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server worker channel is closed",
|
||||
)
|
||||
})?;
|
||||
response_rx.await.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server request channel is closed",
|
||||
)
|
||||
})?
|
||||
}
|
||||
|
||||
pub async fn request_typed<T>(&self, request: ClientRequest) -> Result<T, TypedRequestError>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let method = request_method_name(&request);
|
||||
let response =
|
||||
self.request(request)
|
||||
.await
|
||||
.map_err(|source| TypedRequestError::Transport {
|
||||
method: method.clone(),
|
||||
source,
|
||||
})?;
|
||||
let result = response.map_err(|source| TypedRequestError::Server {
|
||||
method: method.clone(),
|
||||
source,
|
||||
})?;
|
||||
serde_json::from_value(result)
|
||||
.map_err(|source| TypedRequestError::Deserialize { method, source })
|
||||
}
|
||||
|
||||
pub async fn notify(&self, notification: ClientNotification) -> IoResult<()> {
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
self.command_tx
|
||||
.send(RemoteClientCommand::Notify {
|
||||
notification,
|
||||
response_tx,
|
||||
})
|
||||
.await
|
||||
.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server worker channel is closed",
|
||||
)
|
||||
})?;
|
||||
response_rx.await.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server notify channel is closed",
|
||||
)
|
||||
})?
|
||||
}
|
||||
|
||||
pub async fn resolve_server_request(
|
||||
&self,
|
||||
request_id: RequestId,
|
||||
result: JsonRpcResult,
|
||||
) -> IoResult<()> {
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
self.command_tx
|
||||
.send(RemoteClientCommand::ResolveServerRequest {
|
||||
request_id,
|
||||
result,
|
||||
response_tx,
|
||||
})
|
||||
.await
|
||||
.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server worker channel is closed",
|
||||
)
|
||||
})?;
|
||||
response_rx.await.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server resolve channel is closed",
|
||||
)
|
||||
})?
|
||||
}
|
||||
|
||||
pub async fn reject_server_request(
|
||||
&self,
|
||||
request_id: RequestId,
|
||||
error: JSONRPCErrorError,
|
||||
) -> IoResult<()> {
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
self.command_tx
|
||||
.send(RemoteClientCommand::RejectServerRequest {
|
||||
request_id,
|
||||
error,
|
||||
response_tx,
|
||||
})
|
||||
.await
|
||||
.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server worker channel is closed",
|
||||
)
|
||||
})?;
|
||||
response_rx.await.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server reject channel is closed",
|
||||
)
|
||||
})?
|
||||
}
|
||||
|
||||
pub async fn next_event(&mut self) -> Option<AppServerEvent> {
|
||||
if let Some(event) = self.pending_events.pop_front() {
|
||||
return Some(event);
|
||||
}
|
||||
self.event_rx.recv().await
|
||||
}
|
||||
|
||||
pub async fn shutdown(self) -> IoResult<()> {
|
||||
let Self {
|
||||
command_tx,
|
||||
event_rx,
|
||||
pending_events: _pending_events,
|
||||
worker_handle,
|
||||
} = self;
|
||||
let mut worker_handle = worker_handle;
|
||||
drop(event_rx);
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
if command_tx
|
||||
.send(RemoteClientCommand::Shutdown { response_tx })
|
||||
.await
|
||||
.is_ok()
|
||||
&& let Ok(command_result) = timeout(SHUTDOWN_TIMEOUT, response_rx).await
|
||||
{
|
||||
command_result.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server shutdown channel is closed",
|
||||
)
|
||||
})??;
|
||||
}
|
||||
|
||||
if let Err(_elapsed) = timeout(SHUTDOWN_TIMEOUT, &mut worker_handle).await {
|
||||
worker_handle.abort();
|
||||
let _ = worker_handle.await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl RemoteAppServerRequestHandle {
|
||||
pub async fn request(&self, request: ClientRequest) -> IoResult<RequestResult> {
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
self.command_tx
|
||||
.send(RemoteClientCommand::Request {
|
||||
request: Box::new(request),
|
||||
response_tx,
|
||||
})
|
||||
.await
|
||||
.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server worker channel is closed",
|
||||
)
|
||||
})?;
|
||||
response_rx.await.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server request channel is closed",
|
||||
)
|
||||
})?
|
||||
}
|
||||
|
||||
pub async fn request_typed<T>(&self, request: ClientRequest) -> Result<T, TypedRequestError>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let method = request_method_name(&request);
|
||||
let response =
|
||||
self.request(request)
|
||||
.await
|
||||
.map_err(|source| TypedRequestError::Transport {
|
||||
method: method.clone(),
|
||||
source,
|
||||
})?;
|
||||
let result = response.map_err(|source| TypedRequestError::Server {
|
||||
method: method.clone(),
|
||||
source,
|
||||
})?;
|
||||
serde_json::from_value(result)
|
||||
.map_err(|source| TypedRequestError::Deserialize { method, source })
|
||||
}
|
||||
}
|
||||
|
||||
async fn initialize_remote_connection(
|
||||
stream: &mut WebSocketStream<MaybeTlsStream<TcpStream>>,
|
||||
websocket_url: &str,
|
||||
params: InitializeParams,
|
||||
initialize_timeout: Duration,
|
||||
) -> IoResult<Vec<AppServerEvent>> {
|
||||
let initialize_request_id = RequestId::String("initialize".to_string());
|
||||
let mut pending_events = Vec::new();
|
||||
write_jsonrpc_message(
|
||||
stream,
|
||||
JSONRPCMessage::Request(jsonrpc_request_from_client_request(
|
||||
ClientRequest::Initialize {
|
||||
request_id: initialize_request_id.clone(),
|
||||
params,
|
||||
},
|
||||
)),
|
||||
websocket_url,
|
||||
)
|
||||
.await?;
|
||||
|
||||
timeout(initialize_timeout, async {
|
||||
loop {
|
||||
match stream.next().await {
|
||||
Some(Ok(Message::Text(text))) => {
|
||||
let message = serde_json::from_str::<JSONRPCMessage>(&text).map_err(|err| {
|
||||
IoError::other(format!(
|
||||
"remote app server at `{websocket_url}` sent invalid initialize response: {err}"
|
||||
))
|
||||
})?;
|
||||
match message {
|
||||
JSONRPCMessage::Response(response) if response.id == initialize_request_id => {
|
||||
break Ok(());
|
||||
}
|
||||
JSONRPCMessage::Error(error) if error.id == initialize_request_id => {
|
||||
break Err(IoError::other(format!(
|
||||
"remote app server at `{websocket_url}` rejected initialize: {}",
|
||||
error.error.message
|
||||
)));
|
||||
}
|
||||
JSONRPCMessage::Notification(notification) => {
|
||||
pending_events.push(app_server_event_from_notification(notification));
|
||||
}
|
||||
JSONRPCMessage::Request(request) => {
|
||||
let request_id = request.id.clone();
|
||||
let method = request.method.clone();
|
||||
match ServerRequest::try_from(request) {
|
||||
Ok(request) => {
|
||||
pending_events.push(AppServerEvent::ServerRequest(request));
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(%err, method, "rejecting unknown remote app-server request during initialize");
|
||||
write_jsonrpc_message(
|
||||
stream,
|
||||
JSONRPCMessage::Error(JSONRPCError {
|
||||
error: JSONRPCErrorError {
|
||||
code: -32601,
|
||||
message: format!(
|
||||
"unsupported remote app-server request `{method}`"
|
||||
),
|
||||
data: None,
|
||||
},
|
||||
id: request_id,
|
||||
}),
|
||||
websocket_url,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
JSONRPCMessage::Response(_) | JSONRPCMessage::Error(_) => {}
|
||||
}
|
||||
}
|
||||
Some(Ok(Message::Binary(_)))
|
||||
| Some(Ok(Message::Ping(_)))
|
||||
| Some(Ok(Message::Pong(_)))
|
||||
| Some(Ok(Message::Frame(_))) => {}
|
||||
Some(Ok(Message::Close(frame))) => {
|
||||
let reason = frame
|
||||
.as_ref()
|
||||
.map(|frame| frame.reason.to_string())
|
||||
.filter(|reason| !reason.is_empty())
|
||||
.unwrap_or_else(|| "connection closed during initialize".to_string());
|
||||
break Err(IoError::new(
|
||||
ErrorKind::ConnectionAborted,
|
||||
format!(
|
||||
"remote app server at `{websocket_url}` closed during initialize: {reason}"
|
||||
),
|
||||
));
|
||||
}
|
||||
Some(Err(err)) => {
|
||||
break Err(IoError::other(format!(
|
||||
"remote app server at `{websocket_url}` transport failed during initialize: {err}"
|
||||
)));
|
||||
}
|
||||
None => {
|
||||
break Err(IoError::new(
|
||||
ErrorKind::UnexpectedEof,
|
||||
format!("remote app server at `{websocket_url}` closed during initialize"),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::TimedOut,
|
||||
format!("timed out waiting for initialize response from `{websocket_url}`"),
|
||||
)
|
||||
})??;
|
||||
|
||||
write_jsonrpc_message(
|
||||
stream,
|
||||
JSONRPCMessage::Notification(jsonrpc_notification_from_client_notification(
|
||||
ClientNotification::Initialized,
|
||||
)),
|
||||
websocket_url,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(pending_events)
|
||||
}
|
||||
|
||||
fn app_server_event_from_notification(notification: JSONRPCNotification) -> AppServerEvent {
|
||||
match ServerNotification::try_from(notification.clone()) {
|
||||
Ok(notification) => AppServerEvent::ServerNotification(notification),
|
||||
Err(_) => AppServerEvent::LegacyNotification(notification),
|
||||
}
|
||||
}
|
||||
|
||||
async fn deliver_event(
|
||||
event_tx: &mpsc::Sender<AppServerEvent>,
|
||||
skipped_events: &mut usize,
|
||||
event: AppServerEvent,
|
||||
stream: &mut WebSocketStream<MaybeTlsStream<TcpStream>>,
|
||||
) -> IoResult<()> {
|
||||
if *skipped_events > 0 {
|
||||
if event_requires_delivery(&event) {
|
||||
if event_tx
|
||||
.send(AppServerEvent::Lagged {
|
||||
skipped: *skipped_events,
|
||||
})
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
return Err(IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server event consumer channel is closed",
|
||||
));
|
||||
}
|
||||
*skipped_events = 0;
|
||||
} else {
|
||||
match event_tx.try_send(AppServerEvent::Lagged {
|
||||
skipped: *skipped_events,
|
||||
}) {
|
||||
Ok(()) => *skipped_events = 0,
|
||||
Err(mpsc::error::TrySendError::Full(_)) => {
|
||||
*skipped_events = (*skipped_events).saturating_add(1);
|
||||
reject_if_server_request_dropped(stream, &event).await?;
|
||||
return Ok(());
|
||||
}
|
||||
Err(mpsc::error::TrySendError::Closed(_)) => {
|
||||
return Err(IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server event consumer channel is closed",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if event_requires_delivery(&event) {
|
||||
event_tx.send(event).await.map_err(|_| {
|
||||
IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server event consumer channel is closed",
|
||||
)
|
||||
})?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match event_tx.try_send(event) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(mpsc::error::TrySendError::Full(event)) => {
|
||||
*skipped_events = (*skipped_events).saturating_add(1);
|
||||
reject_if_server_request_dropped(stream, &event).await
|
||||
}
|
||||
Err(mpsc::error::TrySendError::Closed(_)) => Err(IoError::new(
|
||||
ErrorKind::BrokenPipe,
|
||||
"remote app-server event consumer channel is closed",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn reject_if_server_request_dropped(
|
||||
stream: &mut WebSocketStream<MaybeTlsStream<TcpStream>>,
|
||||
event: &AppServerEvent,
|
||||
) -> IoResult<()> {
|
||||
let AppServerEvent::ServerRequest(request) = event else {
|
||||
return Ok(());
|
||||
};
|
||||
write_jsonrpc_message(
|
||||
stream,
|
||||
JSONRPCMessage::Error(JSONRPCError {
|
||||
error: JSONRPCErrorError {
|
||||
code: -32001,
|
||||
message: "remote app-server event queue is full".to_string(),
|
||||
data: None,
|
||||
},
|
||||
id: request.id().clone(),
|
||||
}),
|
||||
"<remote-app-server>",
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
fn event_requires_delivery(event: &AppServerEvent) -> bool {
|
||||
match event {
|
||||
AppServerEvent::ServerNotification(ServerNotification::TurnCompleted(_)) => true,
|
||||
AppServerEvent::LegacyNotification(notification) => matches!(
|
||||
notification
|
||||
.method
|
||||
.strip_prefix("codex/event/")
|
||||
.unwrap_or(¬ification.method),
|
||||
"task_complete" | "turn_aborted" | "shutdown_complete"
|
||||
),
|
||||
AppServerEvent::Disconnected { .. } => true,
|
||||
AppServerEvent::Lagged { .. }
|
||||
| AppServerEvent::ServerNotification(_)
|
||||
| AppServerEvent::ServerRequest(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn request_id_from_client_request(request: &ClientRequest) -> RequestId {
|
||||
jsonrpc_request_from_client_request(request.clone()).id
|
||||
}
|
||||
|
||||
fn jsonrpc_request_from_client_request(request: ClientRequest) -> JSONRPCRequest {
|
||||
let value = match serde_json::to_value(request) {
|
||||
Ok(value) => value,
|
||||
Err(err) => panic!("client request should serialize: {err}"),
|
||||
};
|
||||
match serde_json::from_value(value) {
|
||||
Ok(request) => request,
|
||||
Err(err) => panic!("client request should encode as JSON-RPC request: {err}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn jsonrpc_notification_from_client_notification(
|
||||
notification: ClientNotification,
|
||||
) -> JSONRPCNotification {
|
||||
let value = match serde_json::to_value(notification) {
|
||||
Ok(value) => value,
|
||||
Err(err) => panic!("client notification should serialize: {err}"),
|
||||
};
|
||||
match serde_json::from_value(value) {
|
||||
Ok(notification) => notification,
|
||||
Err(err) => panic!("client notification should encode as JSON-RPC notification: {err}"),
|
||||
}
|
||||
}
|
||||
|
||||
async fn write_jsonrpc_message(
|
||||
stream: &mut WebSocketStream<MaybeTlsStream<TcpStream>>,
|
||||
message: JSONRPCMessage,
|
||||
websocket_url: &str,
|
||||
) -> IoResult<()> {
|
||||
let payload = serde_json::to_string(&message).map_err(IoError::other)?;
|
||||
stream
|
||||
.send(Message::Text(payload.into()))
|
||||
.await
|
||||
.map_err(|err| {
|
||||
IoError::other(format!(
|
||||
"failed to write websocket message to `{websocket_url}`: {err}"
|
||||
))
|
||||
})
|
||||
}
|
||||
@@ -163,6 +163,10 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"CollaborationModeListParams": {
|
||||
"description": "EXPERIMENTAL - list collaboration mode presets.",
|
||||
"type": "object"
|
||||
},
|
||||
"CommandExecParams": {
|
||||
"description": "Run a standalone command (argv vector) in the server sandbox without creating a thread or turn.\n\nThe final `command/exec` response is deferred until the process exits and is sent only after all `command/exec/outputDelta` notifications for that connection have been emitted.",
|
||||
"properties": {
|
||||
@@ -871,24 +875,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"FunctionCallOutputPayload": {
|
||||
"description": "The payload we send back to OpenAI when reporting a tool call result.\n\n`body` serializes directly as the wire value for `function_call_output.output`. `success` remains internal metadata for downstream handling.",
|
||||
"properties": {
|
||||
"body": {
|
||||
"$ref": "#/definitions/FunctionCallOutputBody"
|
||||
},
|
||||
"success": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"body"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"FuzzyFileSearchParams": {
|
||||
"properties": {
|
||||
"cancellationToken": {
|
||||
@@ -913,6 +899,50 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"FuzzyFileSearchSessionStartParams": {
|
||||
"properties": {
|
||||
"roots": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"sessionId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"roots",
|
||||
"sessionId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"FuzzyFileSearchSessionStopParams": {
|
||||
"properties": {
|
||||
"sessionId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"sessionId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"FuzzyFileSearchSessionUpdateParams": {
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"query",
|
||||
"sessionId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"GetAccountParams": {
|
||||
"properties": {
|
||||
"refreshToken": {
|
||||
@@ -955,15 +985,6 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"HazelnutScope": {
|
||||
"enum": [
|
||||
"example",
|
||||
"workspace-shared",
|
||||
"all-shared",
|
||||
"personal"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ImageDetail": {
|
||||
"enum": [
|
||||
"auto",
|
||||
@@ -1227,6 +1248,18 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"MockExperimentalMethodParams": {
|
||||
"properties": {
|
||||
"value": {
|
||||
"description": "Test-only payload field.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"ModeKind": {
|
||||
"description": "Initial collaboration mode to use when the TUI starts.",
|
||||
"enum": [
|
||||
@@ -1280,6 +1313,10 @@
|
||||
},
|
||||
"PluginInstallParams": {
|
||||
"properties": {
|
||||
"forceRemoteSync": {
|
||||
"description": "When true, apply the remote plugin change before the local install flow.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"marketplacePath": {
|
||||
"$ref": "#/definitions/AbsolutePathBuf"
|
||||
},
|
||||
@@ -1329,6 +1366,10 @@
|
||||
},
|
||||
"PluginUninstallParams": {
|
||||
"properties": {
|
||||
"forceRemoteSync": {
|
||||
"description": "When true, apply the remote plugin change before the local uninstall flow.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"pluginId": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -1338,15 +1379,6 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ProductSurface": {
|
||||
"enum": [
|
||||
"chatgpt",
|
||||
"codex",
|
||||
"api",
|
||||
"atlas"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ReadOnlyAccess": {
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -1575,10 +1607,6 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"writeOnly": true
|
||||
},
|
||||
"summary": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ReasoningItemReasoningSummary"
|
||||
@@ -1594,7 +1622,6 @@
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"summary",
|
||||
"type"
|
||||
],
|
||||
@@ -1728,7 +1755,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"output": {
|
||||
"$ref": "#/definitions/FunctionCallOutputPayload"
|
||||
"$ref": "#/definitions/FunctionCallOutputBody"
|
||||
},
|
||||
"type": {
|
||||
"enum": [
|
||||
@@ -1792,8 +1819,14 @@
|
||||
"call_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"$ref": "#/definitions/FunctionCallOutputPayload"
|
||||
"$ref": "#/definitions/FunctionCallOutputBody"
|
||||
},
|
||||
"type": {
|
||||
"enum": [
|
||||
@@ -2425,42 +2458,6 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"SkillsRemoteReadParams": {
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"hazelnutScope": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/HazelnutScope"
|
||||
}
|
||||
],
|
||||
"default": "example"
|
||||
},
|
||||
"productSurface": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ProductSurface"
|
||||
}
|
||||
],
|
||||
"default": "codex"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"SkillsRemoteWriteParams": {
|
||||
"properties": {
|
||||
"hazelnutId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"hazelnutId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"TextElement": {
|
||||
"properties": {
|
||||
"byteRange": {
|
||||
@@ -2495,6 +2492,17 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadBackgroundTerminalsCleanParams": {
|
||||
"properties": {
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"threadId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadCompactStartParams": {
|
||||
"properties": {
|
||||
"threadId": {
|
||||
@@ -2506,6 +2514,19 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadDecrementElicitationParams": {
|
||||
"description": "Parameters for `thread/decrement_elicitation`.",
|
||||
"properties": {
|
||||
"threadId": {
|
||||
"description": "Thread whose out-of-band elicitation counter should be decremented.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"threadId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadForkParams": {
|
||||
"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 path, the thread_id param will be ignored.\n\nPrefer using thread_id whenever possible.",
|
||||
"properties": {
|
||||
@@ -2571,6 +2592,18 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"path": {
|
||||
"description": "[UNSTABLE] Specify the rollout path to fork from. If specified, the thread_id param will be ignored.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"persistExtendedHistory": {
|
||||
"default": false,
|
||||
"description": "If true, persist additional rollout EventMsg variants required to reconstruct a richer thread history on subsequent resume/fork/read.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"sandbox": {
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -2607,6 +2640,19 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadIncrementElicitationParams": {
|
||||
"description": "Parameters for `thread/increment_elicitation`.",
|
||||
"properties": {
|
||||
"threadId": {
|
||||
"description": "Thread whose out-of-band elicitation counter should be incremented.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"threadId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadListParams": {
|
||||
"properties": {
|
||||
"archived": {
|
||||
@@ -2765,12 +2811,50 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadRealtimeAppendAudioParams": {
|
||||
"description": "EXPERIMENTAL - append audio input to thread realtime.",
|
||||
"properties": {
|
||||
"audio": {
|
||||
"$ref": "#/definitions/ThreadRealtimeAudioChunk"
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"audio",
|
||||
"threadId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadRealtimeAppendTextParams": {
|
||||
"description": "EXPERIMENTAL - append text input to thread realtime.",
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"text",
|
||||
"threadId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadRealtimeAudioChunk": {
|
||||
"description": "EXPERIMENTAL - thread realtime audio chunk.",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "string"
|
||||
},
|
||||
"itemId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"numChannels": {
|
||||
"format": "uint16",
|
||||
"minimum": 0.0,
|
||||
@@ -2797,6 +2881,40 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadRealtimeStartParams": {
|
||||
"description": "EXPERIMENTAL - start a thread-scoped realtime session.",
|
||||
"properties": {
|
||||
"prompt": {
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"prompt",
|
||||
"threadId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadRealtimeStopParams": {
|
||||
"description": "EXPERIMENTAL - stop thread realtime.",
|
||||
"properties": {
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"threadId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadResumeParams": {
|
||||
"description": "There are three ways to resume a thread: 1. By thread_id: load the thread from disk by thread_id and resume it. 2. By history: instantiate the thread from memory and resume it. 3. By path: load the thread from disk by path and resume it.\n\nThe precedence is: history > path > thread_id. If using history or path, the thread_id param will be ignored.\n\nPrefer using thread_id whenever possible.",
|
||||
"properties": {
|
||||
@@ -2846,6 +2964,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"history": {
|
||||
"description": "[UNSTABLE] FOR CODEX CLOUD - DO NOT USE. If specified, the thread will be resumed with the provided history instead of loaded from disk.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ResponseItem"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"model": {
|
||||
"description": "Configuration overrides for the resumed thread, if any.",
|
||||
"type": [
|
||||
@@ -2859,6 +2987,18 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"path": {
|
||||
"description": "[UNSTABLE] Specify the rollout path to resume from. If specified, the thread_id param will be ignored.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"persistExtendedHistory": {
|
||||
"default": false,
|
||||
"description": "If true, persist additional rollout EventMsg variants required to reconstruct a richer thread history on subsequent resume/fork/read.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"personality": {
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -2951,6 +3091,7 @@
|
||||
"vscode",
|
||||
"exec",
|
||||
"appServer",
|
||||
"custom",
|
||||
"subAgent",
|
||||
"subAgentReview",
|
||||
"subAgentCompact",
|
||||
@@ -3008,12 +3149,33 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"dynamicTools": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/DynamicToolSpec"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"ephemeral": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"experimentalRawEvents": {
|
||||
"default": false,
|
||||
"description": "If true, opt into emitting raw Responses API items on the event stream. This is for internal use only (e.g. Codex Cloud).",
|
||||
"type": "boolean"
|
||||
},
|
||||
"mockExperimentalField": {
|
||||
"description": "Test-only experimental field used to validate experimental gating and schema filtering behavior in a stable way.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"model": {
|
||||
"type": [
|
||||
"string",
|
||||
@@ -3026,6 +3188,11 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"persistExtendedHistory": {
|
||||
"default": false,
|
||||
"description": "If true, persist additional rollout EventMsg variants required to reconstruct a richer thread history on resume/fork/read.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"personality": {
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -3133,6 +3300,17 @@
|
||||
],
|
||||
"description": "Override where approval requests are routed for review on this turn and subsequent turns."
|
||||
},
|
||||
"collaborationMode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/CollaborationMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "EXPERIMENTAL - Set a pre-set collaboration mode. Takes precedence over model, reasoning_effort, and developer instructions if set.\n\nFor `collaboration_mode.settings.developer_instructions`, `null` means \"use the built-in instructions for the selected mode\"."
|
||||
},
|
||||
"cwd": {
|
||||
"description": "Override the working directory for this turn and subsequent turns.",
|
||||
"type": [
|
||||
@@ -3547,6 +3725,56 @@
|
||||
"title": "Thread/unsubscribeRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"description": "Increment the thread-local out-of-band elicitation counter.\n\nThis is used by external helpers to pause timeout accounting while a user approval or other elicitation is pending outside the app-server request flow.",
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"thread/increment_elicitation"
|
||||
],
|
||||
"title": "Thread/incrementElicitationRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/ThreadIncrementElicitationParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Thread/incrementElicitationRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"description": "Decrement the thread-local out-of-band elicitation counter.\n\nWhen the count reaches zero, timeout accounting resumes for the thread.",
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"thread/decrement_elicitation"
|
||||
],
|
||||
"title": "Thread/decrementElicitationRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/ThreadDecrementElicitationParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Thread/decrementElicitationRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -3643,6 +3871,30 @@
|
||||
"title": "Thread/compact/startRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"thread/backgroundTerminals/clean"
|
||||
],
|
||||
"title": "Thread/backgroundTerminals/cleanRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/ThreadBackgroundTerminalsCleanParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Thread/backgroundTerminals/cleanRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -3811,54 +4063,6 @@
|
||||
"title": "Plugin/readRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"skills/remote/list"
|
||||
],
|
||||
"title": "Skills/remote/listRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/SkillsRemoteReadParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Skills/remote/listRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"skills/remote/export"
|
||||
],
|
||||
"title": "Skills/remote/exportRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/SkillsRemoteWriteParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Skills/remote/exportRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -4195,6 +4399,102 @@
|
||||
"title": "Turn/interruptRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"thread/realtime/start"
|
||||
],
|
||||
"title": "Thread/realtime/startRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/ThreadRealtimeStartParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Thread/realtime/startRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"thread/realtime/appendAudio"
|
||||
],
|
||||
"title": "Thread/realtime/appendAudioRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/ThreadRealtimeAppendAudioParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Thread/realtime/appendAudioRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"thread/realtime/appendText"
|
||||
],
|
||||
"title": "Thread/realtime/appendTextRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/ThreadRealtimeAppendTextParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Thread/realtime/appendTextRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"thread/realtime/stop"
|
||||
],
|
||||
"title": "Thread/realtime/stopRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/ThreadRealtimeStopParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Thread/realtime/stopRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -4267,6 +4567,56 @@
|
||||
"title": "ExperimentalFeature/listRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"description": "Lists collaboration mode presets.",
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"collaborationMode/list"
|
||||
],
|
||||
"title": "CollaborationMode/listRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/CollaborationModeListParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "CollaborationMode/listRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"description": "Test-only method used to validate experimental gating.",
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"mock/experimentalMethod"
|
||||
],
|
||||
"title": "Mock/experimentalMethodRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/MockExperimentalMethodParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Mock/experimentalMethodRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -4770,6 +5120,78 @@
|
||||
],
|
||||
"title": "FuzzyFileSearchRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"fuzzyFileSearch/sessionStart"
|
||||
],
|
||||
"title": "FuzzyFileSearch/sessionStartRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/FuzzyFileSearchSessionStartParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "FuzzyFileSearch/sessionStartRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"fuzzyFileSearch/sessionUpdate"
|
||||
],
|
||||
"title": "FuzzyFileSearch/sessionUpdateRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/FuzzyFileSearchSessionUpdateParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "FuzzyFileSearch/sessionUpdateRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"fuzzyFileSearch/sessionStop"
|
||||
],
|
||||
"title": "FuzzyFileSearch/sessionStopRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/FuzzyFileSearchSessionStopParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "FuzzyFileSearch/sessionStopRequest",
|
||||
"type": "object"
|
||||
}
|
||||
],
|
||||
"title": "ClientRequest"
|
||||
|
||||
@@ -400,6 +400,17 @@
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"additionalPermissions": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AdditionalPermissionProfile"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional additional permissions requested for this command."
|
||||
},
|
||||
"approvalId": {
|
||||
"description": "Unique identifier for this specific approval callback.\n\nFor regular shell/unified_exec approvals, this is null.\n\nFor zsh-exec-bridge subcommand approvals, multiple callbacks can belong to one parent `itemId`, so `approvalId` is a distinct opaque callback id (a UUID) used to disambiguate routing.",
|
||||
"type": [
|
||||
@@ -407,6 +418,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"availableDecisions": {
|
||||
"description": "Ordered list of decisions the client may present for this prompt.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/CommandExecutionApprovalDecision"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"command": {
|
||||
"description": "The command to be executed.",
|
||||
"type": [
|
||||
@@ -472,6 +493,17 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"skillMetadata": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/CommandExecutionRequestApprovalSkillMetadata"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional skill metadata when the approval was triggered by a skill script."
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -28,41 +28,6 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"AdditionalMacOsPermissions": {
|
||||
"properties": {
|
||||
"accessibility": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"automations": {
|
||||
"$ref": "#/definitions/MacOsAutomationPermission"
|
||||
},
|
||||
"calendar": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"contacts": {
|
||||
"$ref": "#/definitions/MacOsContactsPermission"
|
||||
},
|
||||
"launchServices": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"preferences": {
|
||||
"$ref": "#/definitions/MacOsPreferencesPermission"
|
||||
},
|
||||
"reminders": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"accessibility",
|
||||
"automations",
|
||||
"calendar",
|
||||
"contacts",
|
||||
"launchServices",
|
||||
"preferences",
|
||||
"reminders"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"AdditionalNetworkPermissions": {
|
||||
"properties": {
|
||||
"enabled": {
|
||||
@@ -74,7 +39,8 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"AdditionalPermissionProfile": {
|
||||
"RequestPermissionProfile": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"fileSystem": {
|
||||
"anyOf": [
|
||||
@@ -86,16 +52,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"macos": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AdditionalMacOsPermissions"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"network": {
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -108,49 +64,6 @@
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"MacOsAutomationPermission": {
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": [
|
||||
"none",
|
||||
"all"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"bundle_ids": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"bundle_ids"
|
||||
],
|
||||
"title": "BundleIdsMacOsAutomationPermission",
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
"MacOsContactsPermission": {
|
||||
"enum": [
|
||||
"none",
|
||||
"read_only",
|
||||
"read_write"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MacOsPreferencesPermission": {
|
||||
"enum": [
|
||||
"none",
|
||||
"read_only",
|
||||
"read_write"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
@@ -158,7 +71,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"permissions": {
|
||||
"$ref": "#/definitions/AdditionalPermissionProfile"
|
||||
"$ref": "#/definitions/RequestPermissionProfile"
|
||||
},
|
||||
"reason": {
|
||||
"type": [
|
||||
|
||||
@@ -39,65 +39,6 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"GrantedMacOsPermissions": {
|
||||
"properties": {
|
||||
"accessibility": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"automations": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MacOsAutomationPermission"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"calendar": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"contacts": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MacOsContactsPermission"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"launchServices": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"preferences": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MacOsPreferencesPermission"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reminders": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"GrantedPermissionProfile": {
|
||||
"properties": {
|
||||
"fileSystem": {
|
||||
@@ -110,16 +51,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"macos": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/GrantedMacOsPermissions"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"network": {
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -133,49 +64,6 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"MacOsAutomationPermission": {
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": [
|
||||
"none",
|
||||
"all"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"bundle_ids": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"bundle_ids"
|
||||
],
|
||||
"title": "BundleIdsMacOsAutomationPermission",
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
"MacOsContactsPermission": {
|
||||
"enum": [
|
||||
"none",
|
||||
"read_only",
|
||||
"read_write"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MacOsPreferencesPermission": {
|
||||
"enum": [
|
||||
"none",
|
||||
"read_only",
|
||||
"read_write"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PermissionGrantScope": {
|
||||
"enum": [
|
||||
"turn",
|
||||
|
||||
@@ -535,6 +535,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -1135,6 +1136,7 @@
|
||||
"HookEventName": {
|
||||
"enum": [
|
||||
"sessionStart",
|
||||
"userPromptSubmit",
|
||||
"stop"
|
||||
],
|
||||
"type": "string"
|
||||
@@ -1453,6 +1455,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -1693,6 +1743,13 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"RealtimeConversationVersion": {
|
||||
"enum": [
|
||||
"v1",
|
||||
"v2"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ReasoningEffort": {
|
||||
"description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning",
|
||||
"enum": [
|
||||
@@ -1823,6 +1880,19 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"custom": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"custom"
|
||||
],
|
||||
"title": "CustomSessionSource",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -2172,6 +2242,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -2749,6 +2830,12 @@
|
||||
"data": {
|
||||
"type": "string"
|
||||
},
|
||||
"itemId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"numChannels": {
|
||||
"format": "uint16",
|
||||
"minimum": 0.0,
|
||||
@@ -2850,10 +2937,14 @@
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"$ref": "#/definitions/RealtimeConversationVersion"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"threadId"
|
||||
"threadId",
|
||||
"version"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
|
||||
@@ -366,6 +366,17 @@
|
||||
},
|
||||
"CommandExecutionRequestApprovalParams": {
|
||||
"properties": {
|
||||
"additionalPermissions": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AdditionalPermissionProfile"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional additional permissions requested for this command."
|
||||
},
|
||||
"approvalId": {
|
||||
"description": "Unique identifier for this specific approval callback.\n\nFor regular shell/unified_exec approvals, this is null.\n\nFor zsh-exec-bridge subcommand approvals, multiple callbacks can belong to one parent `itemId`, so `approvalId` is a distinct opaque callback id (a UUID) used to disambiguate routing.",
|
||||
"type": [
|
||||
@@ -373,6 +384,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"availableDecisions": {
|
||||
"description": "Ordered list of decisions the client may present for this prompt.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/CommandExecutionApprovalDecision"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"command": {
|
||||
"description": "The command to be executed.",
|
||||
"type": [
|
||||
@@ -438,6 +459,17 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"skillMetadata": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/CommandExecutionRequestApprovalSkillMetadata"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional skill metadata when the approval was triggered by a skill script."
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -1449,7 +1481,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"permissions": {
|
||||
"$ref": "#/definitions/AdditionalPermissionProfile"
|
||||
"$ref": "#/definitions/RequestPermissionProfile"
|
||||
},
|
||||
"reason": {
|
||||
"type": [
|
||||
@@ -1483,6 +1515,32 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"RequestPermissionProfile": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"fileSystem": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AdditionalFileSystemPermissions"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"network": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AdditionalNetworkPermissions"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadId": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -221,6 +221,17 @@
|
||||
],
|
||||
"description": "[UNSTABLE] Optional default for where approval requests are routed for review."
|
||||
},
|
||||
"apps": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AppsConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"compact_prompt": {
|
||||
"type": [
|
||||
"string",
|
||||
|
||||
@@ -98,10 +98,28 @@
|
||||
"object",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"network": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/NetworkRequirements"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"NetworkDomainPermission": {
|
||||
"enum": [
|
||||
"allow",
|
||||
"deny",
|
||||
"none"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"NetworkRequirements": {
|
||||
"properties": {
|
||||
"allowLocalBinding": {
|
||||
@@ -110,30 +128,12 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"allowUnixSockets": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"allowUpstreamProxy": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"allowedDomains": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"dangerouslyAllowAllUnixSockets": {
|
||||
"type": [
|
||||
"boolean",
|
||||
@@ -146,12 +146,12 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"deniedDomains": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
"domains": {
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/NetworkDomainPermission"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"object",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
@@ -176,10 +176,26 @@
|
||||
"integer",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"unixSockets": {
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/NetworkUnixSocketPermission"
|
||||
},
|
||||
"type": [
|
||||
"object",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"NetworkUnixSocketPermission": {
|
||||
"enum": [
|
||||
"allow",
|
||||
"none"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ResidencyRequirement": {
|
||||
"enum": [
|
||||
"us"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"HookEventName": {
|
||||
"enum": [
|
||||
"sessionStart",
|
||||
"userPromptSubmit",
|
||||
"stop"
|
||||
],
|
||||
"type": "string"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"HookEventName": {
|
||||
"enum": [
|
||||
"sessionStart",
|
||||
"userPromptSubmit",
|
||||
"stop"
|
||||
],
|
||||
"type": "string"
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -288,6 +289,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -443,6 +492,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -288,6 +289,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -443,6 +492,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"forceRemoteSync": {
|
||||
"description": "When true, apply the remote plugin change before the local install flow.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"marketplacePath": {
|
||||
"$ref": "#/definitions/AbsolutePathBuf"
|
||||
},
|
||||
|
||||
@@ -5,6 +5,17 @@
|
||||
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
|
||||
"type": "string"
|
||||
},
|
||||
"MarketplaceInterface": {
|
||||
"properties": {
|
||||
"displayName": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"PluginAuthPolicy": {
|
||||
"enum": [
|
||||
"ON_INSTALL",
|
||||
@@ -127,6 +138,16 @@
|
||||
},
|
||||
"PluginMarketplaceEntry": {
|
||||
"properties": {
|
||||
"interface": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MarketplaceInterface"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"forceRemoteSync": {
|
||||
"description": "When true, apply the remote plugin change before the local uninstall flow.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"pluginId": {
|
||||
"type": "string"
|
||||
}
|
||||
|
||||
@@ -133,24 +133,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"FunctionCallOutputPayload": {
|
||||
"description": "The payload we send back to OpenAI when reporting a tool call result.\n\n`body` serializes directly as the wire value for `function_call_output.output`. `success` remains internal metadata for downstream handling.",
|
||||
"properties": {
|
||||
"body": {
|
||||
"$ref": "#/definitions/FunctionCallOutputBody"
|
||||
},
|
||||
"success": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"body"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"GhostCommit": {
|
||||
"description": "Details of a ghost commit created from a repository state.",
|
||||
"properties": {
|
||||
@@ -413,10 +395,6 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"writeOnly": true
|
||||
},
|
||||
"summary": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ReasoningItemReasoningSummary"
|
||||
@@ -432,7 +410,6 @@
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"summary",
|
||||
"type"
|
||||
],
|
||||
@@ -566,7 +543,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"output": {
|
||||
"$ref": "#/definitions/FunctionCallOutputPayload"
|
||||
"$ref": "#/definitions/FunctionCallOutputBody"
|
||||
},
|
||||
"type": {
|
||||
"enum": [
|
||||
@@ -630,8 +607,14 @@
|
||||
"call_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"$ref": "#/definitions/FunctionCallOutputPayload"
|
||||
"$ref": "#/definitions/FunctionCallOutputBody"
|
||||
},
|
||||
"type": {
|
||||
"enum": [
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -402,6 +403,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -557,6 +606,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"definitions": {
|
||||
"HazelnutScope": {
|
||||
"enum": [
|
||||
"example",
|
||||
"workspace-shared",
|
||||
"all-shared",
|
||||
"personal"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ProductSurface": {
|
||||
"enum": [
|
||||
"chatgpt",
|
||||
"codex",
|
||||
"api",
|
||||
"atlas"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"hazelnutScope": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/HazelnutScope"
|
||||
}
|
||||
],
|
||||
"default": "example"
|
||||
},
|
||||
"productSurface": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ProductSurface"
|
||||
}
|
||||
],
|
||||
"default": "codex"
|
||||
}
|
||||
},
|
||||
"title": "SkillsRemoteReadParams",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"definitions": {
|
||||
"RemoteSkillSummary": {
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"description",
|
||||
"id",
|
||||
"name"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"data": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/RemoteSkillSummary"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"data"
|
||||
],
|
||||
"title": "SkillsRemoteReadResponse",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"hazelnutId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"hazelnutId"
|
||||
],
|
||||
"title": "SkillsRemoteWriteParams",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"path"
|
||||
],
|
||||
"title": "SkillsRemoteWriteResponse",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -139,6 +139,18 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"path": {
|
||||
"description": "[UNSTABLE] Specify the rollout path to fork from. If specified, the thread_id param will be ignored.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"persistExtendedHistory": {
|
||||
"default": false,
|
||||
"description": "If true, persist additional rollout EventMsg variants required to reconstruct a richer thread history on subsequent resume/fork/read.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"sandbox": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -217,6 +217,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -487,6 +488,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -777,6 +826,19 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"custom": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"custom"
|
||||
],
|
||||
"title": "CustomSessionSource",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -1037,6 +1099,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"vscode",
|
||||
"exec",
|
||||
"appServer",
|
||||
"custom",
|
||||
"subAgent",
|
||||
"subAgentReview",
|
||||
"subAgentCompact",
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -425,6 +426,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -535,6 +584,19 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"custom": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"custom"
|
||||
],
|
||||
"title": "CustomSessionSource",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -795,6 +857,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -425,6 +426,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -535,6 +584,19 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"custom": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"custom"
|
||||
],
|
||||
"title": "CustomSessionSource",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -795,6 +857,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -425,6 +426,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -535,6 +584,19 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"custom": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"custom"
|
||||
],
|
||||
"title": "CustomSessionSource",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -795,6 +857,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -7,6 +7,12 @@
|
||||
"data": {
|
||||
"type": "string"
|
||||
},
|
||||
"itemId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"numChannels": {
|
||||
"format": "uint16",
|
||||
"minimum": 0.0,
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"definitions": {
|
||||
"RealtimeConversationVersion": {
|
||||
"enum": [
|
||||
"v1",
|
||||
"v2"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"description": "EXPERIMENTAL - emitted when thread realtime startup is accepted.",
|
||||
"properties": {
|
||||
"sessionId": {
|
||||
@@ -10,10 +19,14 @@
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"$ref": "#/definitions/RealtimeConversationVersion"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"threadId"
|
||||
"threadId",
|
||||
"version"
|
||||
],
|
||||
"title": "ThreadRealtimeStartedNotification",
|
||||
"type": "object"
|
||||
|
||||
@@ -191,24 +191,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"FunctionCallOutputPayload": {
|
||||
"description": "The payload we send back to OpenAI when reporting a tool call result.\n\n`body` serializes directly as the wire value for `function_call_output.output`. `success` remains internal metadata for downstream handling.",
|
||||
"properties": {
|
||||
"body": {
|
||||
"$ref": "#/definitions/FunctionCallOutputBody"
|
||||
},
|
||||
"success": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"body"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"GhostCommit": {
|
||||
"description": "Details of a ghost commit created from a repository state.",
|
||||
"properties": {
|
||||
@@ -479,10 +461,6 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"writeOnly": true
|
||||
},
|
||||
"summary": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ReasoningItemReasoningSummary"
|
||||
@@ -498,7 +476,6 @@
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"summary",
|
||||
"type"
|
||||
],
|
||||
@@ -632,7 +609,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"output": {
|
||||
"$ref": "#/definitions/FunctionCallOutputPayload"
|
||||
"$ref": "#/definitions/FunctionCallOutputBody"
|
||||
},
|
||||
"type": {
|
||||
"enum": [
|
||||
@@ -696,8 +673,14 @@
|
||||
"call_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"$ref": "#/definitions/FunctionCallOutputPayload"
|
||||
"$ref": "#/definitions/FunctionCallOutputBody"
|
||||
},
|
||||
"type": {
|
||||
"enum": [
|
||||
@@ -1046,6 +1029,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"history": {
|
||||
"description": "[UNSTABLE] FOR CODEX CLOUD - DO NOT USE. If specified, the thread will be resumed with the provided history instead of loaded from disk.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ResponseItem"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"model": {
|
||||
"description": "Configuration overrides for the resumed thread, if any.",
|
||||
"type": [
|
||||
@@ -1059,6 +1052,18 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"path": {
|
||||
"description": "[UNSTABLE] Specify the rollout path to resume from. If specified, the thread_id param will be ignored.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"persistExtendedHistory": {
|
||||
"default": false,
|
||||
"description": "If true, persist additional rollout EventMsg variants required to reconstruct a richer thread history on subsequent resume/fork/read.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"personality": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -217,6 +217,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -487,6 +488,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -777,6 +826,19 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"custom": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"custom"
|
||||
],
|
||||
"title": "CustomSessionSource",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -1037,6 +1099,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -425,6 +426,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -535,6 +584,19 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"custom": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"custom"
|
||||
],
|
||||
"title": "CustomSessionSource",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -795,6 +857,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -150,12 +150,33 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"dynamicTools": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/DynamicToolSpec"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"ephemeral": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"experimentalRawEvents": {
|
||||
"default": false,
|
||||
"description": "If true, opt into emitting raw Responses API items on the event stream. This is for internal use only (e.g. Codex Cloud).",
|
||||
"type": "boolean"
|
||||
},
|
||||
"mockExperimentalField": {
|
||||
"description": "Test-only experimental field used to validate experimental gating and schema filtering behavior in a stable way.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"model": {
|
||||
"type": [
|
||||
"string",
|
||||
@@ -168,6 +189,11 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"persistExtendedHistory": {
|
||||
"default": false,
|
||||
"description": "If true, persist additional rollout EventMsg variants required to reconstruct a richer thread history on resume/fork/read.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"personality": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -217,6 +217,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -487,6 +488,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -777,6 +826,19 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"custom": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"custom"
|
||||
],
|
||||
"title": "CustomSessionSource",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -1037,6 +1099,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -425,6 +426,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -535,6 +584,19 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"custom": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"custom"
|
||||
],
|
||||
"title": "CustomSessionSource",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -795,6 +857,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -425,6 +426,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -535,6 +584,19 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"custom": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"custom"
|
||||
],
|
||||
"title": "CustomSessionSource",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -795,6 +857,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -402,6 +403,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -557,6 +606,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -521,6 +521,17 @@
|
||||
],
|
||||
"description": "Override where approval requests are routed for review on this turn and subsequent turns."
|
||||
},
|
||||
"collaborationMode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/CollaborationMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "EXPERIMENTAL - Set a pre-set collaboration mode. Takes precedence over model, reasoning_effort, and developer instructions if set.\n\nFor `collaboration_mode.settings.developer_instructions`, `null` means \"use the built-in instructions for the selected mode\"."
|
||||
},
|
||||
"cwd": {
|
||||
"description": "Override the working directory for this turn and subsequent turns.",
|
||||
"type": [
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -402,6 +403,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -557,6 +606,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
"enum": [
|
||||
"pendingInit",
|
||||
"running",
|
||||
"interrupted",
|
||||
"completed",
|
||||
"errored",
|
||||
"shutdown",
|
||||
@@ -402,6 +403,54 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
@@ -557,6 +606,17 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,12 +0,0 @@
|
||||
// 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 { FunctionCallOutputBody } from "./FunctionCallOutputBody";
|
||||
|
||||
/**
|
||||
* The payload we send back to OpenAI when reporting a tool call result.
|
||||
*
|
||||
* `body` serializes directly as the wire value for `function_call_output.output`.
|
||||
* `success` remains internal metadata for downstream handling.
|
||||
*/
|
||||
export type FunctionCallOutputPayload = { body: FunctionCallOutputBody, success: boolean | 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 SkillsRemoteWriteParams = { hazelnutId: string, };
|
||||
export type RealtimeConversationVersion = "v1" | "v2";
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ContentItem } from "./ContentItem";
|
||||
import type { FunctionCallOutputPayload } from "./FunctionCallOutputPayload";
|
||||
import type { FunctionCallOutputBody } from "./FunctionCallOutputBody";
|
||||
import type { GhostCommit } from "./GhostCommit";
|
||||
import type { LocalShellAction } from "./LocalShellAction";
|
||||
import type { LocalShellStatus } from "./LocalShellStatus";
|
||||
@@ -15,4 +15,4 @@ export type ResponseItem = { "type": "message", role: string, content: Array<Con
|
||||
/**
|
||||
* Set when using the Responses API.
|
||||
*/
|
||||
call_id: string | null, status: LocalShellStatus, action: LocalShellAction, } | { "type": "function_call", name: string, namespace?: string, arguments: string, call_id: string, } | { "type": "tool_search_call", call_id: string | null, status?: string, execution: string, arguments: unknown, } | { "type": "function_call_output", call_id: string, output: FunctionCallOutputPayload, } | { "type": "custom_tool_call", status?: string, call_id: string, name: string, input: string, } | { "type": "custom_tool_call_output", call_id: string, output: FunctionCallOutputPayload, } | { "type": "tool_search_output", call_id: string | null, status: string, execution: string, tools: unknown[], } | { "type": "web_search_call", status?: string, action?: WebSearchAction, } | { "type": "image_generation_call", id: string, status: string, revised_prompt?: string, result: string, } | { "type": "ghost_snapshot", ghost_commit: GhostCommit, } | { "type": "compaction", encrypted_content: string, } | { "type": "other" };
|
||||
call_id: string | null, status: LocalShellStatus, action: LocalShellAction, } | { "type": "function_call", name: string, namespace?: string, arguments: string, call_id: string, } | { "type": "tool_search_call", call_id: string | null, status?: string, execution: string, arguments: unknown, } | { "type": "function_call_output", call_id: string, output: FunctionCallOutputBody, } | { "type": "custom_tool_call", status?: string, call_id: string, name: string, input: string, } | { "type": "custom_tool_call_output", call_id: string, name?: string, output: FunctionCallOutputBody, } | { "type": "tool_search_output", call_id: string | null, status: string, execution: string, tools: unknown[], } | { "type": "web_search_call", status?: string, action?: WebSearchAction, } | { "type": "image_generation_call", id: string, status: string, revised_prompt?: string, result: string, } | { "type": "ghost_snapshot", ghost_commit: GhostCommit, } | { "type": "compaction", encrypted_content: string, } | { "type": "other" };
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { SubAgentSource } from "./SubAgentSource";
|
||||
|
||||
export type SessionSource = "cli" | "vscode" | "exec" | "mcp" | { "subagent": SubAgentSource } | "unknown";
|
||||
export type SessionSource = "cli" | "vscode" | "exec" | "mcp" | { "custom": string } | { "subagent": SubAgentSource } | "unknown";
|
||||
|
||||
@@ -18,11 +18,16 @@ export type { FileChange } from "./FileChange";
|
||||
export type { ForcedLoginMethod } from "./ForcedLoginMethod";
|
||||
export type { FunctionCallOutputBody } from "./FunctionCallOutputBody";
|
||||
export type { FunctionCallOutputContentItem } from "./FunctionCallOutputContentItem";
|
||||
export type { FunctionCallOutputPayload } from "./FunctionCallOutputPayload";
|
||||
export type { FuzzyFileSearchParams } from "./FuzzyFileSearchParams";
|
||||
export type { FuzzyFileSearchResponse } from "./FuzzyFileSearchResponse";
|
||||
export type { FuzzyFileSearchResult } from "./FuzzyFileSearchResult";
|
||||
export type { FuzzyFileSearchSessionCompletedNotification } from "./FuzzyFileSearchSessionCompletedNotification";
|
||||
export type { FuzzyFileSearchSessionStartParams } from "./FuzzyFileSearchSessionStartParams";
|
||||
export type { FuzzyFileSearchSessionStartResponse } from "./FuzzyFileSearchSessionStartResponse";
|
||||
export type { FuzzyFileSearchSessionStopParams } from "./FuzzyFileSearchSessionStopParams";
|
||||
export type { FuzzyFileSearchSessionStopResponse } from "./FuzzyFileSearchSessionStopResponse";
|
||||
export type { FuzzyFileSearchSessionUpdateParams } from "./FuzzyFileSearchSessionUpdateParams";
|
||||
export type { FuzzyFileSearchSessionUpdateResponse } from "./FuzzyFileSearchSessionUpdateResponse";
|
||||
export type { FuzzyFileSearchSessionUpdatedNotification } from "./FuzzyFileSearchSessionUpdatedNotification";
|
||||
export type { GetAuthStatusParams } from "./GetAuthStatusParams";
|
||||
export type { GetAuthStatusResponse } from "./GetAuthStatusResponse";
|
||||
@@ -50,6 +55,7 @@ export type { NetworkPolicyRuleAction } from "./NetworkPolicyRuleAction";
|
||||
export type { ParsedCommand } from "./ParsedCommand";
|
||||
export type { Personality } from "./Personality";
|
||||
export type { PlanType } from "./PlanType";
|
||||
export type { RealtimeConversationVersion } from "./RealtimeConversationVersion";
|
||||
export type { ReasoningEffort } from "./ReasoningEffort";
|
||||
export type { ReasoningItemContent } from "./ReasoningItemContent";
|
||||
export type { ReasoningItemReasoningSummary } from "./ReasoningItemReasoningSummary";
|
||||
|
||||
@@ -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 CollabAgentStatus = "pendingInit" | "running" | "completed" | "errored" | "shutdown" | "notFound";
|
||||
export type CollabAgentStatus = "pendingInit" | "running" | "interrupted" | "completed" | "errored" | "shutdown" | "notFound";
|
||||
|
||||
@@ -10,14 +10,16 @@ import type { WebSearchMode } from "../WebSearchMode";
|
||||
import type { JsonValue } from "../serde_json/JsonValue";
|
||||
import type { AnalyticsConfig } from "./AnalyticsConfig";
|
||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AppsConfig } from "./AppsConfig";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
import type { ProfileV2 } from "./ProfileV2";
|
||||
import type { SandboxMode } from "./SandboxMode";
|
||||
import type { SandboxWorkspaceWrite } from "./SandboxWorkspaceWrite";
|
||||
import type { ToolsV2 } from "./ToolsV2";
|
||||
|
||||
export type Config = {model: string | null, review_model: string | null, model_context_window: bigint | null, model_auto_compact_token_limit: bigint | null, model_provider: string | null, approval_policy: AskForApproval | null, /**
|
||||
export type Config = { model: string | null, review_model: string | null, model_context_window: bigint | null, model_auto_compact_token_limit: bigint | null, model_provider: string | null, approval_policy: AskForApproval | null,
|
||||
/**
|
||||
* [UNSTABLE] Optional default for where approval requests are routed for
|
||||
* review.
|
||||
*/
|
||||
approvals_reviewer: ApprovalsReviewer | null, sandbox_mode: SandboxMode | null, sandbox_workspace_write: SandboxWorkspaceWrite | null, forced_chatgpt_workspace_id: string | null, forced_login_method: ForcedLoginMethod | null, web_search: WebSearchMode | null, tools: ToolsV2 | null, profile: string | null, profiles: { [key in string]?: ProfileV2 }, instructions: string | null, developer_instructions: string | null, compact_prompt: string | null, model_reasoning_effort: ReasoningEffort | null, model_reasoning_summary: ReasoningSummary | null, model_verbosity: Verbosity | null, service_tier: ServiceTier | null, analytics: AnalyticsConfig | null} & ({ [key in string]?: number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null });
|
||||
approvals_reviewer: ApprovalsReviewer | null, sandbox_mode: SandboxMode | null, sandbox_workspace_write: SandboxWorkspaceWrite | null, forced_chatgpt_workspace_id: string | null, forced_login_method: ForcedLoginMethod | null, web_search: WebSearchMode | null, tools: ToolsV2 | null, profile: string | null, profiles: { [key in string]?: ProfileV2 }, instructions: string | null, developer_instructions: string | null, compact_prompt: string | null, model_reasoning_effort: ReasoningEffort | null, model_reasoning_summary: ReasoningSummary | null, model_verbosity: Verbosity | null, service_tier: ServiceTier | null, analytics: AnalyticsConfig | null, apps: AppsConfig | null, } & ({ [key in string]?: number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null });
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { WebSearchMode } from "../WebSearchMode";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
import type { NetworkRequirements } from "./NetworkRequirements";
|
||||
import type { ResidencyRequirement } from "./ResidencyRequirement";
|
||||
import type { SandboxMode } from "./SandboxMode";
|
||||
|
||||
export type ConfigRequirements = {allowedApprovalPolicies: Array<AskForApproval> | null, allowedSandboxModes: Array<SandboxMode> | null, allowedWebSearchModes: Array<WebSearchMode> | null, featureRequirements: { [key in string]?: boolean } | null, enforceResidency: ResidencyRequirement | null};
|
||||
export type ConfigRequirements = { allowedApprovalPolicies: Array<AskForApproval> | null, allowedSandboxModes: Array<SandboxMode> | null, allowedWebSearchModes: Array<WebSearchMode> | null, featureRequirements: { [key in string]?: boolean } | null, enforceResidency: ResidencyRequirement | null, network: NetworkRequirements | null, };
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
// 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 { MacOsAutomationPermission } from "../MacOsAutomationPermission";
|
||||
import type { MacOsContactsPermission } from "../MacOsContactsPermission";
|
||||
import type { MacOsPreferencesPermission } from "../MacOsPreferencesPermission";
|
||||
|
||||
export type GrantedMacOsPermissions = { preferences?: MacOsPreferencesPermission, automations?: MacOsAutomationPermission, launchServices?: boolean, accessibility?: boolean, calendar?: boolean, reminders?: boolean, contacts?: MacOsContactsPermission, };
|
||||
@@ -3,6 +3,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { AdditionalFileSystemPermissions } from "./AdditionalFileSystemPermissions";
|
||||
import type { AdditionalNetworkPermissions } from "./AdditionalNetworkPermissions";
|
||||
import type { GrantedMacOsPermissions } from "./GrantedMacOsPermissions";
|
||||
|
||||
export type GrantedPermissionProfile = { network?: AdditionalNetworkPermissions, fileSystem?: AdditionalFileSystemPermissions, macos?: GrantedMacOsPermissions, };
|
||||
export type GrantedPermissionProfile = { network?: AdditionalNetworkPermissions, fileSystem?: AdditionalFileSystemPermissions, };
|
||||
|
||||
@@ -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 HookEventName = "sessionStart" | "stop";
|
||||
export type HookEventName = "sessionStart" | "userPromptSubmit" | "stop";
|
||||
|
||||
@@ -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 ProductSurface = "chatgpt" | "codex" | "api" | "atlas";
|
||||
export type MarketplaceInterface = { displayName: string | null, };
|
||||
@@ -0,0 +1,6 @@
|
||||
// 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 { MemoryCitationEntry } from "./MemoryCitationEntry";
|
||||
|
||||
export type MemoryCitation = { entries: Array<MemoryCitationEntry>, threadIds: Array<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 HazelnutScope = "example" | "workspace-shared" | "all-shared" | "personal";
|
||||
export type MemoryCitationEntry = { path: string, lineStart: number, lineEnd: number, note: 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 SkillsRemoteWriteResponse = { id: string, path: string, };
|
||||
export type NetworkDomainPermission = "allow" | "deny" | "none";
|
||||
@@ -1,5 +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 { NetworkDomainPermission } from "./NetworkDomainPermission";
|
||||
import type { NetworkUnixSocketPermission } from "./NetworkUnixSocketPermission";
|
||||
|
||||
export type NetworkRequirements = { enabled: boolean | null, httpPort: number | null, socksPort: number | null, allowUpstreamProxy: boolean | null, dangerouslyAllowNonLoopbackProxy: boolean | null, dangerouslyAllowAllUnixSockets: boolean | null, allowedDomains: Array<string> | null, deniedDomains: Array<string> | null, allowUnixSockets: Array<string> | null, allowLocalBinding: boolean | null, };
|
||||
export type NetworkRequirements = { enabled: boolean | null, httpPort: number | null, socksPort: number | null, allowUpstreamProxy: boolean | null, dangerouslyAllowNonLoopbackProxy: boolean | null, dangerouslyAllowAllUnixSockets: boolean | null, domains: { [key in string]?: NetworkDomainPermission } | null, unixSockets: { [key in string]?: NetworkUnixSocketPermission } | null, allowLocalBinding: boolean | 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 RemoteSkillSummary = { id: string, name: string, description: string, };
|
||||
export type NetworkUnixSocketPermission = "allow" | "none";
|
||||
@@ -1,6 +1,6 @@
|
||||
// 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 { AdditionalPermissionProfile } from "./AdditionalPermissionProfile";
|
||||
import type { RequestPermissionProfile } from "./RequestPermissionProfile";
|
||||
|
||||
export type PermissionsRequestApprovalParams = { threadId: string, turnId: string, itemId: string, reason: string | null, permissions: AdditionalPermissionProfile, };
|
||||
export type PermissionsRequestApprovalParams = { threadId: string, turnId: string, itemId: string, reason: string | null, permissions: RequestPermissionProfile, };
|
||||
|
||||
@@ -3,4 +3,8 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { AbsolutePathBuf } from "../AbsolutePathBuf";
|
||||
|
||||
export type PluginInstallParams = { marketplacePath: AbsolutePathBuf, pluginName: string, };
|
||||
export type PluginInstallParams = { marketplacePath: AbsolutePathBuf, pluginName: string,
|
||||
/**
|
||||
* When true, apply the remote plugin change before the local install flow.
|
||||
*/
|
||||
forceRemoteSync?: boolean, };
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { AbsolutePathBuf } from "../AbsolutePathBuf";
|
||||
import type { MarketplaceInterface } from "./MarketplaceInterface";
|
||||
import type { PluginSummary } from "./PluginSummary";
|
||||
|
||||
export type PluginMarketplaceEntry = { name: string, path: AbsolutePathBuf, plugins: Array<PluginSummary>, };
|
||||
export type PluginMarketplaceEntry = { name: string, path: AbsolutePathBuf, interface: MarketplaceInterface | null, plugins: Array<PluginSummary>, };
|
||||
|
||||
@@ -2,4 +2,8 @@
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type PluginUninstallParams = { pluginId: string, };
|
||||
export type PluginUninstallParams = { pluginId: string,
|
||||
/**
|
||||
* When true, apply the remote plugin change before the local uninstall flow.
|
||||
*/
|
||||
forceRemoteSync?: boolean, };
|
||||
|
||||
@@ -11,9 +11,10 @@ import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
import type { ToolsV2 } from "./ToolsV2";
|
||||
|
||||
export type ProfileV2 = {model: string | null, model_provider: string | null, approval_policy: AskForApproval | null, /**
|
||||
export type ProfileV2 = { model: string | null, model_provider: string | null, approval_policy: AskForApproval | null,
|
||||
/**
|
||||
* [UNSTABLE] Optional profile-level override for where approval requests
|
||||
* are routed for review. If omitted, the enclosing config default is
|
||||
* used.
|
||||
*/
|
||||
approvals_reviewer: ApprovalsReviewer | null, service_tier: ServiceTier | null, model_reasoning_effort: ReasoningEffort | null, model_reasoning_summary: ReasoningSummary | null, model_verbosity: Verbosity | null, web_search: WebSearchMode | null, tools: ToolsV2 | null, chatgpt_base_url: string | null} & ({ [key in string]?: number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null });
|
||||
approvals_reviewer: ApprovalsReviewer | null, service_tier: ServiceTier | null, model_reasoning_effort: ReasoningEffort | null, model_reasoning_summary: ReasoningSummary | null, model_verbosity: Verbosity | null, web_search: WebSearchMode | null, tools: ToolsV2 | null, chatgpt_base_url: string | null, } & ({ [key in string]?: number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null });
|
||||
|
||||
@@ -0,0 +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 { AdditionalFileSystemPermissions } from "./AdditionalFileSystemPermissions";
|
||||
import type { AdditionalNetworkPermissions } from "./AdditionalNetworkPermissions";
|
||||
|
||||
export type RequestPermissionProfile = { network: AdditionalNetworkPermissions | null, fileSystem: AdditionalFileSystemPermissions | null, };
|
||||
@@ -3,4 +3,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { SubAgentSource } from "../SubAgentSource";
|
||||
|
||||
export type SessionSource = "cli" | "vscode" | "exec" | "appServer" | { "subAgent": SubAgentSource } | "unknown";
|
||||
export type SessionSource = "cli" | "vscode" | "exec" | "appServer" | { "custom": string } | { "subAgent": SubAgentSource } | "unknown";
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
// 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 { HazelnutScope } from "./HazelnutScope";
|
||||
import type { ProductSurface } from "./ProductSurface";
|
||||
|
||||
export type SkillsRemoteReadParams = { hazelnutScope: HazelnutScope, productSurface: ProductSurface, enabled: boolean, };
|
||||
@@ -1,6 +0,0 @@
|
||||
// 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 { RemoteSkillSummary } from "./RemoteSkillSummary";
|
||||
|
||||
export type SkillsRemoteReadResponse = { data: Array<RemoteSkillSummary>, };
|
||||
@@ -16,19 +16,23 @@ import type { SandboxMode } from "./SandboxMode";
|
||||
*
|
||||
* Prefer using thread_id whenever possible.
|
||||
*/
|
||||
export type ThreadForkParams = {threadId: string, /**
|
||||
export type ThreadForkParams = { threadId: string,
|
||||
/**
|
||||
* [UNSTABLE] Specify the rollout path to fork from.
|
||||
* If specified, the thread_id param will be ignored.
|
||||
*/
|
||||
path?: string | null, /**
|
||||
path?: string | null,
|
||||
/**
|
||||
* Configuration overrides for the forked thread, if any.
|
||||
*/
|
||||
model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier | null | null, cwd?: string | null, approvalPolicy?: AskForApproval | null, /**
|
||||
model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier | null | null, cwd?: string | null, approvalPolicy?: AskForApproval | null,
|
||||
/**
|
||||
* Override where approval requests are routed for review on this thread
|
||||
* and subsequent turns.
|
||||
*/
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, ephemeral?: boolean, /**
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, ephemeral?: boolean,
|
||||
/**
|
||||
* If true, persist additional rollout EventMsg variants required to
|
||||
* reconstruct a richer thread history on subsequent resume/fork/read.
|
||||
*/
|
||||
persistExtendedHistory: boolean};
|
||||
persistExtendedHistory: boolean, };
|
||||
|
||||
@@ -15,11 +15,12 @@ import type { FileUpdateChange } from "./FileUpdateChange";
|
||||
import type { McpToolCallError } from "./McpToolCallError";
|
||||
import type { McpToolCallResult } from "./McpToolCallResult";
|
||||
import type { McpToolCallStatus } from "./McpToolCallStatus";
|
||||
import type { MemoryCitation } from "./MemoryCitation";
|
||||
import type { PatchApplyStatus } from "./PatchApplyStatus";
|
||||
import type { UserInput } from "./UserInput";
|
||||
import type { WebSearchAction } from "./WebSearchAction";
|
||||
|
||||
export type ThreadItem = { "type": "userMessage", id: string, content: Array<UserInput>, } | { "type": "agentMessage", id: string, text: string, phase: MessagePhase | null, } | { "type": "plan", id: string, text: string, } | { "type": "reasoning", id: string, summary: Array<string>, content: Array<string>, } | { "type": "commandExecution", id: string,
|
||||
export type ThreadItem = { "type": "userMessage", id: string, content: Array<UserInput>, } | { "type": "agentMessage", id: string, text: string, phase: MessagePhase | null, memoryCitation: MemoryCitation | null, } | { "type": "plan", id: string, text: string, } | { "type": "reasoning", id: string, summary: Array<string>, content: Array<string>, } | { "type": "commandExecution", id: string,
|
||||
/**
|
||||
* The command to be executed.
|
||||
*/
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
/**
|
||||
* EXPERIMENTAL - thread realtime audio chunk.
|
||||
*/
|
||||
export type ThreadRealtimeAudioChunk = { data: string, sampleRate: number, numChannels: number, samplesPerChannel: number | null, };
|
||||
export type ThreadRealtimeAudioChunk = { data: string, sampleRate: number, numChannels: number, samplesPerChannel: number | null, itemId: string | null, };
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// 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 { RealtimeConversationVersion } from "../RealtimeConversationVersion";
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL - emitted when thread realtime startup is accepted.
|
||||
*/
|
||||
export type ThreadRealtimeStartedNotification = { threadId: string, sessionId: string | null, };
|
||||
export type ThreadRealtimeStartedNotification = { threadId: string, sessionId: string | null, version: RealtimeConversationVersion, };
|
||||
|
||||
@@ -20,24 +20,29 @@ import type { SandboxMode } from "./SandboxMode";
|
||||
*
|
||||
* Prefer using thread_id whenever possible.
|
||||
*/
|
||||
export type ThreadResumeParams = {threadId: string, /**
|
||||
export type ThreadResumeParams = { threadId: string,
|
||||
/**
|
||||
* [UNSTABLE] FOR CODEX CLOUD - DO NOT USE.
|
||||
* If specified, the thread will be resumed with the provided history
|
||||
* instead of loaded from disk.
|
||||
*/
|
||||
history?: Array<ResponseItem> | null, /**
|
||||
history?: Array<ResponseItem> | null,
|
||||
/**
|
||||
* [UNSTABLE] Specify the rollout path to resume from.
|
||||
* If specified, the thread_id param will be ignored.
|
||||
*/
|
||||
path?: string | null, /**
|
||||
path?: string | null,
|
||||
/**
|
||||
* Configuration overrides for the resumed thread, if any.
|
||||
*/
|
||||
model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier | null | null, cwd?: string | null, approvalPolicy?: AskForApproval | null, /**
|
||||
model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier | null | null, cwd?: string | null, approvalPolicy?: AskForApproval | null,
|
||||
/**
|
||||
* Override where approval requests are routed for review on this thread
|
||||
* and subsequent turns.
|
||||
*/
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, /**
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null,
|
||||
/**
|
||||
* If true, persist additional rollout EventMsg variants required to
|
||||
* reconstruct a richer thread history on subsequent resume/fork/read.
|
||||
*/
|
||||
persistExtendedHistory: boolean};
|
||||
persistExtendedHistory: boolean, };
|
||||
|
||||
@@ -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 ThreadSourceKind = "cli" | "vscode" | "exec" | "appServer" | "subAgent" | "subAgentReview" | "subAgentCompact" | "subAgentThreadSpawn" | "subAgentOther" | "unknown";
|
||||
export type ThreadSourceKind = "cli" | "vscode" | "exec" | "appServer" | "custom" | "subAgent" | "subAgentReview" | "subAgentCompact" | "subAgentThreadSpawn" | "subAgentOther" | "unknown";
|
||||
|
||||
@@ -6,18 +6,27 @@ import type { ServiceTier } from "../ServiceTier";
|
||||
import type { JsonValue } from "../serde_json/JsonValue";
|
||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
import type { DynamicToolSpec } from "./DynamicToolSpec";
|
||||
import type { SandboxMode } from "./SandboxMode";
|
||||
|
||||
export type ThreadStartParams = {model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier | null | null, cwd?: string | null, approvalPolicy?: AskForApproval | null, /**
|
||||
export type ThreadStartParams = { model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier | null | null, cwd?: string | null, approvalPolicy?: AskForApproval | null,
|
||||
/**
|
||||
* Override where approval requests are routed for review on this thread
|
||||
* and subsequent turns.
|
||||
*/
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, serviceName?: string | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, ephemeral?: boolean | null, /**
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, serviceName?: string | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, ephemeral?: boolean | null, dynamicTools?: Array<DynamicToolSpec> | null,
|
||||
/**
|
||||
* Test-only experimental field used to validate experimental gating and
|
||||
* schema filtering behavior in a stable way.
|
||||
*/
|
||||
mockExperimentalField?: string | null,
|
||||
/**
|
||||
* If true, opt into emitting raw Responses API items on the event stream.
|
||||
* This is for internal use only (e.g. Codex Cloud).
|
||||
*/
|
||||
experimentalRawEvents: boolean, /**
|
||||
experimentalRawEvents: boolean,
|
||||
/**
|
||||
* If true, persist additional rollout EventMsg variants required to
|
||||
* reconstruct a richer thread history on resume/fork/read.
|
||||
*/
|
||||
persistExtendedHistory: boolean};
|
||||
persistExtendedHistory: boolean, };
|
||||
|
||||
@@ -12,43 +12,54 @@ import type { AskForApproval } from "./AskForApproval";
|
||||
import type { SandboxPolicy } from "./SandboxPolicy";
|
||||
import type { UserInput } from "./UserInput";
|
||||
|
||||
export type TurnStartParams = {threadId: string, input: Array<UserInput>, /**
|
||||
export type TurnStartParams = { threadId: string, input: Array<UserInput>,
|
||||
/**
|
||||
* Override the working directory for this turn and subsequent turns.
|
||||
*/
|
||||
cwd?: string | null, /**
|
||||
cwd?: string | null,
|
||||
/**
|
||||
* Override the approval policy for this turn and subsequent turns.
|
||||
*/
|
||||
approvalPolicy?: AskForApproval | null, /**
|
||||
approvalPolicy?: AskForApproval | null,
|
||||
/**
|
||||
* Override where approval requests are routed for review on this turn and
|
||||
* subsequent turns.
|
||||
*/
|
||||
approvalsReviewer?: ApprovalsReviewer | null, /**
|
||||
approvalsReviewer?: ApprovalsReviewer | null,
|
||||
/**
|
||||
* Override the sandbox policy for this turn and subsequent turns.
|
||||
*/
|
||||
sandboxPolicy?: SandboxPolicy | null, /**
|
||||
sandboxPolicy?: SandboxPolicy | null,
|
||||
/**
|
||||
* Override the model for this turn and subsequent turns.
|
||||
*/
|
||||
model?: string | null, /**
|
||||
model?: string | null,
|
||||
/**
|
||||
* Override the service tier for this turn and subsequent turns.
|
||||
*/
|
||||
serviceTier?: ServiceTier | null | null, /**
|
||||
serviceTier?: ServiceTier | null | null,
|
||||
/**
|
||||
* Override the reasoning effort for this turn and subsequent turns.
|
||||
*/
|
||||
effort?: ReasoningEffort | null, /**
|
||||
effort?: ReasoningEffort | null,
|
||||
/**
|
||||
* Override the reasoning summary for this turn and subsequent turns.
|
||||
*/
|
||||
summary?: ReasoningSummary | null, /**
|
||||
summary?: ReasoningSummary | null,
|
||||
/**
|
||||
* Override the personality for this turn and subsequent turns.
|
||||
*/
|
||||
personality?: Personality | null, /**
|
||||
personality?: Personality | null,
|
||||
/**
|
||||
* Optional JSON Schema used to constrain the final assistant message for
|
||||
* this turn.
|
||||
*/
|
||||
outputSchema?: JsonValue | null, /**
|
||||
outputSchema?: JsonValue | null,
|
||||
/**
|
||||
* EXPERIMENTAL - Set a pre-set collaboration mode.
|
||||
* Takes precedence over model, reasoning_effort, and developer instructions if set.
|
||||
*
|
||||
* For `collaboration_mode.settings.developer_instructions`, `null` means
|
||||
* "use the built-in instructions for the selected mode".
|
||||
*/
|
||||
collaborationMode?: CollaborationMode | null};
|
||||
collaborationMode?: CollaborationMode | null, };
|
||||
|
||||
@@ -37,6 +37,8 @@ export type { CollabAgentState } from "./CollabAgentState";
|
||||
export type { CollabAgentStatus } from "./CollabAgentStatus";
|
||||
export type { CollabAgentTool } from "./CollabAgentTool";
|
||||
export type { CollabAgentToolCallStatus } from "./CollabAgentToolCallStatus";
|
||||
export type { CollaborationModeListParams } from "./CollaborationModeListParams";
|
||||
export type { CollaborationModeListResponse } from "./CollaborationModeListResponse";
|
||||
export type { CollaborationModeMask } from "./CollaborationModeMask";
|
||||
export type { CommandAction } from "./CommandAction";
|
||||
export type { CommandExecOutputDeltaNotification } from "./CommandExecOutputDeltaNotification";
|
||||
@@ -115,12 +117,10 @@ export type { GetAccountParams } from "./GetAccountParams";
|
||||
export type { GetAccountRateLimitsResponse } from "./GetAccountRateLimitsResponse";
|
||||
export type { GetAccountResponse } from "./GetAccountResponse";
|
||||
export type { GitInfo } from "./GitInfo";
|
||||
export type { GrantedMacOsPermissions } from "./GrantedMacOsPermissions";
|
||||
export type { GrantedPermissionProfile } from "./GrantedPermissionProfile";
|
||||
export type { GuardianApprovalReview } from "./GuardianApprovalReview";
|
||||
export type { GuardianApprovalReviewStatus } from "./GuardianApprovalReviewStatus";
|
||||
export type { GuardianRiskLevel } from "./GuardianRiskLevel";
|
||||
export type { HazelnutScope } from "./HazelnutScope";
|
||||
export type { HookCompletedNotification } from "./HookCompletedNotification";
|
||||
export type { HookEventName } from "./HookEventName";
|
||||
export type { HookExecutionMode } from "./HookExecutionMode";
|
||||
@@ -140,6 +140,7 @@ export type { ListMcpServerStatusResponse } from "./ListMcpServerStatusResponse"
|
||||
export type { LoginAccountParams } from "./LoginAccountParams";
|
||||
export type { LoginAccountResponse } from "./LoginAccountResponse";
|
||||
export type { LogoutAccountResponse } from "./LogoutAccountResponse";
|
||||
export type { MarketplaceInterface } from "./MarketplaceInterface";
|
||||
export type { McpAuthStatus } from "./McpAuthStatus";
|
||||
export type { McpElicitationArrayType } from "./McpElicitationArrayType";
|
||||
export type { McpElicitationBooleanSchema } from "./McpElicitationBooleanSchema";
|
||||
@@ -175,7 +176,11 @@ export type { McpToolCallError } from "./McpToolCallError";
|
||||
export type { McpToolCallProgressNotification } from "./McpToolCallProgressNotification";
|
||||
export type { McpToolCallResult } from "./McpToolCallResult";
|
||||
export type { McpToolCallStatus } from "./McpToolCallStatus";
|
||||
export type { MemoryCitation } from "./MemoryCitation";
|
||||
export type { MemoryCitationEntry } from "./MemoryCitationEntry";
|
||||
export type { MergeStrategy } from "./MergeStrategy";
|
||||
export type { MockExperimentalMethodParams } from "./MockExperimentalMethodParams";
|
||||
export type { MockExperimentalMethodResponse } from "./MockExperimentalMethodResponse";
|
||||
export type { Model } from "./Model";
|
||||
export type { ModelAvailabilityNux } from "./ModelAvailabilityNux";
|
||||
export type { ModelListParams } from "./ModelListParams";
|
||||
@@ -186,9 +191,11 @@ export type { ModelUpgradeInfo } from "./ModelUpgradeInfo";
|
||||
export type { NetworkAccess } from "./NetworkAccess";
|
||||
export type { NetworkApprovalContext } from "./NetworkApprovalContext";
|
||||
export type { NetworkApprovalProtocol } from "./NetworkApprovalProtocol";
|
||||
export type { NetworkDomainPermission } from "./NetworkDomainPermission";
|
||||
export type { NetworkPolicyAmendment } from "./NetworkPolicyAmendment";
|
||||
export type { NetworkPolicyRuleAction } from "./NetworkPolicyRuleAction";
|
||||
export type { NetworkRequirements } from "./NetworkRequirements";
|
||||
export type { NetworkUnixSocketPermission } from "./NetworkUnixSocketPermission";
|
||||
export type { OverriddenMetadata } from "./OverriddenMetadata";
|
||||
export type { PatchApplyStatus } from "./PatchApplyStatus";
|
||||
export type { PatchChangeKind } from "./PatchChangeKind";
|
||||
@@ -211,7 +218,6 @@ export type { PluginSource } from "./PluginSource";
|
||||
export type { PluginSummary } from "./PluginSummary";
|
||||
export type { PluginUninstallParams } from "./PluginUninstallParams";
|
||||
export type { PluginUninstallResponse } from "./PluginUninstallResponse";
|
||||
export type { ProductSurface } from "./ProductSurface";
|
||||
export type { ProfileV2 } from "./ProfileV2";
|
||||
export type { RateLimitSnapshot } from "./RateLimitSnapshot";
|
||||
export type { RateLimitWindow } from "./RateLimitWindow";
|
||||
@@ -221,7 +227,7 @@ export type { ReasoningEffortOption } from "./ReasoningEffortOption";
|
||||
export type { ReasoningSummaryPartAddedNotification } from "./ReasoningSummaryPartAddedNotification";
|
||||
export type { ReasoningSummaryTextDeltaNotification } from "./ReasoningSummaryTextDeltaNotification";
|
||||
export type { ReasoningTextDeltaNotification } from "./ReasoningTextDeltaNotification";
|
||||
export type { RemoteSkillSummary } from "./RemoteSkillSummary";
|
||||
export type { RequestPermissionProfile } from "./RequestPermissionProfile";
|
||||
export type { ResidencyRequirement } from "./ResidencyRequirement";
|
||||
export type { ReviewDelivery } from "./ReviewDelivery";
|
||||
export type { ReviewStartParams } from "./ReviewStartParams";
|
||||
@@ -246,10 +252,6 @@ export type { SkillsListEntry } from "./SkillsListEntry";
|
||||
export type { SkillsListExtraRootsForCwd } from "./SkillsListExtraRootsForCwd";
|
||||
export type { SkillsListParams } from "./SkillsListParams";
|
||||
export type { SkillsListResponse } from "./SkillsListResponse";
|
||||
export type { SkillsRemoteReadParams } from "./SkillsRemoteReadParams";
|
||||
export type { SkillsRemoteReadResponse } from "./SkillsRemoteReadResponse";
|
||||
export type { SkillsRemoteWriteParams } from "./SkillsRemoteWriteParams";
|
||||
export type { SkillsRemoteWriteResponse } from "./SkillsRemoteWriteResponse";
|
||||
export type { TerminalInteractionNotification } from "./TerminalInteractionNotification";
|
||||
export type { TextElement } from "./TextElement";
|
||||
export type { TextPosition } from "./TextPosition";
|
||||
@@ -259,11 +261,17 @@ export type { ThreadActiveFlag } from "./ThreadActiveFlag";
|
||||
export type { ThreadArchiveParams } from "./ThreadArchiveParams";
|
||||
export type { ThreadArchiveResponse } from "./ThreadArchiveResponse";
|
||||
export type { ThreadArchivedNotification } from "./ThreadArchivedNotification";
|
||||
export type { ThreadBackgroundTerminalsCleanParams } from "./ThreadBackgroundTerminalsCleanParams";
|
||||
export type { ThreadBackgroundTerminalsCleanResponse } from "./ThreadBackgroundTerminalsCleanResponse";
|
||||
export type { ThreadClosedNotification } from "./ThreadClosedNotification";
|
||||
export type { ThreadCompactStartParams } from "./ThreadCompactStartParams";
|
||||
export type { ThreadCompactStartResponse } from "./ThreadCompactStartResponse";
|
||||
export type { ThreadDecrementElicitationParams } from "./ThreadDecrementElicitationParams";
|
||||
export type { ThreadDecrementElicitationResponse } from "./ThreadDecrementElicitationResponse";
|
||||
export type { ThreadForkParams } from "./ThreadForkParams";
|
||||
export type { ThreadForkResponse } from "./ThreadForkResponse";
|
||||
export type { ThreadIncrementElicitationParams } from "./ThreadIncrementElicitationParams";
|
||||
export type { ThreadIncrementElicitationResponse } from "./ThreadIncrementElicitationResponse";
|
||||
export type { ThreadItem } from "./ThreadItem";
|
||||
export type { ThreadListParams } from "./ThreadListParams";
|
||||
export type { ThreadListResponse } from "./ThreadListResponse";
|
||||
@@ -275,12 +283,20 @@ export type { ThreadMetadataUpdateResponse } from "./ThreadMetadataUpdateRespons
|
||||
export type { ThreadNameUpdatedNotification } from "./ThreadNameUpdatedNotification";
|
||||
export type { ThreadReadParams } from "./ThreadReadParams";
|
||||
export type { ThreadReadResponse } from "./ThreadReadResponse";
|
||||
export type { ThreadRealtimeAppendAudioParams } from "./ThreadRealtimeAppendAudioParams";
|
||||
export type { ThreadRealtimeAppendAudioResponse } from "./ThreadRealtimeAppendAudioResponse";
|
||||
export type { ThreadRealtimeAppendTextParams } from "./ThreadRealtimeAppendTextParams";
|
||||
export type { ThreadRealtimeAppendTextResponse } from "./ThreadRealtimeAppendTextResponse";
|
||||
export type { ThreadRealtimeAudioChunk } from "./ThreadRealtimeAudioChunk";
|
||||
export type { ThreadRealtimeClosedNotification } from "./ThreadRealtimeClosedNotification";
|
||||
export type { ThreadRealtimeErrorNotification } from "./ThreadRealtimeErrorNotification";
|
||||
export type { ThreadRealtimeItemAddedNotification } from "./ThreadRealtimeItemAddedNotification";
|
||||
export type { ThreadRealtimeOutputAudioDeltaNotification } from "./ThreadRealtimeOutputAudioDeltaNotification";
|
||||
export type { ThreadRealtimeStartParams } from "./ThreadRealtimeStartParams";
|
||||
export type { ThreadRealtimeStartResponse } from "./ThreadRealtimeStartResponse";
|
||||
export type { ThreadRealtimeStartedNotification } from "./ThreadRealtimeStartedNotification";
|
||||
export type { ThreadRealtimeStopParams } from "./ThreadRealtimeStopParams";
|
||||
export type { ThreadRealtimeStopResponse } from "./ThreadRealtimeStopResponse";
|
||||
export type { ThreadResumeParams } from "./ThreadResumeParams";
|
||||
export type { ThreadResumeResponse } from "./ThreadResumeResponse";
|
||||
export type { ThreadRollbackParams } from "./ThreadRollbackParams";
|
||||
|
||||
@@ -17,6 +17,7 @@ use crate::protocol::common::EXPERIMENTAL_CLIENT_METHODS;
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use anyhow::anyhow;
|
||||
use codex_protocol::protocol::RolloutLine;
|
||||
use schemars::JsonSchema;
|
||||
use schemars::schema_for;
|
||||
use serde::Serialize;
|
||||
@@ -182,7 +183,13 @@ pub fn generate_ts_with_options(
|
||||
}
|
||||
|
||||
pub fn generate_json(out_dir: &Path) -> Result<()> {
|
||||
generate_json_with_experimental(out_dir, false)
|
||||
generate_json_with_experimental(out_dir, /*experimental_api*/ false)
|
||||
}
|
||||
|
||||
pub fn generate_internal_json_schema(out_dir: &Path) -> Result<()> {
|
||||
ensure_dir(out_dir)?;
|
||||
write_json_schema::<RolloutLine>(out_dir, "RolloutLine")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn generate_json_with_experimental(out_dir: &Path, experimental_api: bool) -> Result<()> {
|
||||
@@ -1984,7 +1991,7 @@ pub(crate) fn generate_index_ts_tree(tree: &mut BTreeMap<PathBuf, String>) {
|
||||
if !v2_entries.is_empty() {
|
||||
tree.insert(
|
||||
PathBuf::from("v2").join("index.ts"),
|
||||
index_ts_entries(&v2_entries, false),
|
||||
index_ts_entries(&v2_entries, /*has_v2_ts*/ false),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ mod schema_fixtures;
|
||||
|
||||
pub use experimental_api::*;
|
||||
pub use export::GenerateTsOptions;
|
||||
pub use export::generate_internal_json_schema;
|
||||
pub use export::generate_json;
|
||||
pub use export::generate_json_with_experimental;
|
||||
pub use export::generate_ts;
|
||||
|
||||
@@ -300,14 +300,6 @@ client_request_definitions! {
|
||||
params: v2::PluginReadParams,
|
||||
response: v2::PluginReadResponse,
|
||||
},
|
||||
SkillsRemoteList => "skills/remote/list" {
|
||||
params: v2::SkillsRemoteReadParams,
|
||||
response: v2::SkillsRemoteReadResponse,
|
||||
},
|
||||
SkillsRemoteExport => "skills/remote/export" {
|
||||
params: v2::SkillsRemoteWriteParams,
|
||||
response: v2::SkillsRemoteWriteResponse,
|
||||
},
|
||||
AppsList => "app/list" {
|
||||
params: v2::AppsListParams,
|
||||
response: v2::AppsListResponse,
|
||||
@@ -946,6 +938,7 @@ mod tests {
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::account::PlanType;
|
||||
use codex_protocol::parse_command::ParsedCommand;
|
||||
use codex_protocol::protocol::RealtimeConversationVersion;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::json;
|
||||
@@ -1577,6 +1570,7 @@ mod tests {
|
||||
sample_rate: 24_000,
|
||||
num_channels: 1,
|
||||
samples_per_channel: Some(512),
|
||||
item_id: None,
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -1589,7 +1583,8 @@ mod tests {
|
||||
"data": "AQID",
|
||||
"sampleRate": 24000,
|
||||
"numChannels": 1,
|
||||
"samplesPerChannel": 512
|
||||
"samplesPerChannel": 512,
|
||||
"itemId": null
|
||||
}
|
||||
}
|
||||
}),
|
||||
@@ -1626,6 +1621,7 @@ mod tests {
|
||||
ServerNotification::ThreadRealtimeStarted(v2::ThreadRealtimeStartedNotification {
|
||||
thread_id: "thr_123".to_string(),
|
||||
session_id: Some("sess_456".to_string()),
|
||||
version: RealtimeConversationVersion::V1,
|
||||
});
|
||||
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(¬ification);
|
||||
assert_eq!(reason, Some("thread/realtime/started"));
|
||||
@@ -1641,6 +1637,7 @@ mod tests {
|
||||
sample_rate: 24_000,
|
||||
num_channels: 1,
|
||||
samples_per_channel: Some(512),
|
||||
item_id: None,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -118,9 +118,11 @@ impl ThreadHistoryBuilder {
|
||||
pub fn handle_event(&mut self, event: &EventMsg) {
|
||||
match event {
|
||||
EventMsg::UserMessage(payload) => self.handle_user_message(payload),
|
||||
EventMsg::AgentMessage(payload) => {
|
||||
self.handle_agent_message(payload.message.clone(), payload.phase.clone())
|
||||
}
|
||||
EventMsg::AgentMessage(payload) => self.handle_agent_message(
|
||||
payload.message.clone(),
|
||||
payload.phase.clone(),
|
||||
payload.memory_citation.clone().map(Into::into),
|
||||
),
|
||||
EventMsg::AgentReasoning(payload) => self.handle_agent_reasoning(payload),
|
||||
EventMsg::AgentReasoningRawContent(payload) => {
|
||||
self.handle_agent_reasoning_raw_content(payload)
|
||||
@@ -201,22 +203,30 @@ impl ThreadHistoryBuilder {
|
||||
let mut turn = self
|
||||
.current_turn
|
||||
.take()
|
||||
.unwrap_or_else(|| self.new_turn(None));
|
||||
.unwrap_or_else(|| self.new_turn(/*id*/ None));
|
||||
let id = self.next_item_id();
|
||||
let content = self.build_user_inputs(payload);
|
||||
turn.items.push(ThreadItem::UserMessage { id, content });
|
||||
self.current_turn = Some(turn);
|
||||
}
|
||||
|
||||
fn handle_agent_message(&mut self, text: String, phase: Option<MessagePhase>) {
|
||||
fn handle_agent_message(
|
||||
&mut self,
|
||||
text: String,
|
||||
phase: Option<MessagePhase>,
|
||||
memory_citation: Option<crate::protocol::v2::MemoryCitation>,
|
||||
) {
|
||||
if text.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let id = self.next_item_id();
|
||||
self.ensure_turn()
|
||||
.items
|
||||
.push(ThreadItem::AgentMessage { id, text, phase });
|
||||
self.ensure_turn().items.push(ThreadItem::AgentMessage {
|
||||
id,
|
||||
text,
|
||||
phase,
|
||||
memory_citation,
|
||||
});
|
||||
}
|
||||
|
||||
fn handle_agent_reasoning(&mut self, payload: &AgentReasoningEvent) {
|
||||
@@ -937,7 +947,7 @@ impl ThreadHistoryBuilder {
|
||||
|
||||
fn ensure_turn(&mut self) -> &mut PendingTurn {
|
||||
if self.current_turn.is_none() {
|
||||
let turn = self.new_turn(None);
|
||||
let turn = self.new_turn(/*id*/ None);
|
||||
return self.current_turn.insert(turn);
|
||||
}
|
||||
|
||||
@@ -1178,6 +1188,7 @@ mod tests {
|
||||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Hi there".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::AgentReasoning(AgentReasoningEvent {
|
||||
text: "thinking".into(),
|
||||
@@ -1194,6 +1205,7 @@ mod tests {
|
||||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Reply two".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -1229,6 +1241,7 @@ mod tests {
|
||||
id: "item-2".into(),
|
||||
text: "Hi there".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -1260,6 +1273,7 @@ mod tests {
|
||||
id: "item-5".into(),
|
||||
text: "Reply two".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1318,6 +1332,7 @@ mod tests {
|
||||
let events = vec![EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Final reply".into(),
|
||||
phase: Some(CoreMessagePhase::FinalAnswer),
|
||||
memory_citation: None,
|
||||
})];
|
||||
|
||||
let items = events
|
||||
@@ -1332,6 +1347,7 @@ mod tests {
|
||||
id: "item-1".into(),
|
||||
text: "Final reply".into(),
|
||||
phase: Some(MessagePhase::FinalAnswer),
|
||||
memory_citation: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1354,6 +1370,7 @@ mod tests {
|
||||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "interlude".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::AgentReasoning(AgentReasoningEvent {
|
||||
text: "second summary".into(),
|
||||
@@ -1399,6 +1416,7 @@ mod tests {
|
||||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Working...".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::TurnAborted(TurnAbortedEvent {
|
||||
turn_id: Some("turn-1".into()),
|
||||
@@ -1413,6 +1431,7 @@ mod tests {
|
||||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Second attempt complete.".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -1442,6 +1461,7 @@ mod tests {
|
||||
id: "item-2".into(),
|
||||
text: "Working...".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1464,6 +1484,7 @@ mod tests {
|
||||
id: "item-4".into(),
|
||||
text: "Second attempt complete.".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1480,6 +1501,7 @@ mod tests {
|
||||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "A1".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::UserMessage(UserMessageEvent {
|
||||
message: "Second".into(),
|
||||
@@ -1490,6 +1512,7 @@ mod tests {
|
||||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "A2".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::ThreadRolledBack(ThreadRolledBackEvent { num_turns: 1 }),
|
||||
EventMsg::UserMessage(UserMessageEvent {
|
||||
@@ -1501,6 +1524,7 @@ mod tests {
|
||||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "A3".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -1529,6 +1553,7 @@ mod tests {
|
||||
id: "item-2".into(),
|
||||
text: "A1".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
},
|
||||
]
|
||||
);
|
||||
@@ -1546,6 +1571,7 @@ mod tests {
|
||||
id: "item-4".into(),
|
||||
text: "A3".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
},
|
||||
]
|
||||
);
|
||||
@@ -1563,6 +1589,7 @@ mod tests {
|
||||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "A1".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::UserMessage(UserMessageEvent {
|
||||
message: "Two".into(),
|
||||
@@ -1573,6 +1600,7 @@ mod tests {
|
||||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "A2".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::ThreadRolledBack(ThreadRolledBackEvent { num_turns: 99 }),
|
||||
];
|
||||
@@ -2209,6 +2237,7 @@ mod tests {
|
||||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "still in b".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::TurnComplete(TurnCompleteEvent {
|
||||
turn_id: "turn-b".into(),
|
||||
@@ -2263,6 +2292,7 @@ mod tests {
|
||||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "still in b".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -2417,6 +2447,74 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reconstructs_interrupted_send_input_as_completed_collab_call() {
|
||||
// `send_input(interrupt=true)` first stops the child's active turn, then redirects it with
|
||||
// new input. The transient interrupted status should remain visible in agent state, but the
|
||||
// collab tool call itself is still a successful redirect rather than a failed operation.
|
||||
let sender = ThreadId::try_from("00000000-0000-0000-0000-000000000001")
|
||||
.expect("valid sender thread id");
|
||||
let receiver = ThreadId::try_from("00000000-0000-0000-0000-000000000002")
|
||||
.expect("valid receiver thread id");
|
||||
let events = vec![
|
||||
EventMsg::UserMessage(UserMessageEvent {
|
||||
message: "redirect".into(),
|
||||
images: None,
|
||||
text_elements: Vec::new(),
|
||||
local_images: Vec::new(),
|
||||
}),
|
||||
EventMsg::CollabAgentInteractionBegin(
|
||||
codex_protocol::protocol::CollabAgentInteractionBeginEvent {
|
||||
call_id: "send-1".into(),
|
||||
sender_thread_id: sender,
|
||||
receiver_thread_id: receiver,
|
||||
prompt: "new task".into(),
|
||||
},
|
||||
),
|
||||
EventMsg::CollabAgentInteractionEnd(
|
||||
codex_protocol::protocol::CollabAgentInteractionEndEvent {
|
||||
call_id: "send-1".into(),
|
||||
sender_thread_id: sender,
|
||||
receiver_thread_id: receiver,
|
||||
receiver_agent_nickname: None,
|
||||
receiver_agent_role: None,
|
||||
prompt: "new task".into(),
|
||||
status: AgentStatus::Interrupted,
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
let items = events
|
||||
.into_iter()
|
||||
.map(RolloutItem::EventMsg)
|
||||
.collect::<Vec<_>>();
|
||||
let turns = build_turns_from_rollout_items(&items);
|
||||
assert_eq!(turns.len(), 1);
|
||||
assert_eq!(turns[0].items.len(), 2);
|
||||
assert_eq!(
|
||||
turns[0].items[1],
|
||||
ThreadItem::CollabAgentToolCall {
|
||||
id: "send-1".into(),
|
||||
tool: CollabAgentTool::SendInput,
|
||||
status: CollabAgentToolCallStatus::Completed,
|
||||
sender_thread_id: sender.to_string(),
|
||||
receiver_thread_ids: vec![receiver.to_string()],
|
||||
prompt: Some("new task".into()),
|
||||
model: None,
|
||||
reasoning_effort: None,
|
||||
agents_states: [(
|
||||
receiver.to_string(),
|
||||
CollabAgentState {
|
||||
status: crate::protocol::v2::CollabAgentStatus::Interrupted,
|
||||
message: None,
|
||||
},
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rollback_failed_error_does_not_mark_turn_failed() {
|
||||
let events = vec![
|
||||
@@ -2429,6 +2527,7 @@ mod tests {
|
||||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "done".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::Error(ErrorEvent {
|
||||
message: "rollback failed".into(),
|
||||
|
||||
@@ -30,6 +30,8 @@ use codex_protocol::items::TurnItem as CoreTurnItem;
|
||||
use codex_protocol::mcp::Resource as McpResource;
|
||||
use codex_protocol::mcp::ResourceTemplate as McpResourceTemplate;
|
||||
use codex_protocol::mcp::Tool as McpTool;
|
||||
use codex_protocol::memory_citation::MemoryCitation as CoreMemoryCitation;
|
||||
use codex_protocol::memory_citation::MemoryCitationEntry as CoreMemoryCitationEntry;
|
||||
use codex_protocol::models::FileSystemPermissions as CoreFileSystemPermissions;
|
||||
use codex_protocol::models::MacOsAutomationPermission as CoreMacOsAutomationPermission;
|
||||
use codex_protocol::models::MacOsContactsPermission as CoreMacOsContactsPermission;
|
||||
@@ -68,6 +70,7 @@ use codex_protocol::protocol::RateLimitSnapshot as CoreRateLimitSnapshot;
|
||||
use codex_protocol::protocol::RateLimitWindow as CoreRateLimitWindow;
|
||||
use codex_protocol::protocol::ReadOnlyAccess as CoreReadOnlyAccess;
|
||||
use codex_protocol::protocol::RealtimeAudioFrame as CoreRealtimeAudioFrame;
|
||||
use codex_protocol::protocol::RealtimeConversationVersion;
|
||||
use codex_protocol::protocol::ReviewDecision as CoreReviewDecision;
|
||||
use codex_protocol::protocol::SessionSource as CoreSessionSource;
|
||||
use codex_protocol::protocol::SkillDependencies as CoreSkillDependencies;
|
||||
@@ -80,6 +83,7 @@ use codex_protocol::protocol::SubAgentSource as CoreSubAgentSource;
|
||||
use codex_protocol::protocol::TokenUsage as CoreTokenUsage;
|
||||
use codex_protocol::protocol::TokenUsageInfo as CoreTokenUsageInfo;
|
||||
use codex_protocol::request_permissions::PermissionGrantScope as CorePermissionGrantScope;
|
||||
use codex_protocol::request_permissions::RequestPermissionProfile as CoreRequestPermissionProfile;
|
||||
use codex_protocol::user_input::ByteRange as CoreByteRange;
|
||||
use codex_protocol::user_input::TextElement as CoreTextElement;
|
||||
use codex_protocol::user_input::UserInput as CoreUserInput;
|
||||
@@ -341,7 +345,7 @@ v2_enum_from_core!(
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum HookEventName from CoreHookEventName {
|
||||
SessionStart, Stop
|
||||
SessionStart, UserPromptSubmit, Stop
|
||||
}
|
||||
);
|
||||
|
||||
@@ -835,12 +839,28 @@ pub struct NetworkRequirements {
|
||||
pub allow_upstream_proxy: Option<bool>,
|
||||
pub dangerously_allow_non_loopback_proxy: Option<bool>,
|
||||
pub dangerously_allow_all_unix_sockets: Option<bool>,
|
||||
pub allowed_domains: Option<Vec<String>>,
|
||||
pub denied_domains: Option<Vec<String>>,
|
||||
pub allow_unix_sockets: Option<Vec<String>>,
|
||||
pub domains: Option<BTreeMap<String, NetworkDomainPermission>>,
|
||||
pub unix_sockets: Option<BTreeMap<String, NetworkUnixSocketPermission>>,
|
||||
pub allow_local_binding: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum NetworkDomainPermission {
|
||||
Allow,
|
||||
Deny,
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum NetworkUnixSocketPermission {
|
||||
Allow,
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
@@ -1114,6 +1134,33 @@ impl From<AdditionalNetworkPermissions> for CoreNetworkPermissions {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct RequestPermissionProfile {
|
||||
pub network: Option<AdditionalNetworkPermissions>,
|
||||
pub file_system: Option<AdditionalFileSystemPermissions>,
|
||||
}
|
||||
|
||||
impl From<CoreRequestPermissionProfile> for RequestPermissionProfile {
|
||||
fn from(value: CoreRequestPermissionProfile) -> Self {
|
||||
Self {
|
||||
network: value.network.map(AdditionalNetworkPermissions::from),
|
||||
file_system: value.file_system.map(AdditionalFileSystemPermissions::from),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RequestPermissionProfile> for CoreRequestPermissionProfile {
|
||||
fn from(value: RequestPermissionProfile) -> Self {
|
||||
Self {
|
||||
network: value.network.map(CoreNetworkPermissions::from),
|
||||
file_system: value.file_system.map(CoreFileSystemPermissions::from),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
@@ -1143,51 +1190,6 @@ impl From<AdditionalPermissionProfile> for CorePermissionProfile {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct GrantedMacOsPermissions {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub preferences: Option<CoreMacOsPreferencesPermission>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub automations: Option<CoreMacOsAutomationPermission>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub launch_services: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub accessibility: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub calendar: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub reminders: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub contacts: Option<CoreMacOsContactsPermission>,
|
||||
}
|
||||
|
||||
impl From<GrantedMacOsPermissions> for CoreMacOsSeatbeltProfileExtensions {
|
||||
fn from(value: GrantedMacOsPermissions) -> Self {
|
||||
Self {
|
||||
macos_preferences: value
|
||||
.preferences
|
||||
.unwrap_or(CoreMacOsPreferencesPermission::None),
|
||||
macos_automation: value
|
||||
.automations
|
||||
.unwrap_or(CoreMacOsAutomationPermission::None),
|
||||
macos_launch_services: value.launch_services.unwrap_or(false),
|
||||
macos_accessibility: value.accessibility.unwrap_or(false),
|
||||
macos_calendar: value.calendar.unwrap_or(false),
|
||||
macos_reminders: value.reminders.unwrap_or(false),
|
||||
macos_contacts: value.contacts.unwrap_or(CoreMacOsContactsPermission::None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
@@ -1198,32 +1200,14 @@ pub struct GrantedPermissionProfile {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub file_system: Option<AdditionalFileSystemPermissions>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub macos: Option<GrantedMacOsPermissions>,
|
||||
}
|
||||
|
||||
impl From<GrantedPermissionProfile> for CorePermissionProfile {
|
||||
fn from(value: GrantedPermissionProfile) -> Self {
|
||||
let macos = value.macos.and_then(|macos| {
|
||||
if macos.preferences.is_none()
|
||||
&& macos.automations.is_none()
|
||||
&& macos.launch_services.is_none()
|
||||
&& macos.accessibility.is_none()
|
||||
&& macos.calendar.is_none()
|
||||
&& macos.reminders.is_none()
|
||||
&& macos.contacts.is_none()
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(CoreMacOsSeatbeltProfileExtensions::from(macos))
|
||||
}
|
||||
});
|
||||
|
||||
Self {
|
||||
network: value.network.map(CoreNetworkPermissions::from),
|
||||
file_system: value.file_system.map(CoreFileSystemPermissions::from),
|
||||
macos,
|
||||
macos: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1499,6 +1483,7 @@ pub enum SessionSource {
|
||||
VsCode,
|
||||
Exec,
|
||||
AppServer,
|
||||
Custom(String),
|
||||
SubAgent(CoreSubAgentSource),
|
||||
#[serde(other)]
|
||||
Unknown,
|
||||
@@ -1511,6 +1496,7 @@ impl From<CoreSessionSource> for SessionSource {
|
||||
CoreSessionSource::VSCode => SessionSource::VsCode,
|
||||
CoreSessionSource::Exec => SessionSource::Exec,
|
||||
CoreSessionSource::Mcp => SessionSource::AppServer,
|
||||
CoreSessionSource::Custom(source) => SessionSource::Custom(source),
|
||||
CoreSessionSource::SubAgent(sub) => SessionSource::SubAgent(sub),
|
||||
CoreSessionSource::Unknown => SessionSource::Unknown,
|
||||
}
|
||||
@@ -1524,6 +1510,7 @@ impl From<SessionSource> for CoreSessionSource {
|
||||
SessionSource::VsCode => CoreSessionSource::VSCode,
|
||||
SessionSource::Exec => CoreSessionSource::Exec,
|
||||
SessionSource::AppServer => CoreSessionSource::Mcp,
|
||||
SessionSource::Custom(source) => CoreSessionSource::Custom(source),
|
||||
SessionSource::SubAgent(sub) => CoreSessionSource::SubAgent(sub),
|
||||
SessionSource::Unknown => CoreSessionSource::Unknown,
|
||||
}
|
||||
@@ -2983,6 +2970,7 @@ pub enum ThreadSourceKind {
|
||||
VsCode,
|
||||
Exec,
|
||||
AppServer,
|
||||
Custom,
|
||||
SubAgent,
|
||||
SubAgentReview,
|
||||
SubAgentCompact,
|
||||
@@ -3142,73 +3130,6 @@ pub struct PluginReadResponse {
|
||||
pub plugin: PluginDetail,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillsRemoteReadParams {
|
||||
#[serde(default)]
|
||||
pub hazelnut_scope: HazelnutScope,
|
||||
#[serde(default)]
|
||||
pub product_surface: ProductSurface,
|
||||
#[serde(default)]
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS, Default)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[ts(rename_all = "kebab-case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum HazelnutScope {
|
||||
#[default]
|
||||
Example,
|
||||
WorkspaceShared,
|
||||
AllShared,
|
||||
Personal,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum ProductSurface {
|
||||
Chatgpt,
|
||||
#[default]
|
||||
Codex,
|
||||
Api,
|
||||
Atlas,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct RemoteSkillSummary {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillsRemoteReadResponse {
|
||||
pub data: Vec<RemoteSkillSummary>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillsRemoteWriteParams {
|
||||
pub hazelnut_id: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillsRemoteWriteResponse {
|
||||
pub id: String,
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(rename_all = "snake_case")]
|
||||
@@ -3311,9 +3232,17 @@ pub struct SkillsListEntry {
|
||||
pub struct PluginMarketplaceEntry {
|
||||
pub name: String,
|
||||
pub path: AbsolutePathBuf,
|
||||
pub interface: Option<MarketplaceInterface>,
|
||||
pub plugins: Vec<PluginSummary>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct MarketplaceInterface {
|
||||
pub display_name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum PluginInstallPolicy {
|
||||
@@ -3430,6 +3359,9 @@ pub struct SkillsConfigWriteResponse {
|
||||
pub struct PluginInstallParams {
|
||||
pub marketplace_path: AbsolutePathBuf,
|
||||
pub plugin_name: String,
|
||||
/// When true, apply the remote plugin change before the local install flow.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub force_remote_sync: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
@@ -3445,6 +3377,9 @@ pub struct PluginInstallResponse {
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginUninstallParams {
|
||||
pub plugin_id: String,
|
||||
/// When true, apply the remote plugin change before the local uninstall flow.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub force_remote_sync: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
@@ -3655,6 +3590,44 @@ pub struct Turn {
|
||||
pub error: Option<TurnError>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct MemoryCitation {
|
||||
pub entries: Vec<MemoryCitationEntry>,
|
||||
pub thread_ids: Vec<String>,
|
||||
}
|
||||
|
||||
impl From<CoreMemoryCitation> for MemoryCitation {
|
||||
fn from(value: CoreMemoryCitation) -> Self {
|
||||
Self {
|
||||
entries: value.entries.into_iter().map(Into::into).collect(),
|
||||
thread_ids: value.rollout_ids,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct MemoryCitationEntry {
|
||||
pub path: String,
|
||||
pub line_start: u32,
|
||||
pub line_end: u32,
|
||||
pub note: String,
|
||||
}
|
||||
|
||||
impl From<CoreMemoryCitationEntry> for MemoryCitationEntry {
|
||||
fn from(value: CoreMemoryCitationEntry) -> Self {
|
||||
Self {
|
||||
path: value.path,
|
||||
line_start: value.line_start,
|
||||
line_end: value.line_end,
|
||||
note: value.note,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, Error)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
@@ -3687,6 +3660,7 @@ pub struct ThreadRealtimeAudioChunk {
|
||||
pub sample_rate: u32,
|
||||
pub num_channels: u16,
|
||||
pub samples_per_channel: Option<u32>,
|
||||
pub item_id: Option<String>,
|
||||
}
|
||||
|
||||
impl From<CoreRealtimeAudioFrame> for ThreadRealtimeAudioChunk {
|
||||
@@ -3696,12 +3670,14 @@ impl From<CoreRealtimeAudioFrame> for ThreadRealtimeAudioChunk {
|
||||
sample_rate,
|
||||
num_channels,
|
||||
samples_per_channel,
|
||||
item_id,
|
||||
} = value;
|
||||
Self {
|
||||
data,
|
||||
sample_rate,
|
||||
num_channels,
|
||||
samples_per_channel,
|
||||
item_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3713,12 +3689,14 @@ impl From<ThreadRealtimeAudioChunk> for CoreRealtimeAudioFrame {
|
||||
sample_rate,
|
||||
num_channels,
|
||||
samples_per_channel,
|
||||
item_id,
|
||||
} = value;
|
||||
Self {
|
||||
data,
|
||||
sample_rate,
|
||||
num_channels,
|
||||
samples_per_channel,
|
||||
item_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3791,6 +3769,7 @@ pub struct ThreadRealtimeStopResponse {}
|
||||
pub struct ThreadRealtimeStartedNotification {
|
||||
pub thread_id: String,
|
||||
pub session_id: Option<String>,
|
||||
pub version: RealtimeConversationVersion,
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - raw non-audio thread realtime item emitted by the backend.
|
||||
@@ -4149,6 +4128,8 @@ pub enum ThreadItem {
|
||||
text: String,
|
||||
#[serde(default)]
|
||||
phase: Option<MessagePhase>,
|
||||
#[serde(default)]
|
||||
memory_citation: Option<MemoryCitation>,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
@@ -4398,6 +4379,7 @@ impl From<CoreTurnItem> for ThreadItem {
|
||||
id: agent.id,
|
||||
text,
|
||||
phase: agent.phase,
|
||||
memory_citation: agent.memory_citation.map(Into::into),
|
||||
}
|
||||
}
|
||||
CoreTurnItem::Plan(plan) => ThreadItem::Plan {
|
||||
@@ -4542,6 +4524,7 @@ pub enum CollabAgentToolCallStatus {
|
||||
pub enum CollabAgentStatus {
|
||||
PendingInit,
|
||||
Running,
|
||||
Interrupted,
|
||||
Completed,
|
||||
Errored,
|
||||
Shutdown,
|
||||
@@ -4567,6 +4550,10 @@ impl From<CoreAgentStatus> for CollabAgentState {
|
||||
status: CollabAgentStatus::Running,
|
||||
message: None,
|
||||
},
|
||||
CoreAgentStatus::Interrupted => Self {
|
||||
status: CollabAgentStatus::Interrupted,
|
||||
message: None,
|
||||
},
|
||||
CoreAgentStatus::Completed(message) => Self {
|
||||
status: CollabAgentStatus::Completed,
|
||||
message,
|
||||
@@ -5607,7 +5594,7 @@ pub struct PermissionsRequestApprovalParams {
|
||||
pub turn_id: String,
|
||||
pub item_id: String,
|
||||
pub reason: Option<String>,
|
||||
pub permissions: AdditionalPermissionProfile,
|
||||
pub permissions: RequestPermissionProfile,
|
||||
}
|
||||
|
||||
v2_enum_from_core!(
|
||||
@@ -5886,6 +5873,17 @@ mod tests {
|
||||
absolute_path("readable")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collab_agent_state_maps_interrupted_status() {
|
||||
assert_eq!(
|
||||
CollabAgentState::from(CoreAgentStatus::Interrupted),
|
||||
CollabAgentState {
|
||||
status: CollabAgentStatus::Interrupted,
|
||||
message: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn command_execution_request_approval_rejects_relative_additional_permission_paths() {
|
||||
let err = serde_json::from_value::<CommandExecutionRequestApprovalParams>(json!({
|
||||
@@ -6034,192 +6032,164 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn permissions_request_approval_response_accepts_partial_macos_grants() {
|
||||
let cases = vec![
|
||||
(json!({}), Some(GrantedMacOsPermissions::default()), None),
|
||||
(
|
||||
json!({
|
||||
"preferences": "read_only",
|
||||
}),
|
||||
Some(GrantedMacOsPermissions {
|
||||
preferences: Some(CoreMacOsPreferencesPermission::ReadOnly),
|
||||
..Default::default()
|
||||
}),
|
||||
Some(CoreMacOsSeatbeltProfileExtensions {
|
||||
macos_preferences: CoreMacOsPreferencesPermission::ReadOnly,
|
||||
macos_automation: CoreMacOsAutomationPermission::None,
|
||||
macos_launch_services: false,
|
||||
macos_accessibility: false,
|
||||
macos_calendar: false,
|
||||
macos_reminders: false,
|
||||
macos_contacts: CoreMacOsContactsPermission::None,
|
||||
}),
|
||||
),
|
||||
(
|
||||
json!({
|
||||
"automations": {
|
||||
"bundle_ids": ["com.apple.Notes"],
|
||||
},
|
||||
}),
|
||||
Some(GrantedMacOsPermissions {
|
||||
automations: Some(CoreMacOsAutomationPermission::BundleIds(vec![
|
||||
"com.apple.Notes".to_string(),
|
||||
])),
|
||||
..Default::default()
|
||||
}),
|
||||
Some(CoreMacOsSeatbeltProfileExtensions {
|
||||
macos_preferences: CoreMacOsPreferencesPermission::None,
|
||||
macos_automation: CoreMacOsAutomationPermission::BundleIds(vec![
|
||||
"com.apple.Notes".to_string(),
|
||||
]),
|
||||
macos_launch_services: false,
|
||||
macos_accessibility: false,
|
||||
macos_calendar: false,
|
||||
macos_reminders: false,
|
||||
macos_contacts: CoreMacOsContactsPermission::None,
|
||||
}),
|
||||
),
|
||||
(
|
||||
json!({
|
||||
"launchServices": true,
|
||||
}),
|
||||
Some(GrantedMacOsPermissions {
|
||||
launch_services: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
Some(CoreMacOsSeatbeltProfileExtensions {
|
||||
macos_preferences: CoreMacOsPreferencesPermission::None,
|
||||
macos_automation: CoreMacOsAutomationPermission::None,
|
||||
macos_launch_services: true,
|
||||
macos_accessibility: false,
|
||||
macos_calendar: false,
|
||||
macos_reminders: false,
|
||||
macos_contacts: CoreMacOsContactsPermission::None,
|
||||
}),
|
||||
),
|
||||
(
|
||||
json!({
|
||||
"accessibility": true,
|
||||
}),
|
||||
Some(GrantedMacOsPermissions {
|
||||
accessibility: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
Some(CoreMacOsSeatbeltProfileExtensions {
|
||||
macos_preferences: CoreMacOsPreferencesPermission::None,
|
||||
macos_automation: CoreMacOsAutomationPermission::None,
|
||||
macos_launch_services: false,
|
||||
macos_accessibility: true,
|
||||
macos_calendar: false,
|
||||
macos_reminders: false,
|
||||
macos_contacts: CoreMacOsContactsPermission::None,
|
||||
}),
|
||||
),
|
||||
(
|
||||
json!({
|
||||
"calendar": true,
|
||||
}),
|
||||
Some(GrantedMacOsPermissions {
|
||||
calendar: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
Some(CoreMacOsSeatbeltProfileExtensions {
|
||||
macos_preferences: CoreMacOsPreferencesPermission::None,
|
||||
macos_automation: CoreMacOsAutomationPermission::None,
|
||||
macos_launch_services: false,
|
||||
macos_accessibility: false,
|
||||
macos_calendar: true,
|
||||
macos_reminders: false,
|
||||
macos_contacts: CoreMacOsContactsPermission::None,
|
||||
}),
|
||||
),
|
||||
(
|
||||
json!({
|
||||
"reminders": true,
|
||||
}),
|
||||
Some(GrantedMacOsPermissions {
|
||||
reminders: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
Some(CoreMacOsSeatbeltProfileExtensions {
|
||||
macos_preferences: CoreMacOsPreferencesPermission::None,
|
||||
macos_automation: CoreMacOsAutomationPermission::None,
|
||||
macos_launch_services: false,
|
||||
macos_accessibility: false,
|
||||
macos_calendar: false,
|
||||
macos_reminders: true,
|
||||
macos_contacts: CoreMacOsContactsPermission::None,
|
||||
}),
|
||||
),
|
||||
(
|
||||
json!({
|
||||
"contacts": "read_only",
|
||||
}),
|
||||
Some(GrantedMacOsPermissions {
|
||||
contacts: Some(CoreMacOsContactsPermission::ReadOnly),
|
||||
..Default::default()
|
||||
}),
|
||||
Some(CoreMacOsSeatbeltProfileExtensions {
|
||||
macos_preferences: CoreMacOsPreferencesPermission::None,
|
||||
macos_automation: CoreMacOsAutomationPermission::None,
|
||||
macos_launch_services: false,
|
||||
macos_accessibility: false,
|
||||
macos_calendar: false,
|
||||
macos_reminders: false,
|
||||
macos_contacts: CoreMacOsContactsPermission::ReadOnly,
|
||||
}),
|
||||
),
|
||||
];
|
||||
|
||||
for (macos_json, expected_granted_macos, expected_core_macos) in cases {
|
||||
let response = serde_json::from_value::<PermissionsRequestApprovalResponse>(json!({
|
||||
"permissions": {
|
||||
"macos": macos_json,
|
||||
fn permissions_request_approval_uses_request_permission_profile() {
|
||||
let read_only_path = if cfg!(windows) {
|
||||
r"C:\tmp\read-only"
|
||||
} else {
|
||||
"/tmp/read-only"
|
||||
};
|
||||
let read_write_path = if cfg!(windows) {
|
||||
r"C:\tmp\read-write"
|
||||
} else {
|
||||
"/tmp/read-write"
|
||||
};
|
||||
let params = serde_json::from_value::<PermissionsRequestApprovalParams>(json!({
|
||||
"threadId": "thr_123",
|
||||
"turnId": "turn_123",
|
||||
"itemId": "call_123",
|
||||
"reason": "Select a workspace root",
|
||||
"permissions": {
|
||||
"network": {
|
||||
"enabled": true,
|
||||
},
|
||||
}))
|
||||
.expect("partial macos permissions response should deserialize");
|
||||
"fileSystem": {
|
||||
"read": [read_only_path],
|
||||
"write": [read_write_path],
|
||||
},
|
||||
},
|
||||
}))
|
||||
.expect("permissions request should deserialize");
|
||||
|
||||
assert_eq!(
|
||||
response.permissions,
|
||||
GrantedPermissionProfile {
|
||||
macos: expected_granted_macos,
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
params.permissions,
|
||||
RequestPermissionProfile {
|
||||
network: Some(AdditionalNetworkPermissions {
|
||||
enabled: Some(true),
|
||||
}),
|
||||
file_system: Some(AdditionalFileSystemPermissions {
|
||||
read: Some(vec![
|
||||
AbsolutePathBuf::try_from(PathBuf::from(read_only_path))
|
||||
.expect("path must be absolute"),
|
||||
]),
|
||||
write: Some(vec![
|
||||
AbsolutePathBuf::try_from(PathBuf::from(read_write_path))
|
||||
.expect("path must be absolute"),
|
||||
]),
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
CorePermissionProfile::from(response.permissions),
|
||||
CorePermissionProfile {
|
||||
macos: expected_core_macos,
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
CoreRequestPermissionProfile::from(params.permissions),
|
||||
CoreRequestPermissionProfile {
|
||||
network: Some(CoreNetworkPermissions {
|
||||
enabled: Some(true),
|
||||
}),
|
||||
file_system: Some(CoreFileSystemPermissions {
|
||||
read: Some(vec![
|
||||
AbsolutePathBuf::try_from(PathBuf::from(read_only_path))
|
||||
.expect("path must be absolute"),
|
||||
]),
|
||||
write: Some(vec![
|
||||
AbsolutePathBuf::try_from(PathBuf::from(read_write_path))
|
||||
.expect("path must be absolute"),
|
||||
]),
|
||||
}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn permissions_request_approval_response_omits_ungranted_macos_keys_when_serialized() {
|
||||
let response = PermissionsRequestApprovalResponse {
|
||||
permissions: GrantedPermissionProfile {
|
||||
macos: Some(GrantedMacOsPermissions {
|
||||
accessibility: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
fn permissions_request_approval_rejects_macos_permissions() {
|
||||
let err = serde_json::from_value::<PermissionsRequestApprovalParams>(json!({
|
||||
"threadId": "thr_123",
|
||||
"turnId": "turn_123",
|
||||
"itemId": "call_123",
|
||||
"reason": "Select a workspace root",
|
||||
"permissions": {
|
||||
"network": null,
|
||||
"fileSystem": null,
|
||||
"macos": {
|
||||
"preferences": "read_only",
|
||||
"automations": "none",
|
||||
"launchServices": false,
|
||||
"accessibility": false,
|
||||
"calendar": false,
|
||||
"reminders": false,
|
||||
"contacts": "none",
|
||||
},
|
||||
},
|
||||
scope: PermissionGrantScope::Turn,
|
||||
}))
|
||||
.expect_err("permissions request should reject macos permissions");
|
||||
|
||||
assert!(
|
||||
err.to_string().contains("unknown field `macos`"),
|
||||
"unexpected error: {err}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn permissions_request_approval_response_uses_granted_permission_profile_without_macos() {
|
||||
let read_only_path = if cfg!(windows) {
|
||||
r"C:\tmp\read-only"
|
||||
} else {
|
||||
"/tmp/read-only"
|
||||
};
|
||||
let read_write_path = if cfg!(windows) {
|
||||
r"C:\tmp\read-write"
|
||||
} else {
|
||||
"/tmp/read-write"
|
||||
};
|
||||
let response = serde_json::from_value::<PermissionsRequestApprovalResponse>(json!({
|
||||
"permissions": {
|
||||
"network": {
|
||||
"enabled": true,
|
||||
},
|
||||
"fileSystem": {
|
||||
"read": [read_only_path],
|
||||
"write": [read_write_path],
|
||||
},
|
||||
},
|
||||
}))
|
||||
.expect("permissions response should deserialize");
|
||||
|
||||
assert_eq!(
|
||||
serde_json::to_value(response).expect("response should serialize"),
|
||||
json!({
|
||||
"permissions": {
|
||||
"macos": {
|
||||
"accessibility": true,
|
||||
},
|
||||
},
|
||||
"scope": "turn",
|
||||
})
|
||||
response.permissions,
|
||||
GrantedPermissionProfile {
|
||||
network: Some(AdditionalNetworkPermissions {
|
||||
enabled: Some(true),
|
||||
}),
|
||||
file_system: Some(AdditionalFileSystemPermissions {
|
||||
read: Some(vec![
|
||||
AbsolutePathBuf::try_from(PathBuf::from(read_only_path))
|
||||
.expect("path must be absolute"),
|
||||
]),
|
||||
write: Some(vec![
|
||||
AbsolutePathBuf::try_from(PathBuf::from(read_write_path))
|
||||
.expect("path must be absolute"),
|
||||
]),
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
CorePermissionProfile::from(response.permissions),
|
||||
CorePermissionProfile {
|
||||
network: Some(CoreNetworkPermissions {
|
||||
enabled: Some(true),
|
||||
}),
|
||||
file_system: Some(CoreFileSystemPermissions {
|
||||
read: Some(vec![
|
||||
AbsolutePathBuf::try_from(PathBuf::from(read_only_path))
|
||||
.expect("path must be absolute"),
|
||||
]),
|
||||
write: Some(vec![
|
||||
AbsolutePathBuf::try_from(PathBuf::from(read_write_path))
|
||||
.expect("path must be absolute"),
|
||||
]),
|
||||
}),
|
||||
macos: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7486,6 +7456,7 @@ mod tests {
|
||||
},
|
||||
],
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
@@ -7494,6 +7465,7 @@ mod tests {
|
||||
id: "agent-1".to_string(),
|
||||
text: "Hello world".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -7503,6 +7475,15 @@ mod tests {
|
||||
text: "final".to_string(),
|
||||
}],
|
||||
phase: Some(MessagePhase::FinalAnswer),
|
||||
memory_citation: Some(CoreMemoryCitation {
|
||||
entries: vec![CoreMemoryCitationEntry {
|
||||
path: "MEMORY.md".to_string(),
|
||||
line_start: 1,
|
||||
line_end: 2,
|
||||
note: "summary".to_string(),
|
||||
}],
|
||||
rollout_ids: vec!["rollout-1".to_string()],
|
||||
}),
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
@@ -7511,6 +7492,15 @@ mod tests {
|
||||
id: "agent-2".to_string(),
|
||||
text: "final".to_string(),
|
||||
phase: Some(MessagePhase::FinalAnswer),
|
||||
memory_citation: Some(MemoryCitation {
|
||||
entries: vec![MemoryCitationEntry {
|
||||
path: "MEMORY.md".to_string(),
|
||||
line_start: 1,
|
||||
line_end: 2,
|
||||
note: "summary".to_string(),
|
||||
}],
|
||||
thread_ids: vec!["rollout-1".to_string()],
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
@@ -7617,6 +7607,69 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plugin_install_params_serialization_uses_force_remote_sync() {
|
||||
let marketplace_path = if cfg!(windows) {
|
||||
r"C:\plugins\marketplace.json"
|
||||
} else {
|
||||
"/plugins/marketplace.json"
|
||||
};
|
||||
let marketplace_path = AbsolutePathBuf::try_from(PathBuf::from(marketplace_path)).unwrap();
|
||||
let marketplace_path_json = marketplace_path.as_path().display().to_string();
|
||||
assert_eq!(
|
||||
serde_json::to_value(PluginInstallParams {
|
||||
marketplace_path: marketplace_path.clone(),
|
||||
plugin_name: "gmail".to_string(),
|
||||
force_remote_sync: false,
|
||||
})
|
||||
.unwrap(),
|
||||
json!({
|
||||
"marketplacePath": marketplace_path_json,
|
||||
"pluginName": "gmail",
|
||||
}),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
serde_json::to_value(PluginInstallParams {
|
||||
marketplace_path,
|
||||
plugin_name: "gmail".to_string(),
|
||||
force_remote_sync: true,
|
||||
})
|
||||
.unwrap(),
|
||||
json!({
|
||||
"marketplacePath": marketplace_path_json,
|
||||
"pluginName": "gmail",
|
||||
"forceRemoteSync": true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plugin_uninstall_params_serialization_uses_force_remote_sync() {
|
||||
assert_eq!(
|
||||
serde_json::to_value(PluginUninstallParams {
|
||||
plugin_id: "gmail@openai-curated".to_string(),
|
||||
force_remote_sync: false,
|
||||
})
|
||||
.unwrap(),
|
||||
json!({
|
||||
"pluginId": "gmail@openai-curated",
|
||||
}),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
serde_json::to_value(PluginUninstallParams {
|
||||
plugin_id: "gmail@openai-curated".to_string(),
|
||||
force_remote_sync: true,
|
||||
})
|
||||
.unwrap(),
|
||||
json!({
|
||||
"pluginId": "gmail@openai-curated",
|
||||
"forceRemoteSync": true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn codex_error_info_serializes_http_status_code_in_camel_case() {
|
||||
let value = CodexErrorInfo::ResponseTooManyFailedAttempts {
|
||||
|
||||
@@ -657,7 +657,7 @@ pub async fn send_message_v2(
|
||||
&endpoint,
|
||||
config_overrides,
|
||||
user_message,
|
||||
true,
|
||||
/*experimental_api*/ true,
|
||||
dynamic_tools,
|
||||
)
|
||||
.await
|
||||
@@ -1510,7 +1510,7 @@ impl CodexClient {
|
||||
}
|
||||
|
||||
fn initialize(&mut self) -> Result<InitializeResponse> {
|
||||
self.initialize_with_experimental_api(true)
|
||||
self.initialize_with_experimental_api(/*experimental_api*/ true)
|
||||
}
|
||||
|
||||
fn initialize_with_experimental_api(
|
||||
|
||||
@@ -32,6 +32,7 @@ axum = { workspace = true, default-features = false, features = [
|
||||
codex-arg0 = { workspace = true }
|
||||
codex-cloud-requirements = { workspace = true }
|
||||
codex-core = { workspace = true }
|
||||
codex-environment = { workspace = true }
|
||||
codex-otel = { workspace = true }
|
||||
codex-shell-command = { workspace = true }
|
||||
codex-utils-cli = { workspace = true }
|
||||
@@ -68,7 +69,6 @@ tokio-tungstenite = { workspace = true }
|
||||
tracing = { workspace = true, features = ["log"] }
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter", "fmt", "json"] }
|
||||
uuid = { workspace = true, features = ["serde", "v7"] }
|
||||
walkdir = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
app_test_support = { workspace = true }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user