mirror of
https://github.com/openai/codex.git
synced 2026-05-14 08:12:36 +00:00
Compare commits
81 Commits
xli-codex/
...
jif/hello-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee94382ba5 | ||
|
|
762c8ae093 | ||
|
|
1378f42e04 | ||
|
|
aa9bb90611 | ||
|
|
1f2badfde4 | ||
|
|
27953de5b9 | ||
|
|
2260be0983 | ||
|
|
7dd7ddb053 | ||
|
|
22068b02b6 | ||
|
|
4892ea4e53 | ||
|
|
cffcb59f5b | ||
|
|
ee1b490c0e | ||
|
|
19dc3d202f | ||
|
|
a7b6245e52 | ||
|
|
1af814fb51 | ||
|
|
f7e8ff8e50 | ||
|
|
b2268999fe | ||
|
|
40e282849c | ||
|
|
898f5bfeaa | ||
|
|
a8488fec5e | ||
|
|
5bc33fe31f | ||
|
|
05cd5c313e | ||
|
|
001363188a | ||
|
|
e394625ea2 | ||
|
|
5a4b2702f2 | ||
|
|
103dc2b6ae | ||
|
|
527d52df03 | ||
|
|
11106016ff | ||
|
|
9417cf9696 | ||
|
|
d5eea229cc | ||
|
|
8f5d68f9d2 | ||
|
|
123e78b97b | ||
|
|
fbdbc6b2fe | ||
|
|
21295f47e2 | ||
|
|
b9c50a53d7 | ||
|
|
d5f0b6d63a | ||
|
|
63a27ad6c6 | ||
|
|
f9063045e1 | ||
|
|
346070a424 | ||
|
|
6b7d6cafa0 | ||
|
|
f32c496144 | ||
|
|
712305be47 | ||
|
|
123ec8b035 | ||
|
|
e97610cf3b | ||
|
|
f2f5d6f6c7 | ||
|
|
ab43db44a2 | ||
|
|
0e821b380a | ||
|
|
2070d5bfd3 | ||
|
|
2004173cd7 | ||
|
|
be1d3cff93 | ||
|
|
ebd9ec05b4 | ||
|
|
5ecff05196 | ||
|
|
ca257b6ce5 | ||
|
|
8f3bb355f4 | ||
|
|
5d6f23a27b | ||
|
|
cc84e6bc6d | ||
|
|
06e5dfa4dd | ||
|
|
fe24a180ab | ||
|
|
b5e965e1d7 | ||
|
|
a98623511b | ||
|
|
f9a907aebe | ||
|
|
22326e263c | ||
|
|
9766d3d51c | ||
|
|
41505bcea2 | ||
|
|
9f06d171e2 | ||
|
|
8ef31894dc | ||
|
|
5119680f85 | ||
|
|
b3d4f1a9f0 | ||
|
|
94db03d5af | ||
|
|
136e442e95 | ||
|
|
024118625e | ||
|
|
a736cb55a2 | ||
|
|
db22c91e61 | ||
|
|
794c240f25 | ||
|
|
2c1a361a2e | ||
|
|
3ec18a2c0a | ||
|
|
26f355b67b | ||
|
|
03d3403a41 | ||
|
|
d7de4dd3ac | ||
|
|
332b8b2c74 | ||
|
|
ee02cf26d6 |
16
.github/dotslash-config.json
vendored
16
.github/dotslash-config.json
vendored
@@ -11,11 +11,11 @@
|
||||
"path": "codex"
|
||||
},
|
||||
"linux-x86_64": {
|
||||
"regex": "^codex-x86_64-unknown-linux-musl\\.zst$",
|
||||
"regex": "^codex-x86_64-unknown-linux-musl-bundle\\.tar\\.zst$",
|
||||
"path": "codex"
|
||||
},
|
||||
"linux-aarch64": {
|
||||
"regex": "^codex-aarch64-unknown-linux-musl\\.zst$",
|
||||
"regex": "^codex-aarch64-unknown-linux-musl-bundle\\.tar\\.zst$",
|
||||
"path": "codex"
|
||||
},
|
||||
"windows-x86_64": {
|
||||
@@ -84,6 +84,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"bwrap": {
|
||||
"platforms": {
|
||||
"linux-x86_64": {
|
||||
"regex": "^bwrap-x86_64-unknown-linux-musl\\.zst$",
|
||||
"path": "bwrap"
|
||||
},
|
||||
"linux-aarch64": {
|
||||
"regex": "^bwrap-aarch64-unknown-linux-musl\\.zst$",
|
||||
"path": "bwrap"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codex-command-runner": {
|
||||
"platforms": {
|
||||
"windows-x86_64": {
|
||||
|
||||
16
.github/workflows/bazel.yml
vendored
16
.github/workflows/bazel.yml
vendored
@@ -371,6 +371,22 @@ jobs:
|
||||
-- \
|
||||
"${bazel_targets[@]}"
|
||||
|
||||
- name: Verify Bazel builds bwrap
|
||||
if: runner.os == 'Linux'
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/scripts/run-bazel-ci.sh \
|
||||
--remote-download-toplevel \
|
||||
--print-failed-action-summary \
|
||||
-- \
|
||||
build \
|
||||
--build_metadata=COMMIT_SHA=${GITHUB_SHA} \
|
||||
--build_metadata=TAG_job=verify-bwrap \
|
||||
-- \
|
||||
//codex-rs/bwrap:bwrap
|
||||
|
||||
- name: Upload Bazel execution logs
|
||||
if: always() && !cancelled()
|
||||
continue-on-error: true
|
||||
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -52,10 +52,12 @@ jobs:
|
||||
CODEX_VERSION=0.125.0
|
||||
WORKFLOW_URL="https://github.com/openai/codex/actions/runs/24901475298"
|
||||
OUTPUT_DIR="${RUNNER_TEMP}"
|
||||
# This reused workflow predates the standalone bwrap artifact.
|
||||
python3 ./scripts/stage_npm_packages.py \
|
||||
--release-version "$CODEX_VERSION" \
|
||||
--workflow-url "$WORKFLOW_URL" \
|
||||
--package codex \
|
||||
--allow-missing-native-component bwrap \
|
||||
--output-dir "$OUTPUT_DIR"
|
||||
PACK_OUTPUT="${OUTPUT_DIR}/codex-npm-${CODEX_VERSION}.tgz"
|
||||
echo "pack_output=$PACK_OUTPUT" >> "$GITHUB_OUTPUT"
|
||||
|
||||
39
.github/workflows/rust-release.yml
vendored
39
.github/workflows/rust-release.yml
vendored
@@ -96,7 +96,7 @@ jobs:
|
||||
target: x86_64-unknown-linux-musl
|
||||
bundle: primary
|
||||
artifact_name: x86_64-unknown-linux-musl
|
||||
binaries: "codex codex-responses-api-proxy"
|
||||
binaries: "codex codex-responses-api-proxy bwrap"
|
||||
build_dmg: "false"
|
||||
- runner: ubuntu-24.04
|
||||
target: x86_64-unknown-linux-musl
|
||||
@@ -108,7 +108,7 @@ jobs:
|
||||
target: aarch64-unknown-linux-musl
|
||||
bundle: primary
|
||||
artifact_name: aarch64-unknown-linux-musl
|
||||
binaries: "codex codex-responses-api-proxy"
|
||||
binaries: "codex codex-responses-api-proxy bwrap"
|
||||
build_dmg: "false"
|
||||
- runner: ubuntu-24.04-arm
|
||||
target: aarch64-unknown-linux-musl
|
||||
@@ -255,6 +255,24 @@ jobs:
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
- if: ${{ contains(matrix.target, 'linux') && matrix.bundle == 'primary' }}
|
||||
name: Build bwrap and export digest
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
target="${{ matrix.target }}"
|
||||
cargo build --target "$target" --release --timings --bin bwrap
|
||||
|
||||
bwrap_path="target/${target}/release/bwrap"
|
||||
if [[ ! -f "$bwrap_path" ]]; then
|
||||
echo "bwrap binary ${bwrap_path} not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
digest="$(sha256sum "$bwrap_path" | awk '{print $1}')"
|
||||
echo "CODEX_BWRAP_SHA256=${digest}" >> "$GITHUB_ENV"
|
||||
echo "Built bwrap ${bwrap_path} with sha256:${digest}"
|
||||
|
||||
- name: Cargo build
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -361,6 +379,17 @@ jobs:
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "${{ matrix.target }}" == *linux* && "${{ matrix.bundle }}" == "primary" ]]; then
|
||||
bundle_root="${RUNNER_TEMP}/codex-${{ matrix.target }}-bundle"
|
||||
rm -rf "$bundle_root"
|
||||
mkdir -p "$bundle_root/codex-resources"
|
||||
cp "$dest/codex-${{ matrix.target }}" "$bundle_root/codex"
|
||||
cp "$dest/bwrap-${{ matrix.target }}" "$bundle_root/codex-resources/bwrap"
|
||||
chmod 0755 "$bundle_root/codex" "$bundle_root/codex-resources/bwrap"
|
||||
tar -C "$bundle_root" -cf - codex codex-resources/bwrap |
|
||||
zstd -T0 -19 -o "$dest/codex-${{ matrix.target }}-bundle.tar.zst"
|
||||
fi
|
||||
|
||||
if [[ "${{ matrix.build_dmg }}" == "true" ]]; then
|
||||
cp target/${{ matrix.target }}/release/codex-${{ matrix.target }}.dmg "$dest/codex-${{ matrix.target }}.dmg"
|
||||
fi
|
||||
@@ -384,7 +413,7 @@ jobs:
|
||||
base="$(basename "$f")"
|
||||
# Skip files that are already archives (shouldn't happen, but be
|
||||
# safe).
|
||||
if [[ "$base" == *.tar.gz || "$base" == *.zip || "$base" == *.dmg ]]; then
|
||||
if [[ "$base" == *.tar.gz || "$base" == *.tar.zst || "$base" == *.zip || "$base" == *.dmg ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
@@ -404,8 +433,8 @@ jobs:
|
||||
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
|
||||
with:
|
||||
name: ${{ matrix.artifact_name }}
|
||||
# Upload the per-binary .zst files as well as the new .tar.gz
|
||||
# equivalents we generated in the previous step.
|
||||
# Upload the per-binary .zst files, .tar.gz equivalents, and any
|
||||
# prebuilt archives staged above.
|
||||
path: |
|
||||
codex-rs/dist/${{ matrix.target }}/*
|
||||
|
||||
|
||||
37
.github/workflows/rusty-v8-release.yml
vendored
37
.github/workflows/rusty-v8-release.yml
vendored
@@ -1,20 +1,12 @@
|
||||
name: rusty-v8-release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
description: Optional release tag. Defaults to rusty-v8-v<resolved_v8_version>.
|
||||
required: false
|
||||
type: string
|
||||
publish:
|
||||
description: Publish the staged musl artifacts to a GitHub release.
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
push:
|
||||
tags:
|
||||
- "rusty-v8-v*.*.*"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}::${{ inputs.release_tag || github.run_id }}
|
||||
group: ${{ github.workflow }}::${{ github.ref_name }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
@@ -43,15 +35,17 @@ jobs:
|
||||
- name: Resolve release tag
|
||||
id: release_tag
|
||||
env:
|
||||
RELEASE_TAG_INPUT: ${{ inputs.release_tag }}
|
||||
GITHUB_REF_NAME: ${{ github.ref_name }}
|
||||
V8_VERSION: ${{ steps.v8_version.outputs.version }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
release_tag="${RELEASE_TAG_INPUT}"
|
||||
if [[ -z "${release_tag}" ]]; then
|
||||
release_tag="rusty-v8-v${V8_VERSION}"
|
||||
expected_release_tag="rusty-v8-v${V8_VERSION}"
|
||||
release_tag="${GITHUB_REF_NAME}"
|
||||
if [[ "${release_tag}" != "${expected_release_tag}" ]]; then
|
||||
echo "Tag ${release_tag} does not match resolved v8 crate version ${V8_VERSION}." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "release_tag=${release_tag}" >> "$GITHUB_OUTPUT"
|
||||
@@ -145,7 +139,6 @@ jobs:
|
||||
path: dist/${{ matrix.target }}/*
|
||||
|
||||
publish-release:
|
||||
if: ${{ inputs.publish }}
|
||||
needs:
|
||||
- metadata
|
||||
- build
|
||||
@@ -155,16 +148,6 @@ jobs:
|
||||
actions: read
|
||||
|
||||
steps:
|
||||
- name: Ensure publishing from default branch
|
||||
if: ${{ github.ref_name != github.event.repository.default_branch }}
|
||||
env:
|
||||
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "Publishing is only allowed from ${DEFAULT_BRANCH}; current ref is ${GITHUB_REF_NAME}." >&2
|
||||
exit 1
|
||||
|
||||
- name: Ensure release tag is new
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
|
||||
@@ -69,8 +69,8 @@ PACKAGE_EXPANSIONS: dict[str, list[str]] = {
|
||||
|
||||
PACKAGE_NATIVE_COMPONENTS: dict[str, list[str]] = {
|
||||
"codex": [],
|
||||
"codex-linux-x64": ["codex", "rg"],
|
||||
"codex-linux-arm64": ["codex", "rg"],
|
||||
"codex-linux-x64": ["bwrap", "codex", "rg"],
|
||||
"codex-linux-arm64": ["bwrap", "codex", "rg"],
|
||||
"codex-darwin-x64": ["codex", "rg"],
|
||||
"codex-darwin-arm64": ["codex", "rg"],
|
||||
"codex-win32-x64": ["codex", "rg", "codex-windows-sandbox-setup", "codex-command-runner"],
|
||||
@@ -87,6 +87,7 @@ PACKAGE_TARGET_FILTERS: dict[str, str] = {
|
||||
PACKAGE_CHOICES = tuple(PACKAGE_NATIVE_COMPONENTS)
|
||||
|
||||
COMPONENT_DEST_DIR: dict[str, str] = {
|
||||
"bwrap": "codex-resources",
|
||||
"codex": "codex",
|
||||
"codex-responses-api-proxy": "codex-responses-api-proxy",
|
||||
"codex-windows-sandbox-setup": "codex",
|
||||
@@ -137,6 +138,16 @@ def parse_args() -> argparse.Namespace:
|
||||
type=Path,
|
||||
help="Directory containing pre-installed native binaries to bundle (vendor root).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--allow-missing-native-component",
|
||||
dest="allow_missing_native_components",
|
||||
action="append",
|
||||
default=[],
|
||||
help=(
|
||||
"Native component that may be absent from --vendor-src. Intended for CI "
|
||||
"compatibility with older artifact workflows; releases should not use this."
|
||||
),
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
@@ -177,6 +188,7 @@ def main() -> int:
|
||||
staging_dir,
|
||||
native_components,
|
||||
target_filter={target_filter} if target_filter else None,
|
||||
allow_missing_components=set(args.allow_missing_native_components),
|
||||
)
|
||||
|
||||
if release_version:
|
||||
@@ -365,12 +377,14 @@ def copy_native_binaries(
|
||||
staging_dir: Path,
|
||||
components: list[str],
|
||||
target_filter: set[str] | None = None,
|
||||
allow_missing_components: set[str] | None = None,
|
||||
) -> None:
|
||||
vendor_src = vendor_src.resolve()
|
||||
if not vendor_src.exists():
|
||||
raise RuntimeError(f"Vendor source directory not found: {vendor_src}")
|
||||
|
||||
components_set = {component for component in components if component in COMPONENT_DEST_DIR}
|
||||
allow_missing_components = allow_missing_components or set()
|
||||
if not components_set:
|
||||
return
|
||||
|
||||
@@ -399,6 +413,8 @@ def copy_native_binaries(
|
||||
|
||||
src_component_dir = target_dir / dest_dir_name
|
||||
if not src_component_dir.exists():
|
||||
if component in allow_missing_components:
|
||||
continue
|
||||
raise RuntimeError(
|
||||
f"Missing native component '{component}' in vendor source: {src_component_dir}"
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Install Codex native binaries (Rust CLI plus ripgrep helpers)."""
|
||||
"""Install Codex native binaries (Rust CLI, bwrap, and ripgrep helpers)."""
|
||||
|
||||
import argparse
|
||||
from contextlib import contextmanager
|
||||
@@ -42,8 +42,15 @@ class BinaryComponent:
|
||||
|
||||
|
||||
WINDOWS_TARGETS = tuple(target for target in BINARY_TARGETS if "windows" in target)
|
||||
LINUX_TARGETS = tuple(target for target in BINARY_TARGETS if "linux" in target)
|
||||
|
||||
BINARY_COMPONENTS = {
|
||||
"bwrap": BinaryComponent(
|
||||
artifact_prefix="bwrap",
|
||||
dest_dir="codex-resources",
|
||||
binary_basename="bwrap",
|
||||
targets=LINUX_TARGETS,
|
||||
),
|
||||
"codex": BinaryComponent(
|
||||
artifact_prefix="codex",
|
||||
dest_dir="codex",
|
||||
@@ -135,7 +142,7 @@ def parse_args() -> argparse.Namespace:
|
||||
choices=tuple(list(BINARY_COMPONENTS) + ["rg"]),
|
||||
help=(
|
||||
"Limit installation to the specified components."
|
||||
" May be repeated. Defaults to codex, codex-windows-sandbox-setup,"
|
||||
" May be repeated. Defaults to bwrap, codex, codex-windows-sandbox-setup,"
|
||||
" codex-command-runner, and rg."
|
||||
),
|
||||
)
|
||||
@@ -159,6 +166,7 @@ def main() -> int:
|
||||
vendor_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
components = args.components or [
|
||||
"bwrap",
|
||||
"codex",
|
||||
"codex-windows-sandbox-setup",
|
||||
"codex-command-runner",
|
||||
|
||||
91
codex-rs/Cargo.lock
generated
91
codex-rs/Cargo.lock
generated
@@ -1944,6 +1944,7 @@ dependencies = [
|
||||
"pretty_assertions",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"toml 0.9.11+spec-1.1.0",
|
||||
@@ -2125,6 +2126,26 @@ dependencies = [
|
||||
"serde_with",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-builtin-mcps"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"codex-memories-mcp",
|
||||
"codex-utils-absolute-path",
|
||||
"pretty_assertions",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-bwrap"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-chatgpt"
|
||||
version = "0.0.0"
|
||||
@@ -2411,7 +2432,6 @@ dependencies = [
|
||||
"bm25",
|
||||
"chrono",
|
||||
"clap",
|
||||
"codex-agent-graph-store",
|
||||
"codex-analytics",
|
||||
"codex-api",
|
||||
"codex-app-server-protocol",
|
||||
@@ -2424,12 +2444,14 @@ dependencies = [
|
||||
"codex-core-skills",
|
||||
"codex-exec-server",
|
||||
"codex-execpolicy",
|
||||
"codex-extension-api",
|
||||
"codex-features",
|
||||
"codex-feedback",
|
||||
"codex-git-utils",
|
||||
"codex-hooks",
|
||||
"codex-login",
|
||||
"codex-mcp",
|
||||
"codex-memories",
|
||||
"codex-memories-read",
|
||||
"codex-model-provider",
|
||||
"codex-model-provider-info",
|
||||
@@ -2548,6 +2570,7 @@ dependencies = [
|
||||
"codex-core-skills",
|
||||
"codex-exec-server",
|
||||
"codex-git-utils",
|
||||
"codex-hooks",
|
||||
"codex-login",
|
||||
"codex-model-provider",
|
||||
"codex-otel",
|
||||
@@ -2759,6 +2782,19 @@ dependencies = [
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-extension-api"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-git-attribution",
|
||||
"codex-guardian",
|
||||
"codex-memories",
|
||||
"codex-multi-agent-v2",
|
||||
"codex-tools",
|
||||
"serde_json",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-external-agent-migration"
|
||||
version = "0.0.0"
|
||||
@@ -2837,6 +2873,13 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-git-attribution"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-extension-api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-git-utils"
|
||||
version = "0.0.0"
|
||||
@@ -2861,6 +2904,13 @@ dependencies = [
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-guardian"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-extension-api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-hooks"
|
||||
version = "0.0.0"
|
||||
@@ -2905,7 +2955,6 @@ dependencies = [
|
||||
name = "codex-linux-sandbox"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"clap",
|
||||
"codex-core",
|
||||
"codex-process-hardening",
|
||||
@@ -2915,11 +2964,11 @@ dependencies = [
|
||||
"globset",
|
||||
"landlock",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"pretty_assertions",
|
||||
"seccompiler",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"url",
|
||||
@@ -2989,6 +3038,7 @@ dependencies = [
|
||||
"async-channel",
|
||||
"codex-api",
|
||||
"codex-async-utils",
|
||||
"codex-builtin-mcps",
|
||||
"codex-config",
|
||||
"codex-exec-server",
|
||||
"codex-login",
|
||||
@@ -3044,6 +3094,19 @@ dependencies = [
|
||||
"wiremock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-memories"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-extension-api",
|
||||
"codex-memories-read",
|
||||
"codex-utils-absolute-path",
|
||||
"rmcp",
|
||||
"serde_json",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-memories-mcp"
|
||||
version = "0.0.0"
|
||||
@@ -3110,6 +3173,19 @@ dependencies = [
|
||||
"wiremock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-message-history"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-config",
|
||||
"pretty_assertions",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-model-provider"
|
||||
version = "0.0.0"
|
||||
@@ -3172,6 +3248,13 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-multi-agent-v2"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-extension-api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-network-proxy"
|
||||
version = "0.0.0"
|
||||
@@ -3652,6 +3735,7 @@ dependencies = [
|
||||
"codex-install-context",
|
||||
"codex-login",
|
||||
"codex-mcp",
|
||||
"codex-message-history",
|
||||
"codex-model-provider",
|
||||
"codex-model-provider-info",
|
||||
"codex-models-manager",
|
||||
@@ -4239,6 +4323,7 @@ dependencies = [
|
||||
"reqwest",
|
||||
"serde_json",
|
||||
"shlex",
|
||||
"similar",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
|
||||
@@ -5,6 +5,8 @@ members = [
|
||||
"agent-graph-store",
|
||||
"agent-identity",
|
||||
"backend-client",
|
||||
"builtin-mcps",
|
||||
"bwrap",
|
||||
"ansi-escape",
|
||||
"async-utils",
|
||||
"app-server",
|
||||
@@ -43,6 +45,11 @@ members = [
|
||||
"exec-server",
|
||||
"execpolicy",
|
||||
"execpolicy-legacy",
|
||||
"ext/extension-api",
|
||||
"ext/guardian",
|
||||
"ext/git-attribution",
|
||||
"ext/memories",
|
||||
"ext/multi-agent-v2",
|
||||
"external-agent-migration",
|
||||
"external-agent-sessions",
|
||||
"keyring-store",
|
||||
@@ -137,6 +144,7 @@ codex-apply-patch = { path = "apply-patch" }
|
||||
codex-arg0 = { path = "arg0" }
|
||||
codex-async-utils = { path = "async-utils" }
|
||||
codex-backend-client = { path = "backend-client" }
|
||||
codex-builtin-mcps = { path = "builtin-mcps" }
|
||||
codex-chatgpt = { path = "chatgpt" }
|
||||
codex-cli = { path = "cli" }
|
||||
codex-client = { path = "codex-client" }
|
||||
@@ -156,10 +164,15 @@ codex-exec = { path = "exec" }
|
||||
codex-file-system = { path = "file-system" }
|
||||
codex-exec-server = { path = "exec-server" }
|
||||
codex-execpolicy = { path = "execpolicy" }
|
||||
codex-extension-api = { path = "ext/extension-api" }
|
||||
codex-external-agent-migration = { path = "external-agent-migration" }
|
||||
codex-external-agent-sessions = { path = "external-agent-sessions" }
|
||||
codex-experimental-api-macros = { path = "codex-experimental-api-macros" }
|
||||
codex-features = { path = "features" }
|
||||
codex-guardian = { path = "ext/guardian" }
|
||||
codex-git-attribution = { path = "ext/git-attribution" }
|
||||
codex-memories = { path = "ext/memories" }
|
||||
codex-multi-agent-v2 = { path = "ext/multi-agent-v2" }
|
||||
codex-feedback = { path = "feedback" }
|
||||
codex-install-context = { path = "install-context" }
|
||||
codex-file-search = { path = "file-search" }
|
||||
@@ -169,6 +182,7 @@ codex-keyring-store = { path = "keyring-store" }
|
||||
codex-linux-sandbox = { path = "linux-sandbox" }
|
||||
codex-lmstudio = { path = "lmstudio" }
|
||||
codex-login = { path = "login" }
|
||||
codex-message-history = { path = "message-history" }
|
||||
codex-memories-mcp = { path = "memories/mcp" }
|
||||
codex-memories-read = { path = "memories/read" }
|
||||
codex-memories-write = { path = "memories/write" }
|
||||
|
||||
@@ -12,7 +12,6 @@ use crate::events::CodexPluginUsedEventRequest;
|
||||
use crate::events::CodexRuntimeMetadata;
|
||||
use crate::events::CodexToolItemEventBase;
|
||||
use crate::events::CodexTurnEventRequest;
|
||||
use crate::events::CommandExecutionSource;
|
||||
use crate::events::GuardianApprovalRequestSource;
|
||||
use crate::events::GuardianReviewDecision;
|
||||
use crate::events::GuardianReviewEventParams;
|
||||
@@ -67,8 +66,13 @@ use codex_app_server_protocol::ClientInfo;
|
||||
use codex_app_server_protocol::ClientRequest;
|
||||
use codex_app_server_protocol::ClientResponsePayload;
|
||||
use codex_app_server_protocol::CodexErrorInfo;
|
||||
use codex_app_server_protocol::CommandAction;
|
||||
use codex_app_server_protocol::CommandExecutionSource;
|
||||
use codex_app_server_protocol::CommandExecutionStatus;
|
||||
use codex_app_server_protocol::InitializeCapabilities;
|
||||
use codex_app_server_protocol::InitializeParams;
|
||||
use codex_app_server_protocol::ItemCompletedNotification;
|
||||
use codex_app_server_protocol::ItemStartedNotification;
|
||||
use codex_app_server_protocol::JSONRPCErrorError;
|
||||
use codex_app_server_protocol::NonSteerableTurnKind;
|
||||
use codex_app_server_protocol::RequestId;
|
||||
@@ -78,7 +82,9 @@ use codex_app_server_protocol::SessionSource as AppServerSessionSource;
|
||||
use codex_app_server_protocol::Thread;
|
||||
use codex_app_server_protocol::ThreadArchiveParams;
|
||||
use codex_app_server_protocol::ThreadArchiveResponse;
|
||||
use codex_app_server_protocol::ThreadItem;
|
||||
use codex_app_server_protocol::ThreadResumeResponse;
|
||||
use codex_app_server_protocol::ThreadSource as AppServerThreadSource;
|
||||
use codex_app_server_protocol::ThreadStartResponse;
|
||||
use codex_app_server_protocol::ThreadStatus as AppServerThreadStatus;
|
||||
use codex_app_server_protocol::Turn;
|
||||
@@ -107,6 +113,7 @@ use codex_protocol::protocol::HookSource;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::protocol::SubAgentSource;
|
||||
use codex_protocol::protocol::ThreadSource;
|
||||
use codex_protocol::protocol::TokenUsage;
|
||||
use codex_utils_absolute_path::test_support::PathBufExt;
|
||||
use codex_utils_absolute_path::test_support::test_path_buf;
|
||||
@@ -118,17 +125,15 @@ use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
fn sample_thread(thread_id: &str, ephemeral: bool) -> Thread {
|
||||
sample_thread_with_source(thread_id, ephemeral, AppServerSessionSource::Exec)
|
||||
}
|
||||
|
||||
fn sample_thread_with_source(
|
||||
fn sample_thread_with_metadata(
|
||||
thread_id: &str,
|
||||
ephemeral: bool,
|
||||
source: AppServerSessionSource,
|
||||
thread_source: Option<AppServerThreadSource>,
|
||||
) -> Thread {
|
||||
Thread {
|
||||
id: thread_id.to_string(),
|
||||
session_id: format!("session-{thread_id}"),
|
||||
forked_from_id: None,
|
||||
preview: "first prompt".to_string(),
|
||||
ephemeral,
|
||||
@@ -140,6 +145,7 @@ fn sample_thread_with_source(
|
||||
cwd: test_path_buf("/tmp").abs(),
|
||||
cli_version: "0.0.0".to_string(),
|
||||
source,
|
||||
thread_source,
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
git_info: None,
|
||||
@@ -154,7 +160,12 @@ fn sample_thread_start_response(
|
||||
model: &str,
|
||||
) -> ClientResponsePayload {
|
||||
ClientResponsePayload::ThreadStart(ThreadStartResponse {
|
||||
thread: sample_thread(thread_id, ephemeral),
|
||||
thread: sample_thread_with_metadata(
|
||||
thread_id,
|
||||
ephemeral,
|
||||
AppServerSessionSource::Exec,
|
||||
Some(AppServerThreadSource::User),
|
||||
),
|
||||
model: model.to_string(),
|
||||
model_provider: "openai".to_string(),
|
||||
service_tier: None,
|
||||
@@ -198,6 +209,7 @@ fn sample_thread_resume_response(
|
||||
ephemeral,
|
||||
model,
|
||||
AppServerSessionSource::Exec,
|
||||
Some(AppServerThreadSource::User),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -206,9 +218,10 @@ fn sample_thread_resume_response_with_source(
|
||||
ephemeral: bool,
|
||||
model: &str,
|
||||
source: AppServerSessionSource,
|
||||
thread_source: Option<AppServerThreadSource>,
|
||||
) -> ClientResponsePayload {
|
||||
ClientResponsePayload::ThreadResume(ThreadResumeResponse {
|
||||
thread: sample_thread_with_source(thread_id, ephemeral, source),
|
||||
thread: sample_thread_with_metadata(thread_id, ephemeral, source, thread_source),
|
||||
model: model.to_string(),
|
||||
model_provider: "openai".to_string(),
|
||||
service_tier: None,
|
||||
@@ -590,6 +603,90 @@ async fn ingest_turn_prerequisites(
|
||||
}
|
||||
}
|
||||
|
||||
async fn ingest_tool_review_prerequisites(
|
||||
reducer: &mut AnalyticsReducer,
|
||||
events: &mut Vec<TrackEventRequest>,
|
||||
) {
|
||||
reducer
|
||||
.ingest(sample_initialize_fact(/*connection_id*/ 7), events)
|
||||
.await;
|
||||
reducer
|
||||
.ingest(
|
||||
AnalyticsFact::ClientResponse {
|
||||
connection_id: 7,
|
||||
request_id: RequestId::Integer(1),
|
||||
response: Box::new(sample_thread_start_response(
|
||||
"thread-1", /*ephemeral*/ false, "gpt-5",
|
||||
)),
|
||||
},
|
||||
events,
|
||||
)
|
||||
.await;
|
||||
events.clear();
|
||||
}
|
||||
|
||||
fn sample_initialize_fact(connection_id: u64) -> AnalyticsFact {
|
||||
AnalyticsFact::Initialize {
|
||||
connection_id,
|
||||
params: InitializeParams {
|
||||
client_info: ClientInfo {
|
||||
name: "codex-tui".to_string(),
|
||||
title: None,
|
||||
version: "1.0.0".to_string(),
|
||||
},
|
||||
capabilities: Some(InitializeCapabilities {
|
||||
experimental_api: false,
|
||||
opt_out_notification_methods: None,
|
||||
}),
|
||||
},
|
||||
product_client_id: DEFAULT_ORIGINATOR.to_string(),
|
||||
runtime: CodexRuntimeMetadata {
|
||||
codex_rs_version: "0.99.0".to_string(),
|
||||
runtime_os: "linux".to_string(),
|
||||
runtime_os_version: "24.04".to_string(),
|
||||
runtime_arch: "x86_64".to_string(),
|
||||
},
|
||||
rpc_transport: AppServerRpcTransport::Websocket,
|
||||
}
|
||||
}
|
||||
|
||||
fn sample_command_execution_item(
|
||||
status: CommandExecutionStatus,
|
||||
exit_code: Option<i32>,
|
||||
duration_ms: Option<i64>,
|
||||
) -> ThreadItem {
|
||||
ThreadItem::CommandExecution {
|
||||
id: "item-1".to_string(),
|
||||
command: "echo hi".to_string(),
|
||||
cwd: test_path_buf("/tmp").abs(),
|
||||
process_id: Some("pid-1".to_string()),
|
||||
source: CommandExecutionSource::Agent,
|
||||
status,
|
||||
command_actions: Vec::new(),
|
||||
aggregated_output: None,
|
||||
exit_code,
|
||||
duration_ms,
|
||||
}
|
||||
}
|
||||
|
||||
fn sample_command_execution_item_with_actions(
|
||||
status: CommandExecutionStatus,
|
||||
exit_code: Option<i32>,
|
||||
duration_ms: Option<i64>,
|
||||
command_actions: Vec<CommandAction>,
|
||||
) -> ThreadItem {
|
||||
let mut item = sample_command_execution_item(status, exit_code, duration_ms);
|
||||
let ThreadItem::CommandExecution {
|
||||
command_actions: item_command_actions,
|
||||
..
|
||||
} = &mut item
|
||||
else {
|
||||
unreachable!("sample command execution item should be CommandExecution");
|
||||
};
|
||||
*item_command_actions = command_actions;
|
||||
item
|
||||
}
|
||||
|
||||
fn expected_absolute_path(path: &PathBuf) -> String {
|
||||
std::fs::canonicalize(path)
|
||||
.unwrap_or_else(|_| path.to_path_buf())
|
||||
@@ -753,7 +850,7 @@ fn compaction_event_serializes_expected_shape() {
|
||||
},
|
||||
sample_app_server_client_metadata(),
|
||||
sample_runtime_metadata(),
|
||||
Some("user"),
|
||||
Some(ThreadSource::User),
|
||||
/*subagent_source*/ None,
|
||||
/*parent_thread_id*/ None,
|
||||
),
|
||||
@@ -852,7 +949,7 @@ fn thread_initialized_event_serializes_expected_shape() {
|
||||
},
|
||||
model: "gpt-5".to_string(),
|
||||
ephemeral: true,
|
||||
thread_source: Some("user"),
|
||||
thread_source: Some(ThreadSource::User),
|
||||
initialization_mode: ThreadInitializationMode::New,
|
||||
subagent_source: None,
|
||||
parent_thread_id: None,
|
||||
@@ -922,6 +1019,7 @@ fn command_execution_event_serializes_expected_shape() {
|
||||
started_at_ms: 123_000,
|
||||
completed_at_ms: 125_000,
|
||||
duration_ms: Some(2000),
|
||||
execution_duration_ms: Some(1900),
|
||||
review_count: 0,
|
||||
guardian_review_count: 0,
|
||||
user_review_count: 0,
|
||||
@@ -970,6 +1068,7 @@ fn command_execution_event_serializes_expected_shape() {
|
||||
"started_at_ms": 123000,
|
||||
"completed_at_ms": 125000,
|
||||
"duration_ms": 2000,
|
||||
"execution_duration_ms": 1900,
|
||||
"review_count": 0,
|
||||
"guardian_review_count": 0,
|
||||
"user_review_count": 0,
|
||||
@@ -1196,6 +1295,7 @@ async fn compaction_event_ingests_custom_fact() {
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
}),
|
||||
Some(AppServerThreadSource::Subagent),
|
||||
)),
|
||||
},
|
||||
&mut events,
|
||||
@@ -1395,6 +1495,114 @@ async fn guardian_review_event_ingests_custom_fact_with_optional_target_item() {
|
||||
assert_eq!(payload[0]["event_params"]["review_timeout_ms"], 90_000);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn item_lifecycle_notifications_publish_command_execution_event() {
|
||||
let mut reducer = AnalyticsReducer::default();
|
||||
let mut events = Vec::new();
|
||||
|
||||
ingest_tool_review_prerequisites(&mut reducer, &mut events).await;
|
||||
reducer
|
||||
.ingest(
|
||||
AnalyticsFact::Notification(Box::new(ServerNotification::ItemStarted(
|
||||
ItemStartedNotification {
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
started_at_ms: 1_000,
|
||||
item: sample_command_execution_item(
|
||||
CommandExecutionStatus::InProgress,
|
||||
/*exit_code*/ None,
|
||||
/*duration_ms*/ None,
|
||||
),
|
||||
},
|
||||
))),
|
||||
&mut events,
|
||||
)
|
||||
.await;
|
||||
assert!(
|
||||
events.is_empty(),
|
||||
"tool item event should emit on completion"
|
||||
);
|
||||
|
||||
reducer
|
||||
.ingest(
|
||||
AnalyticsFact::Notification(Box::new(ServerNotification::ItemCompleted(
|
||||
ItemCompletedNotification {
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 1_045,
|
||||
item: sample_command_execution_item_with_actions(
|
||||
CommandExecutionStatus::Completed,
|
||||
Some(0),
|
||||
Some(42),
|
||||
vec![
|
||||
CommandAction::Read {
|
||||
command: "cat README.md".to_string(),
|
||||
name: "README.md".to_string(),
|
||||
path: test_path_buf("/tmp/README.md").abs(),
|
||||
},
|
||||
CommandAction::ListFiles {
|
||||
command: "ls".to_string(),
|
||||
path: None,
|
||||
},
|
||||
CommandAction::Search {
|
||||
command: "rg TODO".to_string(),
|
||||
query: Some("TODO".to_string()),
|
||||
path: None,
|
||||
},
|
||||
CommandAction::Unknown {
|
||||
command: "cargo test".to_string(),
|
||||
},
|
||||
],
|
||||
),
|
||||
},
|
||||
))),
|
||||
&mut events,
|
||||
)
|
||||
.await;
|
||||
|
||||
let payload = serde_json::to_value(&events).expect("serialize events");
|
||||
assert_eq!(payload.as_array().expect("events array").len(), 1);
|
||||
assert_eq!(payload[0]["event_type"], "codex_command_execution_event");
|
||||
assert_eq!(payload[0]["event_params"]["thread_id"], "thread-1");
|
||||
assert_eq!(payload[0]["event_params"]["turn_id"], "turn-1");
|
||||
assert_eq!(payload[0]["event_params"]["item_id"], "item-1");
|
||||
assert_eq!(payload[0]["event_params"]["tool_name"], "shell");
|
||||
assert_eq!(
|
||||
payload[0]["event_params"]["command_execution_source"],
|
||||
"agent"
|
||||
);
|
||||
assert_eq!(payload[0]["event_params"]["terminal_status"], "completed");
|
||||
assert_eq!(
|
||||
payload[0]["event_params"]["final_approval_outcome"],
|
||||
"unknown"
|
||||
);
|
||||
assert_eq!(
|
||||
payload[0]["event_params"]["failure_kind"],
|
||||
serde_json::Value::Null
|
||||
);
|
||||
assert_eq!(payload[0]["event_params"]["exit_code"], 0);
|
||||
assert_eq!(payload[0]["event_params"]["command_total_action_count"], 4);
|
||||
assert_eq!(payload[0]["event_params"]["command_read_action_count"], 1);
|
||||
assert_eq!(
|
||||
payload[0]["event_params"]["command_list_files_action_count"],
|
||||
1
|
||||
);
|
||||
assert_eq!(payload[0]["event_params"]["command_search_action_count"], 1);
|
||||
assert_eq!(
|
||||
payload[0]["event_params"]["command_unknown_action_count"],
|
||||
1
|
||||
);
|
||||
assert_eq!(payload[0]["event_params"]["started_at_ms"], 1_000);
|
||||
assert_eq!(payload[0]["event_params"]["completed_at_ms"], 1_045);
|
||||
assert_eq!(payload[0]["event_params"]["duration_ms"], 45);
|
||||
assert_eq!(payload[0]["event_params"]["execution_duration_ms"], 42);
|
||||
assert_eq!(
|
||||
payload[0]["event_params"]["app_server_client"]["client_name"],
|
||||
"codex-tui"
|
||||
);
|
||||
assert_eq!(payload[0]["event_params"]["thread_source"], "user");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subagent_thread_started_review_serializes_expected_shape() {
|
||||
let event = TrackEventRequest::ThreadInitialized(subagent_thread_started_event_request(
|
||||
@@ -1678,6 +1886,79 @@ async fn subagent_thread_started_inherits_parent_connection_for_new_thread() {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn subagent_tool_items_inherit_parent_connection_metadata() {
|
||||
let mut reducer = AnalyticsReducer::default();
|
||||
let mut events = Vec::new();
|
||||
|
||||
ingest_tool_review_prerequisites(&mut reducer, &mut events).await;
|
||||
reducer
|
||||
.ingest(
|
||||
AnalyticsFact::Custom(CustomAnalyticsFact::SubAgentThreadStarted(
|
||||
SubAgentThreadStartedInput {
|
||||
thread_id: "thread-subagent".to_string(),
|
||||
parent_thread_id: Some("thread-1".to_string()),
|
||||
product_client_id: "codex-tui".to_string(),
|
||||
client_name: "codex-tui".to_string(),
|
||||
client_version: "1.0.0".to_string(),
|
||||
model: "gpt-5".to_string(),
|
||||
ephemeral: false,
|
||||
subagent_source: SubAgentSource::Review,
|
||||
created_at: 128,
|
||||
},
|
||||
)),
|
||||
&mut events,
|
||||
)
|
||||
.await;
|
||||
events.clear();
|
||||
|
||||
reducer
|
||||
.ingest(
|
||||
AnalyticsFact::Notification(Box::new(ServerNotification::ItemStarted(
|
||||
ItemStartedNotification {
|
||||
thread_id: "thread-subagent".to_string(),
|
||||
turn_id: "turn-subagent".to_string(),
|
||||
started_at_ms: 1_000,
|
||||
item: sample_command_execution_item(
|
||||
CommandExecutionStatus::InProgress,
|
||||
/*exit_code*/ None,
|
||||
/*duration_ms*/ None,
|
||||
),
|
||||
},
|
||||
))),
|
||||
&mut events,
|
||||
)
|
||||
.await;
|
||||
reducer
|
||||
.ingest(
|
||||
AnalyticsFact::Notification(Box::new(ServerNotification::ItemCompleted(
|
||||
ItemCompletedNotification {
|
||||
thread_id: "thread-subagent".to_string(),
|
||||
turn_id: "turn-subagent".to_string(),
|
||||
completed_at_ms: 1_042,
|
||||
item: sample_command_execution_item(
|
||||
CommandExecutionStatus::Completed,
|
||||
Some(0),
|
||||
Some(42),
|
||||
),
|
||||
},
|
||||
))),
|
||||
&mut events,
|
||||
)
|
||||
.await;
|
||||
|
||||
let payload = serde_json::to_value(&events).expect("serialize events");
|
||||
assert_eq!(payload.as_array().expect("events array").len(), 1);
|
||||
assert_eq!(payload[0]["event_type"], "codex_command_execution_event");
|
||||
assert_eq!(payload[0]["event_params"]["thread_source"], "subagent");
|
||||
assert_eq!(payload[0]["event_params"]["subagent_source"], "review");
|
||||
assert_eq!(payload[0]["event_params"]["parent_thread_id"], "thread-1");
|
||||
assert_eq!(
|
||||
payload[0]["event_params"]["app_server_client"]["client_name"],
|
||||
"codex-tui"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plugin_used_event_serializes_expected_shape() {
|
||||
let tracking = TrackEventsContext {
|
||||
@@ -2116,7 +2397,7 @@ fn turn_event_serializes_expected_shape() {
|
||||
runtime: sample_runtime_metadata(),
|
||||
submission_type: None,
|
||||
ephemeral: false,
|
||||
thread_source: Some("user".to_string()),
|
||||
thread_source: Some(ThreadSource::User),
|
||||
initialization_mode: ThreadInitializationMode::New,
|
||||
subagent_source: None,
|
||||
parent_thread_id: None,
|
||||
|
||||
@@ -333,10 +333,6 @@ impl AnalyticsEventsClient {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn track_notification(&self, notification: ServerNotification) {
|
||||
self.record_fact(AnalyticsFact::Notification(Box::new(notification)));
|
||||
}
|
||||
|
||||
pub fn track_server_request(&self, connection_id: u64, request: ServerRequest) {
|
||||
self.record_fact(AnalyticsFact::ServerRequest {
|
||||
connection_id,
|
||||
@@ -349,6 +345,21 @@ impl AnalyticsEventsClient {
|
||||
response: Box::new(response),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn track_notification(&self, notification: ServerNotification) {
|
||||
if !matches!(
|
||||
notification,
|
||||
ServerNotification::TurnStarted(_)
|
||||
| ServerNotification::TurnCompleted(_)
|
||||
| ServerNotification::ItemStarted(_)
|
||||
| ServerNotification::ItemCompleted(_)
|
||||
| ServerNotification::ItemGuardianApprovalReviewStarted(_)
|
||||
| ServerNotification::ItemGuardianApprovalReviewCompleted(_)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
self.record_fact(AnalyticsFact::Notification(Box::new(notification)));
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_track_events(
|
||||
|
||||
@@ -76,6 +76,7 @@ fn sample_thread_archive_request() -> ClientRequest {
|
||||
fn sample_thread(thread_id: &str) -> Thread {
|
||||
Thread {
|
||||
id: thread_id.to_string(),
|
||||
session_id: format!("session-{thread_id}"),
|
||||
forked_from_id: None,
|
||||
preview: "first prompt".to_string(),
|
||||
ephemeral: false,
|
||||
@@ -87,6 +88,7 @@ fn sample_thread(thread_id: &str) -> Thread {
|
||||
cwd: test_path_buf("/tmp").abs(),
|
||||
cli_version: "0.0.0".to_string(),
|
||||
source: AppServerSessionSource::Exec,
|
||||
thread_source: None,
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
git_info: None,
|
||||
|
||||
@@ -20,6 +20,7 @@ use crate::facts::TurnSteerResult;
|
||||
use crate::facts::TurnSubmissionType;
|
||||
use crate::now_unix_seconds;
|
||||
use codex_app_server_protocol::CodexErrorInfo;
|
||||
use codex_app_server_protocol::CommandExecutionSource;
|
||||
use codex_login::default_client::originator;
|
||||
use codex_plugin::PluginTelemetryMetadata;
|
||||
use codex_protocol::approvals::NetworkApprovalProtocol;
|
||||
@@ -33,6 +34,7 @@ use codex_protocol::protocol::HookEventName;
|
||||
use codex_protocol::protocol::HookRunStatus;
|
||||
use codex_protocol::protocol::HookSource;
|
||||
use codex_protocol::protocol::SubAgentSource;
|
||||
use codex_protocol::protocol::ThreadSource;
|
||||
use codex_protocol::protocol::TokenUsage;
|
||||
use serde::Serialize;
|
||||
|
||||
@@ -61,19 +63,12 @@ pub(crate) enum TrackEventRequest {
|
||||
Compaction(Box<CodexCompactionEventRequest>),
|
||||
TurnEvent(Box<CodexTurnEventRequest>),
|
||||
TurnSteer(CodexTurnSteerEventRequest),
|
||||
#[allow(dead_code)]
|
||||
CommandExecution(CodexCommandExecutionEventRequest),
|
||||
#[allow(dead_code)]
|
||||
FileChange(CodexFileChangeEventRequest),
|
||||
#[allow(dead_code)]
|
||||
McpToolCall(CodexMcpToolCallEventRequest),
|
||||
#[allow(dead_code)]
|
||||
DynamicToolCall(CodexDynamicToolCallEventRequest),
|
||||
#[allow(dead_code)]
|
||||
CollabAgentToolCall(CodexCollabAgentToolCallEventRequest),
|
||||
#[allow(dead_code)]
|
||||
WebSearch(CodexWebSearchEventRequest),
|
||||
#[allow(dead_code)]
|
||||
ImageGeneration(CodexImageGenerationEventRequest),
|
||||
PluginUsed(CodexPluginUsedEventRequest),
|
||||
PluginInstalled(CodexPluginEventRequest),
|
||||
@@ -126,7 +121,7 @@ pub(crate) struct ThreadInitializedEventParams {
|
||||
pub(crate) runtime: CodexRuntimeMetadata,
|
||||
pub(crate) model: String,
|
||||
pub(crate) ephemeral: bool,
|
||||
pub(crate) thread_source: Option<&'static str>,
|
||||
pub(crate) thread_source: Option<ThreadSource>,
|
||||
pub(crate) initialization_mode: ThreadInitializationMode,
|
||||
pub(crate) subagent_source: Option<String>,
|
||||
pub(crate) parent_thread_id: Option<String>,
|
||||
@@ -453,7 +448,10 @@ pub(crate) struct CodexToolItemEventBase {
|
||||
pub(crate) tool_name: String,
|
||||
pub(crate) started_at_ms: u64,
|
||||
pub(crate) completed_at_ms: u64,
|
||||
// Observed item lifecycle duration. This may undercount end-to-end execution
|
||||
// for tools where app-server only sees part of the upstream flow.
|
||||
pub(crate) duration_ms: Option<u64>,
|
||||
pub(crate) execution_duration_ms: Option<u64>,
|
||||
pub(crate) review_count: u64,
|
||||
pub(crate) guardian_review_count: u64,
|
||||
pub(crate) user_review_count: u64,
|
||||
@@ -464,17 +462,6 @@ pub(crate) struct CodexToolItemEventBase {
|
||||
pub(crate) requested_network_access: bool,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Copy, Debug, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub(crate) enum CommandExecutionSource {
|
||||
Agent,
|
||||
UserShell,
|
||||
UnifiedExecStartup,
|
||||
UnifiedExecInteraction,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Copy, Debug, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub(crate) enum WebSearchActionKind {
|
||||
@@ -591,7 +578,6 @@ pub(crate) struct CodexWebSearchEventRequest {
|
||||
pub(crate) struct CodexImageGenerationEventParams {
|
||||
#[serde(flatten)]
|
||||
pub(crate) base: CodexToolItemEventBase,
|
||||
pub(crate) image_generation_status: String,
|
||||
pub(crate) revised_prompt_present: bool,
|
||||
pub(crate) saved_path_present: bool,
|
||||
}
|
||||
@@ -647,7 +633,7 @@ pub(crate) struct CodexCompactionEventParams {
|
||||
pub(crate) turn_id: String,
|
||||
pub(crate) app_server_client: CodexAppServerClientMetadata,
|
||||
pub(crate) runtime: CodexRuntimeMetadata,
|
||||
pub(crate) thread_source: Option<&'static str>,
|
||||
pub(crate) thread_source: Option<ThreadSource>,
|
||||
pub(crate) subagent_source: Option<String>,
|
||||
pub(crate) parent_thread_id: Option<String>,
|
||||
pub(crate) trigger: CompactionTrigger,
|
||||
@@ -680,7 +666,7 @@ pub(crate) struct CodexTurnEventParams {
|
||||
pub(crate) app_server_client: CodexAppServerClientMetadata,
|
||||
pub(crate) runtime: CodexRuntimeMetadata,
|
||||
pub(crate) ephemeral: bool,
|
||||
pub(crate) thread_source: Option<String>,
|
||||
pub(crate) thread_source: Option<ThreadSource>,
|
||||
pub(crate) initialization_mode: ThreadInitializationMode,
|
||||
pub(crate) subagent_source: Option<String>,
|
||||
pub(crate) parent_thread_id: Option<String>,
|
||||
@@ -733,7 +719,7 @@ pub(crate) struct CodexTurnSteerEventParams {
|
||||
pub(crate) accepted_turn_id: Option<String>,
|
||||
pub(crate) app_server_client: CodexAppServerClientMetadata,
|
||||
pub(crate) runtime: CodexRuntimeMetadata,
|
||||
pub(crate) thread_source: Option<String>,
|
||||
pub(crate) thread_source: Option<ThreadSource>,
|
||||
pub(crate) subagent_source: Option<String>,
|
||||
pub(crate) parent_thread_id: Option<String>,
|
||||
pub(crate) num_input_images: usize,
|
||||
@@ -836,7 +822,7 @@ pub(crate) fn codex_compaction_event_params(
|
||||
input: CodexCompactionEvent,
|
||||
app_server_client: CodexAppServerClientMetadata,
|
||||
runtime: CodexRuntimeMetadata,
|
||||
thread_source: Option<&'static str>,
|
||||
thread_source: Option<ThreadSource>,
|
||||
subagent_source: Option<String>,
|
||||
parent_thread_id: Option<String>,
|
||||
) -> CodexCompactionEventParams {
|
||||
@@ -894,6 +880,8 @@ fn analytics_hook_event_name(event_name: HookEventName) -> &'static str {
|
||||
HookEventName::PreToolUse => "PreToolUse",
|
||||
HookEventName::PermissionRequest => "PermissionRequest",
|
||||
HookEventName::PostToolUse => "PostToolUse",
|
||||
HookEventName::PreCompact => "PreCompact",
|
||||
HookEventName::PostCompact => "PostCompact",
|
||||
HookEventName::SessionStart => "SessionStart",
|
||||
HookEventName::UserPromptSubmit => "UserPromptSubmit",
|
||||
HookEventName::Stop => "Stop",
|
||||
@@ -940,7 +928,7 @@ pub(crate) fn subagent_thread_started_event_request(
|
||||
runtime: current_runtime_metadata(),
|
||||
model: input.model,
|
||||
ephemeral: input.ephemeral,
|
||||
thread_source: Some("subagent"),
|
||||
thread_source: Some(ThreadSource::Subagent),
|
||||
initialization_mode: ThreadInitializationMode::New,
|
||||
subagent_source: Some(subagent_source_name(&input.subagent_source)),
|
||||
parent_thread_id: input
|
||||
|
||||
@@ -51,3 +51,27 @@ pub fn now_unix_seconds() -> u64 {
|
||||
.unwrap_or_default()
|
||||
.as_secs()
|
||||
}
|
||||
|
||||
pub fn now_unix_millis() -> u64 {
|
||||
u64::try_from(
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_millis(),
|
||||
)
|
||||
.unwrap_or(u64::MAX)
|
||||
}
|
||||
|
||||
pub(crate) fn serialize_enum_as_string<T: serde::Serialize>(value: &T) -> Option<String> {
|
||||
serde_json::to_value(value)
|
||||
.ok()
|
||||
.and_then(|value| value.as_str().map(str::to_string))
|
||||
}
|
||||
|
||||
pub(crate) fn usize_to_u64(value: usize) -> u64 {
|
||||
u64::try_from(value).unwrap_or(u64::MAX)
|
||||
}
|
||||
|
||||
pub(crate) fn option_i64_to_u64(value: Option<i64>) -> Option<u64> {
|
||||
value.and_then(|value| u64::try_from(value).ok())
|
||||
}
|
||||
|
||||
@@ -2,15 +2,30 @@ use crate::events::AppServerRpcTransport;
|
||||
use crate::events::CodexAppMentionedEventRequest;
|
||||
use crate::events::CodexAppServerClientMetadata;
|
||||
use crate::events::CodexAppUsedEventRequest;
|
||||
use crate::events::CodexCollabAgentToolCallEventParams;
|
||||
use crate::events::CodexCollabAgentToolCallEventRequest;
|
||||
use crate::events::CodexCommandExecutionEventParams;
|
||||
use crate::events::CodexCommandExecutionEventRequest;
|
||||
use crate::events::CodexCompactionEventRequest;
|
||||
use crate::events::CodexDynamicToolCallEventParams;
|
||||
use crate::events::CodexDynamicToolCallEventRequest;
|
||||
use crate::events::CodexFileChangeEventParams;
|
||||
use crate::events::CodexFileChangeEventRequest;
|
||||
use crate::events::CodexHookRunEventRequest;
|
||||
use crate::events::CodexImageGenerationEventParams;
|
||||
use crate::events::CodexImageGenerationEventRequest;
|
||||
use crate::events::CodexMcpToolCallEventParams;
|
||||
use crate::events::CodexMcpToolCallEventRequest;
|
||||
use crate::events::CodexPluginEventRequest;
|
||||
use crate::events::CodexPluginUsedEventRequest;
|
||||
use crate::events::CodexRuntimeMetadata;
|
||||
use crate::events::CodexToolItemEventBase;
|
||||
use crate::events::CodexTurnEventParams;
|
||||
use crate::events::CodexTurnEventRequest;
|
||||
use crate::events::CodexTurnSteerEventParams;
|
||||
use crate::events::CodexTurnSteerEventRequest;
|
||||
use crate::events::CodexWebSearchEventParams;
|
||||
use crate::events::CodexWebSearchEventRequest;
|
||||
use crate::events::GuardianReviewEventParams;
|
||||
use crate::events::GuardianReviewEventPayload;
|
||||
use crate::events::GuardianReviewEventRequest;
|
||||
@@ -18,7 +33,11 @@ use crate::events::SkillInvocationEventParams;
|
||||
use crate::events::SkillInvocationEventRequest;
|
||||
use crate::events::ThreadInitializedEvent;
|
||||
use crate::events::ThreadInitializedEventParams;
|
||||
use crate::events::ToolItemFailureKind;
|
||||
use crate::events::ToolItemFinalApprovalOutcome;
|
||||
use crate::events::ToolItemTerminalStatus;
|
||||
use crate::events::TrackEventRequest;
|
||||
use crate::events::WebSearchActionKind;
|
||||
use crate::events::codex_app_metadata;
|
||||
use crate::events::codex_compaction_event_params;
|
||||
use crate::events::codex_hook_run_metadata;
|
||||
@@ -47,14 +66,30 @@ use crate::facts::TurnSteerRejectionReason;
|
||||
use crate::facts::TurnSteerResult;
|
||||
use crate::facts::TurnTokenUsageFact;
|
||||
use crate::now_unix_seconds;
|
||||
use crate::option_i64_to_u64;
|
||||
use crate::serialize_enum_as_string;
|
||||
use crate::usize_to_u64;
|
||||
use codex_app_server_protocol::ClientRequest;
|
||||
use codex_app_server_protocol::ClientResponse;
|
||||
use codex_app_server_protocol::CodexErrorInfo;
|
||||
use codex_app_server_protocol::CollabAgentStatus;
|
||||
use codex_app_server_protocol::CollabAgentTool;
|
||||
use codex_app_server_protocol::CollabAgentToolCallStatus;
|
||||
use codex_app_server_protocol::CommandAction;
|
||||
use codex_app_server_protocol::CommandExecutionSource;
|
||||
use codex_app_server_protocol::CommandExecutionStatus;
|
||||
use codex_app_server_protocol::DynamicToolCallOutputContentItem;
|
||||
use codex_app_server_protocol::DynamicToolCallStatus;
|
||||
use codex_app_server_protocol::InitializeParams;
|
||||
use codex_app_server_protocol::McpToolCallStatus;
|
||||
use codex_app_server_protocol::PatchApplyStatus;
|
||||
use codex_app_server_protocol::PatchChangeKind;
|
||||
use codex_app_server_protocol::RequestId;
|
||||
use codex_app_server_protocol::ServerNotification;
|
||||
use codex_app_server_protocol::ThreadItem;
|
||||
use codex_app_server_protocol::TurnSteerResponse;
|
||||
use codex_app_server_protocol::UserInput;
|
||||
use codex_app_server_protocol::WebSearchAction;
|
||||
use codex_git_utils::collect_git_info;
|
||||
use codex_git_utils::get_git_repo_root;
|
||||
use codex_login::default_client::originator;
|
||||
@@ -64,6 +99,7 @@ use codex_protocol::config_types::ReasoningSummary;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::protocol::SkillScope;
|
||||
use codex_protocol::protocol::ThreadSource;
|
||||
use codex_protocol::protocol::TokenUsage;
|
||||
use sha1::Digest;
|
||||
use std::collections::HashMap;
|
||||
@@ -75,6 +111,7 @@ pub(crate) struct AnalyticsReducer {
|
||||
turns: HashMap<String, TurnState>,
|
||||
connections: HashMap<u64, ConnectionState>,
|
||||
threads: HashMap<String, ThreadAnalyticsState>,
|
||||
tool_items_started_at_ms: HashMap<ToolItemKey, u64>,
|
||||
}
|
||||
|
||||
struct ConnectionState {
|
||||
@@ -118,6 +155,19 @@ impl<'a> AnalyticsDropSite<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn tool_item(
|
||||
notification: &'a codex_app_server_protocol::ItemCompletedNotification,
|
||||
item_id: &'a str,
|
||||
) -> Self {
|
||||
Self {
|
||||
event_name: "tool item",
|
||||
thread_id: ¬ification.thread_id,
|
||||
turn_id: Some(¬ification.turn_id),
|
||||
review_id: None,
|
||||
item_id: Some(item_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn turn_steer(thread_id: &'a str) -> Self {
|
||||
Self {
|
||||
event_name: "turn steer",
|
||||
@@ -147,7 +197,7 @@ enum MissingAnalyticsContext {
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ThreadMetadataState {
|
||||
thread_source: Option<&'static str>,
|
||||
thread_source: Option<ThreadSource>,
|
||||
initialization_mode: ThreadInitializationMode,
|
||||
subagent_source: Option<String>,
|
||||
parent_thread_id: Option<String>,
|
||||
@@ -156,6 +206,7 @@ struct ThreadMetadataState {
|
||||
impl ThreadMetadataState {
|
||||
fn from_thread_metadata(
|
||||
session_source: &SessionSource,
|
||||
thread_source: Option<ThreadSource>,
|
||||
initialization_mode: ThreadInitializationMode,
|
||||
) -> Self {
|
||||
let (subagent_source, parent_thread_id) = match session_source {
|
||||
@@ -172,7 +223,7 @@ impl ThreadMetadataState {
|
||||
| SessionSource::Unknown => (None, None),
|
||||
};
|
||||
Self {
|
||||
thread_source: session_source.thread_source_name(),
|
||||
thread_source,
|
||||
initialization_mode,
|
||||
subagent_source,
|
||||
parent_thread_id,
|
||||
@@ -216,6 +267,13 @@ struct TurnState {
|
||||
steer_count: usize,
|
||||
}
|
||||
|
||||
#[derive(Hash, Eq, PartialEq)]
|
||||
struct ToolItemKey {
|
||||
thread_id: String,
|
||||
turn_id: String,
|
||||
item_id: String,
|
||||
}
|
||||
|
||||
impl AnalyticsReducer {
|
||||
pub(crate) async fn ingest(&mut self, input: AnalyticsFact, out: &mut Vec<TrackEventRequest>) {
|
||||
match input {
|
||||
@@ -348,7 +406,7 @@ impl AnalyticsReducer {
|
||||
thread_state
|
||||
.metadata
|
||||
.get_or_insert_with(|| ThreadMetadataState {
|
||||
thread_source: Some("subagent"),
|
||||
thread_source: Some(ThreadSource::Subagent),
|
||||
initialization_mode: ThreadInitializationMode::New,
|
||||
subagent_source: Some(subagent_source_name(&input.subagent_source)),
|
||||
parent_thread_id,
|
||||
@@ -688,6 +746,62 @@ impl AnalyticsReducer {
|
||||
out: &mut Vec<TrackEventRequest>,
|
||||
) {
|
||||
match notification {
|
||||
ServerNotification::ItemStarted(notification) => {
|
||||
let Some(item_id) = tracked_tool_item_id(¬ification.item) else {
|
||||
return;
|
||||
};
|
||||
let Some(started_at_ms) = option_i64_to_u64(Some(notification.started_at_ms))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
self.tool_items_started_at_ms.insert(
|
||||
ToolItemKey {
|
||||
thread_id: notification.thread_id,
|
||||
turn_id: notification.turn_id,
|
||||
item_id: item_id.to_string(),
|
||||
},
|
||||
started_at_ms,
|
||||
);
|
||||
}
|
||||
ServerNotification::ItemCompleted(notification) => {
|
||||
let Some(item_id) = tracked_tool_item_id(¬ification.item) else {
|
||||
return;
|
||||
};
|
||||
let key = ToolItemKey {
|
||||
thread_id: notification.thread_id.clone(),
|
||||
turn_id: notification.turn_id.clone(),
|
||||
item_id: item_id.to_string(),
|
||||
};
|
||||
let Some(started_at_ms) = self.tool_items_started_at_ms.remove(&key) else {
|
||||
tracing::warn!(
|
||||
thread_id = %notification.thread_id,
|
||||
turn_id = %notification.turn_id,
|
||||
item_id,
|
||||
"dropping tool item analytics event: missing item started notification"
|
||||
);
|
||||
return;
|
||||
};
|
||||
let Some(completed_at_ms) = option_i64_to_u64(Some(notification.completed_at_ms))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Some((connection_state, thread_metadata)) = self
|
||||
.thread_context_or_warn(AnalyticsDropSite::tool_item(¬ification, item_id))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
if let Some(event) = tool_item_event(
|
||||
¬ification.thread_id,
|
||||
¬ification.turn_id,
|
||||
¬ification.item,
|
||||
started_at_ms,
|
||||
completed_at_ms,
|
||||
connection_state,
|
||||
thread_metadata,
|
||||
) {
|
||||
out.push(event);
|
||||
}
|
||||
}
|
||||
ServerNotification::TurnStarted(notification) => {
|
||||
let turn_state = self.turns.entry(notification.turn.id).or_insert(TurnState {
|
||||
connection_id: None,
|
||||
@@ -749,13 +863,16 @@ impl AnalyticsReducer {
|
||||
initialization_mode: ThreadInitializationMode,
|
||||
out: &mut Vec<TrackEventRequest>,
|
||||
) {
|
||||
let thread_source: SessionSource = thread.source.into();
|
||||
let session_source: SessionSource = thread.source.into();
|
||||
let thread_id = thread.id;
|
||||
let Some(connection_state) = self.connections.get(&connection_id) else {
|
||||
return;
|
||||
};
|
||||
let thread_metadata =
|
||||
ThreadMetadataState::from_thread_metadata(&thread_source, initialization_mode);
|
||||
let thread_metadata = ThreadMetadataState::from_thread_metadata(
|
||||
&session_source,
|
||||
thread.thread_source.map(Into::into),
|
||||
initialization_mode,
|
||||
);
|
||||
self.threads.insert(
|
||||
thread_id.clone(),
|
||||
ThreadAnalyticsState {
|
||||
@@ -774,7 +891,7 @@ impl AnalyticsReducer {
|
||||
ephemeral: thread.ephemeral,
|
||||
thread_source: thread_metadata.thread_source,
|
||||
initialization_mode,
|
||||
subagent_source: thread_metadata.subagent_source,
|
||||
subagent_source: thread_metadata.subagent_source.clone(),
|
||||
parent_thread_id: thread_metadata.parent_thread_id,
|
||||
created_at: u64::try_from(thread.created_at).unwrap_or_default(),
|
||||
},
|
||||
@@ -857,7 +974,7 @@ impl AnalyticsReducer {
|
||||
accepted_turn_id,
|
||||
app_server_client: connection_state.app_server_client.clone(),
|
||||
runtime: connection_state.runtime.clone(),
|
||||
thread_source: thread_metadata.thread_source.map(str::to_string),
|
||||
thread_source: thread_metadata.thread_source,
|
||||
subagent_source: thread_metadata.subagent_source.clone(),
|
||||
parent_thread_id: thread_metadata.parent_thread_id.clone(),
|
||||
num_input_images: pending_request.num_input_images,
|
||||
@@ -978,6 +1095,552 @@ fn warn_missing_analytics_context(
|
||||
);
|
||||
}
|
||||
|
||||
fn tracked_tool_item_id(item: &ThreadItem) -> Option<&str> {
|
||||
match item {
|
||||
ThreadItem::CommandExecution { id, .. }
|
||||
| ThreadItem::FileChange { id, .. }
|
||||
| ThreadItem::McpToolCall { id, .. }
|
||||
| ThreadItem::DynamicToolCall { id, .. }
|
||||
| ThreadItem::CollabAgentToolCall { id, .. }
|
||||
| ThreadItem::WebSearch { id, .. }
|
||||
| ThreadItem::ImageGeneration { id, .. } => Some(id),
|
||||
ThreadItem::UserMessage { .. }
|
||||
| ThreadItem::HookPrompt { .. }
|
||||
| ThreadItem::AgentMessage { .. }
|
||||
| ThreadItem::Plan { .. }
|
||||
| ThreadItem::Reasoning { .. }
|
||||
| ThreadItem::ImageView { .. }
|
||||
| ThreadItem::EnteredReviewMode { .. }
|
||||
| ThreadItem::ExitedReviewMode { .. }
|
||||
| ThreadItem::ContextCompaction { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn tool_item_event(
|
||||
thread_id: &str,
|
||||
turn_id: &str,
|
||||
item: &ThreadItem,
|
||||
started_at_ms: u64,
|
||||
completed_at_ms: u64,
|
||||
connection_state: &ConnectionState,
|
||||
thread_metadata: &ThreadMetadataState,
|
||||
) -> Option<TrackEventRequest> {
|
||||
let context = ToolItemContext {
|
||||
started_at_ms,
|
||||
completed_at_ms,
|
||||
connection_state,
|
||||
thread_metadata,
|
||||
};
|
||||
match item {
|
||||
ThreadItem::CommandExecution {
|
||||
id,
|
||||
source,
|
||||
status,
|
||||
command_actions,
|
||||
exit_code,
|
||||
duration_ms,
|
||||
..
|
||||
} => {
|
||||
let (terminal_status, failure_kind) = command_execution_outcome(status)?;
|
||||
let action_counts = command_action_counts(command_actions);
|
||||
let base = tool_item_base(
|
||||
thread_id,
|
||||
turn_id,
|
||||
id.clone(),
|
||||
command_execution_tool_name(*source).to_string(),
|
||||
ToolItemOutcome {
|
||||
terminal_status,
|
||||
failure_kind,
|
||||
execution_duration_ms: option_i64_to_u64(*duration_ms),
|
||||
},
|
||||
context,
|
||||
);
|
||||
Some(TrackEventRequest::CommandExecution(
|
||||
CodexCommandExecutionEventRequest {
|
||||
event_type: "codex_command_execution_event",
|
||||
event_params: CodexCommandExecutionEventParams {
|
||||
base,
|
||||
command_execution_source: *source,
|
||||
exit_code: *exit_code,
|
||||
command_total_action_count: action_counts.total,
|
||||
command_read_action_count: action_counts.read,
|
||||
command_list_files_action_count: action_counts.list_files,
|
||||
command_search_action_count: action_counts.search,
|
||||
command_unknown_action_count: action_counts.unknown,
|
||||
},
|
||||
},
|
||||
))
|
||||
}
|
||||
ThreadItem::FileChange {
|
||||
id,
|
||||
changes,
|
||||
status,
|
||||
} => {
|
||||
let (terminal_status, failure_kind) = patch_apply_outcome(status)?;
|
||||
let counts = file_change_counts(changes);
|
||||
let base = tool_item_base(
|
||||
thread_id,
|
||||
turn_id,
|
||||
id.clone(),
|
||||
"apply_patch".to_string(),
|
||||
ToolItemOutcome {
|
||||
terminal_status,
|
||||
failure_kind,
|
||||
execution_duration_ms: None,
|
||||
},
|
||||
context,
|
||||
);
|
||||
Some(TrackEventRequest::FileChange(CodexFileChangeEventRequest {
|
||||
event_type: "codex_file_change_event",
|
||||
event_params: CodexFileChangeEventParams {
|
||||
base,
|
||||
file_change_count: usize_to_u64(changes.len()),
|
||||
file_add_count: counts.add,
|
||||
file_update_count: counts.update,
|
||||
file_delete_count: counts.delete,
|
||||
file_move_count: counts.move_,
|
||||
},
|
||||
}))
|
||||
}
|
||||
ThreadItem::McpToolCall {
|
||||
id,
|
||||
server,
|
||||
tool,
|
||||
status,
|
||||
error,
|
||||
duration_ms,
|
||||
..
|
||||
} => {
|
||||
let (terminal_status, failure_kind) = mcp_tool_call_outcome(status)?;
|
||||
let base = tool_item_base(
|
||||
thread_id,
|
||||
turn_id,
|
||||
id.clone(),
|
||||
tool.clone(),
|
||||
ToolItemOutcome {
|
||||
terminal_status,
|
||||
failure_kind,
|
||||
execution_duration_ms: option_i64_to_u64(*duration_ms),
|
||||
},
|
||||
context,
|
||||
);
|
||||
Some(TrackEventRequest::McpToolCall(
|
||||
CodexMcpToolCallEventRequest {
|
||||
event_type: "codex_mcp_tool_call_event",
|
||||
event_params: CodexMcpToolCallEventParams {
|
||||
base,
|
||||
mcp_server_name: server.clone(),
|
||||
mcp_tool_name: tool.clone(),
|
||||
mcp_error_present: error.is_some(),
|
||||
},
|
||||
},
|
||||
))
|
||||
}
|
||||
ThreadItem::DynamicToolCall {
|
||||
id,
|
||||
tool,
|
||||
status,
|
||||
content_items,
|
||||
success,
|
||||
duration_ms,
|
||||
..
|
||||
} => {
|
||||
let (terminal_status, failure_kind) = dynamic_tool_call_outcome(status)?;
|
||||
let counts = content_items
|
||||
.as_ref()
|
||||
.map(|items| dynamic_content_counts(items));
|
||||
let base = tool_item_base(
|
||||
thread_id,
|
||||
turn_id,
|
||||
id.clone(),
|
||||
tool.clone(),
|
||||
ToolItemOutcome {
|
||||
terminal_status,
|
||||
failure_kind,
|
||||
execution_duration_ms: option_i64_to_u64(*duration_ms),
|
||||
},
|
||||
context,
|
||||
);
|
||||
Some(TrackEventRequest::DynamicToolCall(
|
||||
CodexDynamicToolCallEventRequest {
|
||||
event_type: "codex_dynamic_tool_call_event",
|
||||
event_params: CodexDynamicToolCallEventParams {
|
||||
base,
|
||||
dynamic_tool_name: tool.clone(),
|
||||
success: *success,
|
||||
output_content_item_count: counts.map(|counts| counts.total),
|
||||
output_text_item_count: counts.map(|counts| counts.text),
|
||||
output_image_item_count: counts.map(|counts| counts.image),
|
||||
},
|
||||
},
|
||||
))
|
||||
}
|
||||
ThreadItem::CollabAgentToolCall {
|
||||
id,
|
||||
tool,
|
||||
status,
|
||||
sender_thread_id,
|
||||
receiver_thread_ids,
|
||||
model,
|
||||
reasoning_effort,
|
||||
agents_states,
|
||||
..
|
||||
} => {
|
||||
let (terminal_status, failure_kind) = collab_tool_call_outcome(status)?;
|
||||
let base = tool_item_base(
|
||||
thread_id,
|
||||
turn_id,
|
||||
id.clone(),
|
||||
collab_agent_tool_name(tool).to_string(),
|
||||
ToolItemOutcome {
|
||||
terminal_status,
|
||||
failure_kind,
|
||||
execution_duration_ms: None,
|
||||
},
|
||||
context,
|
||||
);
|
||||
Some(TrackEventRequest::CollabAgentToolCall(
|
||||
CodexCollabAgentToolCallEventRequest {
|
||||
event_type: "codex_collab_agent_tool_call_event",
|
||||
event_params: CodexCollabAgentToolCallEventParams {
|
||||
base,
|
||||
sender_thread_id: sender_thread_id.clone(),
|
||||
receiver_thread_count: usize_to_u64(receiver_thread_ids.len()),
|
||||
receiver_thread_ids: Some(receiver_thread_ids.clone()),
|
||||
requested_model: model.clone(),
|
||||
requested_reasoning_effort: reasoning_effort
|
||||
.as_ref()
|
||||
.and_then(serialize_enum_as_string),
|
||||
agent_state_count: Some(usize_to_u64(agents_states.len())),
|
||||
completed_agent_count: Some(usize_to_u64(
|
||||
agents_states
|
||||
.values()
|
||||
.filter(|state| state.status == CollabAgentStatus::Completed)
|
||||
.count(),
|
||||
)),
|
||||
failed_agent_count: Some(usize_to_u64(
|
||||
agents_states
|
||||
.values()
|
||||
.filter(|state| {
|
||||
matches!(
|
||||
state.status,
|
||||
CollabAgentStatus::Errored
|
||||
| CollabAgentStatus::Shutdown
|
||||
| CollabAgentStatus::NotFound
|
||||
)
|
||||
})
|
||||
.count(),
|
||||
)),
|
||||
},
|
||||
},
|
||||
))
|
||||
}
|
||||
ThreadItem::WebSearch { id, query, action } => {
|
||||
let base = tool_item_base(
|
||||
thread_id,
|
||||
turn_id,
|
||||
id.clone(),
|
||||
"web_search".to_string(),
|
||||
ToolItemOutcome {
|
||||
terminal_status: ToolItemTerminalStatus::Completed,
|
||||
failure_kind: None,
|
||||
execution_duration_ms: None,
|
||||
},
|
||||
context,
|
||||
);
|
||||
Some(TrackEventRequest::WebSearch(CodexWebSearchEventRequest {
|
||||
event_type: "codex_web_search_event",
|
||||
event_params: CodexWebSearchEventParams {
|
||||
base,
|
||||
web_search_action: action.as_ref().map(web_search_action_kind),
|
||||
query_present: !query.trim().is_empty(),
|
||||
query_count: web_search_query_count(query, action.as_ref()),
|
||||
},
|
||||
}))
|
||||
}
|
||||
ThreadItem::ImageGeneration {
|
||||
id,
|
||||
status,
|
||||
revised_prompt,
|
||||
saved_path,
|
||||
..
|
||||
} => {
|
||||
let (terminal_status, failure_kind) = image_generation_outcome(status.as_str());
|
||||
let base = tool_item_base(
|
||||
thread_id,
|
||||
turn_id,
|
||||
id.clone(),
|
||||
"image_generation".to_string(),
|
||||
ToolItemOutcome {
|
||||
terminal_status,
|
||||
failure_kind,
|
||||
execution_duration_ms: None,
|
||||
},
|
||||
context,
|
||||
);
|
||||
Some(TrackEventRequest::ImageGeneration(
|
||||
CodexImageGenerationEventRequest {
|
||||
event_type: "codex_image_generation_event",
|
||||
event_params: CodexImageGenerationEventParams {
|
||||
base,
|
||||
revised_prompt_present: revised_prompt.is_some(),
|
||||
saved_path_present: saved_path.is_some(),
|
||||
},
|
||||
},
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
struct ToolItemOutcome {
|
||||
terminal_status: ToolItemTerminalStatus,
|
||||
failure_kind: Option<ToolItemFailureKind>,
|
||||
execution_duration_ms: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct CommandActionCounts {
|
||||
total: u64,
|
||||
read: u64,
|
||||
list_files: u64,
|
||||
search: u64,
|
||||
unknown: u64,
|
||||
}
|
||||
|
||||
fn command_action_counts(command_actions: &[CommandAction]) -> CommandActionCounts {
|
||||
let mut counts = CommandActionCounts {
|
||||
total: usize_to_u64(command_actions.len()),
|
||||
..Default::default()
|
||||
};
|
||||
for action in command_actions {
|
||||
match action {
|
||||
CommandAction::Read { .. } => counts.read += 1,
|
||||
CommandAction::ListFiles { .. } => counts.list_files += 1,
|
||||
CommandAction::Search { .. } => counts.search += 1,
|
||||
CommandAction::Unknown { .. } => counts.unknown += 1,
|
||||
}
|
||||
}
|
||||
counts
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct ToolItemContext<'a> {
|
||||
started_at_ms: u64,
|
||||
completed_at_ms: u64,
|
||||
connection_state: &'a ConnectionState,
|
||||
thread_metadata: &'a ThreadMetadataState,
|
||||
}
|
||||
|
||||
fn tool_item_base(
|
||||
thread_id: &str,
|
||||
turn_id: &str,
|
||||
item_id: String,
|
||||
tool_name: String,
|
||||
outcome: ToolItemOutcome,
|
||||
context: ToolItemContext<'_>,
|
||||
) -> CodexToolItemEventBase {
|
||||
let thread_metadata = context.thread_metadata;
|
||||
CodexToolItemEventBase {
|
||||
thread_id: thread_id.to_string(),
|
||||
turn_id: turn_id.to_string(),
|
||||
item_id,
|
||||
app_server_client: context.connection_state.app_server_client.clone(),
|
||||
runtime: context.connection_state.runtime.clone(),
|
||||
thread_source: thread_metadata.thread_source.map(ThreadSource::as_str),
|
||||
subagent_source: thread_metadata.subagent_source.clone(),
|
||||
parent_thread_id: thread_metadata.parent_thread_id.clone(),
|
||||
tool_name,
|
||||
started_at_ms: context.started_at_ms,
|
||||
completed_at_ms: context.completed_at_ms,
|
||||
// duration_ms reflects item lifecycle observed by app-server. For web
|
||||
// search and image generation in particular, that can be narrower than
|
||||
// full upstream execution time.
|
||||
duration_ms: observed_duration_ms(context.started_at_ms, context.completed_at_ms),
|
||||
execution_duration_ms: outcome.execution_duration_ms,
|
||||
review_count: 0,
|
||||
guardian_review_count: 0,
|
||||
user_review_count: 0,
|
||||
final_approval_outcome: ToolItemFinalApprovalOutcome::Unknown,
|
||||
terminal_status: outcome.terminal_status,
|
||||
failure_kind: outcome.failure_kind,
|
||||
requested_additional_permissions: false,
|
||||
requested_network_access: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn observed_duration_ms(started_at_ms: u64, completed_at_ms: u64) -> Option<u64> {
|
||||
completed_at_ms.checked_sub(started_at_ms)
|
||||
}
|
||||
|
||||
fn command_execution_tool_name(source: CommandExecutionSource) -> &'static str {
|
||||
match source {
|
||||
CommandExecutionSource::UnifiedExecStartup
|
||||
| CommandExecutionSource::UnifiedExecInteraction => "unified_exec",
|
||||
CommandExecutionSource::UserShell => "user_shell",
|
||||
CommandExecutionSource::Agent => "shell",
|
||||
}
|
||||
}
|
||||
|
||||
fn command_execution_outcome(
|
||||
status: &CommandExecutionStatus,
|
||||
) -> Option<(ToolItemTerminalStatus, Option<ToolItemFailureKind>)> {
|
||||
match status {
|
||||
CommandExecutionStatus::InProgress => None,
|
||||
CommandExecutionStatus::Completed => Some((ToolItemTerminalStatus::Completed, None)),
|
||||
CommandExecutionStatus::Failed => Some((
|
||||
ToolItemTerminalStatus::Failed,
|
||||
Some(ToolItemFailureKind::ToolError),
|
||||
)),
|
||||
CommandExecutionStatus::Declined => Some((
|
||||
ToolItemTerminalStatus::Rejected,
|
||||
Some(ToolItemFailureKind::ApprovalDenied),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn patch_apply_outcome(
|
||||
status: &PatchApplyStatus,
|
||||
) -> Option<(ToolItemTerminalStatus, Option<ToolItemFailureKind>)> {
|
||||
match status {
|
||||
PatchApplyStatus::InProgress => None,
|
||||
PatchApplyStatus::Completed => Some((ToolItemTerminalStatus::Completed, None)),
|
||||
PatchApplyStatus::Failed => Some((
|
||||
ToolItemTerminalStatus::Failed,
|
||||
Some(ToolItemFailureKind::ToolError),
|
||||
)),
|
||||
PatchApplyStatus::Declined => Some((
|
||||
ToolItemTerminalStatus::Rejected,
|
||||
Some(ToolItemFailureKind::ApprovalDenied),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn mcp_tool_call_outcome(
|
||||
status: &McpToolCallStatus,
|
||||
) -> Option<(ToolItemTerminalStatus, Option<ToolItemFailureKind>)> {
|
||||
match status {
|
||||
McpToolCallStatus::InProgress => None,
|
||||
McpToolCallStatus::Completed => Some((ToolItemTerminalStatus::Completed, None)),
|
||||
McpToolCallStatus::Failed => Some((
|
||||
ToolItemTerminalStatus::Failed,
|
||||
Some(ToolItemFailureKind::ToolError),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn dynamic_tool_call_outcome(
|
||||
status: &DynamicToolCallStatus,
|
||||
) -> Option<(ToolItemTerminalStatus, Option<ToolItemFailureKind>)> {
|
||||
match status {
|
||||
DynamicToolCallStatus::InProgress => None,
|
||||
DynamicToolCallStatus::Completed => Some((ToolItemTerminalStatus::Completed, None)),
|
||||
DynamicToolCallStatus::Failed => Some((
|
||||
ToolItemTerminalStatus::Failed,
|
||||
Some(ToolItemFailureKind::ToolError),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn collab_tool_call_outcome(
|
||||
status: &CollabAgentToolCallStatus,
|
||||
) -> Option<(ToolItemTerminalStatus, Option<ToolItemFailureKind>)> {
|
||||
match status {
|
||||
CollabAgentToolCallStatus::InProgress => None,
|
||||
CollabAgentToolCallStatus::Completed => Some((ToolItemTerminalStatus::Completed, None)),
|
||||
CollabAgentToolCallStatus::Failed => Some((
|
||||
ToolItemTerminalStatus::Failed,
|
||||
Some(ToolItemFailureKind::ToolError),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn image_generation_outcome(status: &str) -> (ToolItemTerminalStatus, Option<ToolItemFailureKind>) {
|
||||
match status {
|
||||
"failed" | "error" => (
|
||||
ToolItemTerminalStatus::Failed,
|
||||
Some(ToolItemFailureKind::ToolError),
|
||||
),
|
||||
_ => (ToolItemTerminalStatus::Completed, None),
|
||||
}
|
||||
}
|
||||
|
||||
fn collab_agent_tool_name(tool: &CollabAgentTool) -> &'static str {
|
||||
match tool {
|
||||
CollabAgentTool::SpawnAgent => "spawn_agent",
|
||||
CollabAgentTool::SendInput => "send_input",
|
||||
CollabAgentTool::ResumeAgent => "resume_agent",
|
||||
CollabAgentTool::Wait => "wait_agent",
|
||||
CollabAgentTool::CloseAgent => "close_agent",
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct FileChangeCounts {
|
||||
add: u64,
|
||||
update: u64,
|
||||
delete: u64,
|
||||
move_: u64,
|
||||
}
|
||||
|
||||
fn file_change_counts(changes: &[codex_app_server_protocol::FileUpdateChange]) -> FileChangeCounts {
|
||||
let mut counts = FileChangeCounts::default();
|
||||
for change in changes {
|
||||
match &change.kind {
|
||||
PatchChangeKind::Add => counts.add += 1,
|
||||
PatchChangeKind::Delete => counts.delete += 1,
|
||||
PatchChangeKind::Update { move_path: Some(_) } => counts.move_ += 1,
|
||||
PatchChangeKind::Update { move_path: None } => counts.update += 1,
|
||||
}
|
||||
}
|
||||
counts
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct DynamicContentCounts {
|
||||
total: u64,
|
||||
text: u64,
|
||||
image: u64,
|
||||
}
|
||||
|
||||
fn dynamic_content_counts(items: &[DynamicToolCallOutputContentItem]) -> DynamicContentCounts {
|
||||
let mut text = 0;
|
||||
let mut image = 0;
|
||||
for item in items {
|
||||
match item {
|
||||
DynamicToolCallOutputContentItem::InputText { .. } => text += 1,
|
||||
DynamicToolCallOutputContentItem::InputImage { .. } => image += 1,
|
||||
}
|
||||
}
|
||||
DynamicContentCounts {
|
||||
total: usize_to_u64(items.len()),
|
||||
text,
|
||||
image,
|
||||
}
|
||||
}
|
||||
|
||||
fn web_search_action_kind(action: &WebSearchAction) -> WebSearchActionKind {
|
||||
match action {
|
||||
WebSearchAction::Search { .. } => WebSearchActionKind::Search,
|
||||
WebSearchAction::OpenPage { .. } => WebSearchActionKind::OpenPage,
|
||||
WebSearchAction::FindInPage { .. } => WebSearchActionKind::FindInPage,
|
||||
WebSearchAction::Other => WebSearchActionKind::Other,
|
||||
}
|
||||
}
|
||||
|
||||
fn web_search_query_count(query: &str, action: Option<&WebSearchAction>) -> Option<u64> {
|
||||
match action {
|
||||
Some(WebSearchAction::Search { query, queries }) => queries
|
||||
.as_ref()
|
||||
.map(|queries| usize_to_u64(queries.len()))
|
||||
.or_else(|| query.as_ref().map(|_| 1)),
|
||||
Some(WebSearchAction::OpenPage { .. })
|
||||
| Some(WebSearchAction::FindInPage { .. })
|
||||
| Some(WebSearchAction::Other) => None,
|
||||
None => (!query.trim().is_empty()).then_some(1),
|
||||
}
|
||||
}
|
||||
|
||||
fn codex_turn_event_params(
|
||||
app_server_client: CodexAppServerClientMetadata,
|
||||
runtime: CodexRuntimeMetadata,
|
||||
@@ -1023,7 +1686,7 @@ fn codex_turn_event_params(
|
||||
runtime,
|
||||
submission_type,
|
||||
ephemeral,
|
||||
thread_source: thread_metadata.thread_source.map(str::to_string),
|
||||
thread_source: thread_metadata.thread_source,
|
||||
initialization_mode: thread_metadata.initialization_mode,
|
||||
subagent_source: thread_metadata.subagent_source.clone(),
|
||||
parent_thread_id: thread_metadata.parent_thread_id.clone(),
|
||||
|
||||
@@ -33,4 +33,5 @@ url = { workspace = true }
|
||||
[dev-dependencies]
|
||||
pretty_assertions = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
|
||||
|
||||
@@ -29,6 +29,7 @@ pub use codex_app_server::in_process::DEFAULT_IN_PROCESS_CHANNEL_CAPACITY;
|
||||
pub use codex_app_server::in_process::InProcessServerEvent;
|
||||
use codex_app_server::in_process::InProcessStartArgs;
|
||||
use codex_app_server::in_process::LogDbLayer;
|
||||
pub use codex_app_server::in_process::StateDbHandle;
|
||||
use codex_app_server_protocol::ClientInfo;
|
||||
use codex_app_server_protocol::ClientNotification;
|
||||
use codex_app_server_protocol::ClientRequest;
|
||||
@@ -46,7 +47,6 @@ use codex_config::LoaderOverrides;
|
||||
use codex_config::NoopThreadConfigLoader;
|
||||
use codex_config::RemoteThreadConfigLoader;
|
||||
use codex_config::ThreadConfigLoader;
|
||||
pub use codex_core::StateDbHandle;
|
||||
use codex_core::config::Config;
|
||||
pub use codex_exec_server::EnvironmentManager;
|
||||
pub use codex_exec_server::EnvironmentManagerArgs;
|
||||
@@ -72,12 +72,9 @@ pub mod legacy_core {
|
||||
pub use codex_core::DEFAULT_AGENTS_MD_FILENAME;
|
||||
pub use codex_core::LOCAL_AGENTS_MD_FILENAME;
|
||||
pub use codex_core::McpManager;
|
||||
pub use codex_core::append_message_history_entry;
|
||||
pub use codex_core::check_execpolicy_for_warnings;
|
||||
pub use codex_core::format_exec_policy_error_with_source;
|
||||
pub use codex_core::grant_read_root_non_elevated;
|
||||
pub use codex_core::lookup_message_history_entry;
|
||||
pub use codex_core::message_history_metadata;
|
||||
pub use codex_core::web_search_detail;
|
||||
|
||||
pub mod config {
|
||||
@@ -954,9 +951,13 @@ mod tests {
|
||||
use codex_app_server_protocol::ToolRequestUserInputParams;
|
||||
use codex_app_server_protocol::ToolRequestUserInputQuestion;
|
||||
use codex_core::config::ConfigBuilder;
|
||||
use codex_core::init_state_db;
|
||||
use futures::SinkExt;
|
||||
use futures::StreamExt;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::ops::Deref;
|
||||
use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::time::Duration;
|
||||
use tokio::time::timeout;
|
||||
@@ -975,19 +976,59 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
async fn build_test_config_for_codex_home(codex_home: &Path) -> Config {
|
||||
match ConfigBuilder::default()
|
||||
.codex_home(codex_home.to_path_buf())
|
||||
.build()
|
||||
.await
|
||||
{
|
||||
Ok(config) => config,
|
||||
Err(_) => Config::load_default_with_cli_overrides_for_codex_home(
|
||||
codex_home.to_path_buf(),
|
||||
Vec::new(),
|
||||
)
|
||||
.await
|
||||
.expect("default config should load"),
|
||||
}
|
||||
}
|
||||
|
||||
struct TestClient {
|
||||
_codex_home: TempDir,
|
||||
client: InProcessAppServerClient,
|
||||
}
|
||||
|
||||
impl Deref for TestClient {
|
||||
type Target = InProcessAppServerClient;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.client
|
||||
}
|
||||
}
|
||||
|
||||
impl TestClient {
|
||||
async fn shutdown(self) -> IoResult<()> {
|
||||
self.client.shutdown().await
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_test_client_with_capacity(
|
||||
session_source: SessionSource,
|
||||
channel_capacity: usize,
|
||||
) -> InProcessAppServerClient {
|
||||
InProcessAppServerClient::start(InProcessClientStartArgs {
|
||||
) -> TestClient {
|
||||
let codex_home = TempDir::new().expect("temp dir");
|
||||
let config = Arc::new(build_test_config_for_codex_home(codex_home.path()).await);
|
||||
let state_db = init_state_db(config.as_ref())
|
||||
.await
|
||||
.expect("state db should initialize for in-process test");
|
||||
let client = InProcessAppServerClient::start(InProcessClientStartArgs {
|
||||
arg0_paths: Arg0DispatchPaths::default(),
|
||||
config: Arc::new(build_test_config().await),
|
||||
config,
|
||||
cli_overrides: Vec::new(),
|
||||
loader_overrides: LoaderOverrides::default(),
|
||||
cloud_requirements: CloudRequirementsLoader::default(),
|
||||
feedback: CodexFeedback::new(),
|
||||
log_db: None,
|
||||
state_db: None,
|
||||
state_db: Some(state_db),
|
||||
environment_manager: Arc::new(EnvironmentManager::default_for_tests()),
|
||||
config_warnings: Vec::new(),
|
||||
session_source,
|
||||
@@ -999,10 +1040,15 @@ mod tests {
|
||||
channel_capacity,
|
||||
})
|
||||
.await
|
||||
.expect("in-process app-server client should start")
|
||||
.expect("in-process app-server client should start");
|
||||
|
||||
TestClient {
|
||||
_codex_home: codex_home,
|
||||
client,
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_test_client(session_source: SessionSource) -> InProcessAppServerClient {
|
||||
async fn start_test_client(session_source: SessionSource) -> TestClient {
|
||||
start_test_client_with_capacity(session_source, DEFAULT_IN_PROCESS_CHANNEL_CAPACITY).await
|
||||
}
|
||||
|
||||
|
||||
@@ -2144,6 +2144,14 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginListMarketplaceKind": {
|
||||
"enum": [
|
||||
"local",
|
||||
"workspace-directory",
|
||||
"shared-with-me"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PluginListParams": {
|
||||
"properties": {
|
||||
"cwds": {
|
||||
@@ -2155,6 +2163,16 @@
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"marketplaceKinds": {
|
||||
"description": "Optional marketplace kind filter. When omitted, only local marketplaces are queried, plus the default remote catalog when enabled by feature flag.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/PluginListMarketplaceKind"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@@ -2197,11 +2215,37 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareDiscoverability": {
|
||||
"enum": [
|
||||
"LISTED",
|
||||
"UNLISTED",
|
||||
"PRIVATE"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PluginShareListParams": {
|
||||
"type": "object"
|
||||
},
|
||||
"PluginSharePrincipalType": {
|
||||
"enum": [
|
||||
"user",
|
||||
"group",
|
||||
"workspace"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PluginShareSaveParams": {
|
||||
"properties": {
|
||||
"discoverability": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/PluginShareDiscoverability"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pluginPath": {
|
||||
"$ref": "#/definitions/AbsolutePathBuf"
|
||||
},
|
||||
@@ -2210,6 +2254,15 @@
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"shareTargets": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/PluginShareTarget"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -2217,6 +2270,39 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareTarget": {
|
||||
"properties": {
|
||||
"principalId": {
|
||||
"type": "string"
|
||||
},
|
||||
"principalType": {
|
||||
"$ref": "#/definitions/PluginSharePrincipalType"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"principalId",
|
||||
"principalType"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareUpdateTargetsParams": {
|
||||
"properties": {
|
||||
"remotePluginId": {
|
||||
"type": "string"
|
||||
},
|
||||
"shareTargets": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/PluginShareTarget"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"remotePluginId",
|
||||
"shareTargets"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginSkillReadParams": {
|
||||
"properties": {
|
||||
"remoteMarketplaceName": {
|
||||
@@ -3256,13 +3342,6 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"SessionMigration": {
|
||||
"properties": {
|
||||
"cwd": {
|
||||
@@ -3540,24 +3619,24 @@
|
||||
]
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional client-supplied analytics source classification for this forked thread."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -3951,20 +4030,9 @@
|
||||
]
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"threadId": {
|
||||
@@ -4032,6 +4100,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadSourceKind": {
|
||||
"enum": [
|
||||
"cli",
|
||||
@@ -4140,20 +4216,9 @@
|
||||
]
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"sessionStartSource": {
|
||||
@@ -4165,6 +4230,17 @@
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional client-supplied analytics source classification for this thread."
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@@ -4309,22 +4385,11 @@
|
||||
"description": "Override the sandbox policy for this turn and subsequent turns."
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Override the service tier for this turn and subsequent turns."
|
||||
"description": "Override the service tier for this turn and subsequent turns.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"anyOf": [
|
||||
@@ -5147,6 +5212,30 @@
|
||||
"title": "Plugin/share/saveRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"plugin/share/updateTargets"
|
||||
],
|
||||
"title": "Plugin/share/updateTargetsRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/PluginShareUpdateTargetsParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Plugin/share/updateTargetsRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
|
||||
@@ -1736,6 +1736,8 @@
|
||||
"preToolUse",
|
||||
"permissionRequest",
|
||||
"postToolUse",
|
||||
"preCompact",
|
||||
"postCompact",
|
||||
"sessionStart",
|
||||
"userPromptSubmit",
|
||||
"stop"
|
||||
@@ -3072,6 +3074,10 @@
|
||||
"description": "Usually the first user message in the thread, if available.",
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"allOf": [
|
||||
{
|
||||
@@ -3088,6 +3094,17 @@
|
||||
],
|
||||
"description": "Current runtime status for the thread."
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional analytics source classification for this thread."
|
||||
},
|
||||
"turns": {
|
||||
"description": "Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` (when `includeTurns` is true) responses. For all other responses and notifications returning a Thread, the turns field will be an empty list.",
|
||||
"items": {
|
||||
@@ -3109,6 +3126,7 @@
|
||||
"id",
|
||||
"modelProvider",
|
||||
"preview",
|
||||
"sessionId",
|
||||
"source",
|
||||
"status",
|
||||
"turns",
|
||||
@@ -4094,6 +4112,14 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadStartedNotification": {
|
||||
"properties": {
|
||||
"thread": {
|
||||
@@ -6074,4 +6100,4 @@
|
||||
}
|
||||
],
|
||||
"title": "ServerNotification"
|
||||
}
|
||||
}
|
||||
@@ -810,6 +810,30 @@
|
||||
"title": "Plugin/share/saveRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/v2/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"plugin/share/updateTargets"
|
||||
],
|
||||
"title": "Plugin/share/updateTargetsRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/v2/PluginShareUpdateTargetsParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Plugin/share/updateTargetsRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -7200,13 +7224,9 @@
|
||||
]
|
||||
},
|
||||
"service_tier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"tools": {
|
||||
@@ -9804,6 +9824,8 @@
|
||||
"preToolUse",
|
||||
"permissionRequest",
|
||||
"postToolUse",
|
||||
"preCompact",
|
||||
"postCompact",
|
||||
"sessionStart",
|
||||
"userPromptSubmit",
|
||||
"stop"
|
||||
@@ -10644,12 +10666,24 @@
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PostCompact": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2/ConfiguredHookMatcherGroup"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PostToolUse": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2/ConfiguredHookMatcherGroup"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PreCompact": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2/ConfiguredHookMatcherGroup"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PreToolUse": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2/ConfiguredHookMatcherGroup"
|
||||
@@ -10689,7 +10723,9 @@
|
||||
},
|
||||
"required": [
|
||||
"PermissionRequest",
|
||||
"PostCompact",
|
||||
"PostToolUse",
|
||||
"PreCompact",
|
||||
"PreToolUse",
|
||||
"SessionStart",
|
||||
"Stop",
|
||||
@@ -12108,6 +12144,12 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"hooks": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2/PluginHookSummary"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"marketplaceName": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -12139,6 +12181,7 @@
|
||||
},
|
||||
"required": [
|
||||
"apps",
|
||||
"hooks",
|
||||
"marketplaceName",
|
||||
"mcpServers",
|
||||
"skills",
|
||||
@@ -12146,6 +12189,21 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginHookSummary": {
|
||||
"properties": {
|
||||
"eventName": {
|
||||
"$ref": "#/definitions/v2/HookEventName"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"eventName",
|
||||
"key"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginInstallParams": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
@@ -12333,6 +12391,14 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginListMarketplaceKind": {
|
||||
"enum": [
|
||||
"local",
|
||||
"workspace-directory",
|
||||
"shared-with-me"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PluginListParams": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
@@ -12345,6 +12411,16 @@
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"marketplaceKinds": {
|
||||
"description": "Optional marketplace kind filter. When omitted, only local marketplaces are queried, plus the default remote catalog when enabled by feature flag.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2/PluginListMarketplaceKind"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"title": "PluginListParams",
|
||||
@@ -12461,6 +12537,29 @@
|
||||
"title": "PluginReadResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareContext": {
|
||||
"properties": {
|
||||
"creatorAccountUserId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"creatorName": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"remotePluginId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"remotePluginId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareDeleteParams": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
@@ -12479,6 +12578,14 @@
|
||||
"title": "PluginShareDeleteResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareDiscoverability": {
|
||||
"enum": [
|
||||
"LISTED",
|
||||
"UNLISTED",
|
||||
"PRIVATE"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PluginShareListItem": {
|
||||
"properties": {
|
||||
"localPluginPath": {
|
||||
@@ -12525,9 +12632,46 @@
|
||||
"title": "PluginShareListResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"PluginSharePrincipal": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"principalId": {
|
||||
"type": "string"
|
||||
},
|
||||
"principalType": {
|
||||
"$ref": "#/definitions/v2/PluginSharePrincipalType"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"principalId",
|
||||
"principalType"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginSharePrincipalType": {
|
||||
"enum": [
|
||||
"user",
|
||||
"group",
|
||||
"workspace"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PluginShareSaveParams": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"discoverability": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/PluginShareDiscoverability"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pluginPath": {
|
||||
"$ref": "#/definitions/v2/AbsolutePathBuf"
|
||||
},
|
||||
@@ -12536,6 +12680,15 @@
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"shareTargets": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2/PluginShareTarget"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -12561,6 +12714,57 @@
|
||||
"title": "PluginShareSaveResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareTarget": {
|
||||
"properties": {
|
||||
"principalId": {
|
||||
"type": "string"
|
||||
},
|
||||
"principalType": {
|
||||
"$ref": "#/definitions/v2/PluginSharePrincipalType"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"principalId",
|
||||
"principalType"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareUpdateTargetsParams": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"remotePluginId": {
|
||||
"type": "string"
|
||||
},
|
||||
"shareTargets": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2/PluginShareTarget"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"remotePluginId",
|
||||
"shareTargets"
|
||||
],
|
||||
"title": "PluginShareUpdateTargetsParams",
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareUpdateTargetsResponse": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"principals": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2/PluginSharePrincipal"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"principals"
|
||||
],
|
||||
"title": "PluginShareUpdateTargetsResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"PluginSkillReadParams": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
@@ -12710,9 +12914,27 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"keywords": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"shareContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/PluginShareContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Remote sharing context associated with this plugin when available."
|
||||
},
|
||||
"source": {
|
||||
"$ref": "#/definitions/v2/PluginSource"
|
||||
}
|
||||
@@ -12953,13 +13175,9 @@
|
||||
]
|
||||
},
|
||||
"service_tier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"tools": {
|
||||
@@ -14488,13 +14706,6 @@
|
||||
"title": "ServerRequestResolvedNotification",
|
||||
"type": "object"
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"SessionMigration": {
|
||||
"properties": {
|
||||
"cwd": {
|
||||
@@ -15209,6 +15420,10 @@
|
||||
"description": "Usually the first user message in the thread, if available.",
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"allOf": [
|
||||
{
|
||||
@@ -15225,6 +15440,17 @@
|
||||
],
|
||||
"description": "Current runtime status for the thread."
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional analytics source classification for this thread."
|
||||
},
|
||||
"turns": {
|
||||
"description": "Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` (when `includeTurns` is true) responses. For all other responses and notifications returning a Thread, the turns field will be an empty list.",
|
||||
"items": {
|
||||
@@ -15246,6 +15472,7 @@
|
||||
"id",
|
||||
"modelProvider",
|
||||
"preview",
|
||||
"sessionId",
|
||||
"source",
|
||||
"status",
|
||||
"turns",
|
||||
@@ -15421,24 +15648,24 @@
|
||||
]
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional client-supplied analytics source classification for this forked thread."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -15497,13 +15724,9 @@
|
||||
"description": "Legacy sandbox policy retained for compatibility. Experimental clients should prefer `permissionProfile` when they need exact runtime permissions."
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"thread": {
|
||||
@@ -16928,20 +17151,9 @@
|
||||
]
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"threadId": {
|
||||
@@ -17004,13 +17216,9 @@
|
||||
"description": "Legacy sandbox policy retained for compatibility. Experimental clients should prefer `permissionProfile` when they need exact runtime permissions."
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"thread": {
|
||||
@@ -17119,6 +17327,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadSourceKind": {
|
||||
"enum": [
|
||||
"cli",
|
||||
@@ -17228,20 +17444,9 @@
|
||||
]
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"sessionStartSource": {
|
||||
@@ -17253,6 +17458,17 @@
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional client-supplied analytics source classification for this thread."
|
||||
}
|
||||
},
|
||||
"title": "ThreadStartParams",
|
||||
@@ -17308,13 +17524,9 @@
|
||||
"description": "Legacy sandbox policy retained for compatibility. Experimental clients should prefer `permissionProfile` when they need exact runtime permissions."
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"thread": {
|
||||
@@ -17981,22 +18193,11 @@
|
||||
"description": "Override the sandbox policy for this turn and subsequent turns."
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Override the service tier for this turn and subsequent turns."
|
||||
"description": "Override the service tier for this turn and subsequent turns.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"anyOf": [
|
||||
@@ -18553,4 +18754,4 @@
|
||||
},
|
||||
"title": "CodexAppServerProtocol",
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
@@ -1569,6 +1569,30 @@
|
||||
"title": "Plugin/share/saveRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"plugin/share/updateTargets"
|
||||
],
|
||||
"title": "Plugin/share/updateTargetsRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/PluginShareUpdateTargetsParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Plugin/share/updateTargetsRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -3656,13 +3680,9 @@
|
||||
]
|
||||
},
|
||||
"service_tier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"tools": {
|
||||
@@ -6371,6 +6391,8 @@
|
||||
"preToolUse",
|
||||
"permissionRequest",
|
||||
"postToolUse",
|
||||
"preCompact",
|
||||
"postCompact",
|
||||
"sessionStart",
|
||||
"userPromptSubmit",
|
||||
"stop"
|
||||
@@ -7255,12 +7277,24 @@
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PostCompact": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PostToolUse": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PreCompact": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PreToolUse": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||
@@ -7300,7 +7334,9 @@
|
||||
},
|
||||
"required": [
|
||||
"PermissionRequest",
|
||||
"PostCompact",
|
||||
"PostToolUse",
|
||||
"PreCompact",
|
||||
"PreToolUse",
|
||||
"SessionStart",
|
||||
"Stop",
|
||||
@@ -8719,6 +8755,12 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"hooks": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/PluginHookSummary"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"marketplaceName": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -8750,6 +8792,7 @@
|
||||
},
|
||||
"required": [
|
||||
"apps",
|
||||
"hooks",
|
||||
"marketplaceName",
|
||||
"mcpServers",
|
||||
"skills",
|
||||
@@ -8757,6 +8800,21 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginHookSummary": {
|
||||
"properties": {
|
||||
"eventName": {
|
||||
"$ref": "#/definitions/HookEventName"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"eventName",
|
||||
"key"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginInstallParams": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
@@ -8944,6 +9002,14 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginListMarketplaceKind": {
|
||||
"enum": [
|
||||
"local",
|
||||
"workspace-directory",
|
||||
"shared-with-me"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PluginListParams": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
@@ -8956,6 +9022,16 @@
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"marketplaceKinds": {
|
||||
"description": "Optional marketplace kind filter. When omitted, only local marketplaces are queried, plus the default remote catalog when enabled by feature flag.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/PluginListMarketplaceKind"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"title": "PluginListParams",
|
||||
@@ -9072,6 +9148,29 @@
|
||||
"title": "PluginReadResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareContext": {
|
||||
"properties": {
|
||||
"creatorAccountUserId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"creatorName": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"remotePluginId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"remotePluginId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareDeleteParams": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
@@ -9090,6 +9189,14 @@
|
||||
"title": "PluginShareDeleteResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareDiscoverability": {
|
||||
"enum": [
|
||||
"LISTED",
|
||||
"UNLISTED",
|
||||
"PRIVATE"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PluginShareListItem": {
|
||||
"properties": {
|
||||
"localPluginPath": {
|
||||
@@ -9136,9 +9243,46 @@
|
||||
"title": "PluginShareListResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"PluginSharePrincipal": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"principalId": {
|
||||
"type": "string"
|
||||
},
|
||||
"principalType": {
|
||||
"$ref": "#/definitions/PluginSharePrincipalType"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"principalId",
|
||||
"principalType"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginSharePrincipalType": {
|
||||
"enum": [
|
||||
"user",
|
||||
"group",
|
||||
"workspace"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PluginShareSaveParams": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"discoverability": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/PluginShareDiscoverability"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pluginPath": {
|
||||
"$ref": "#/definitions/AbsolutePathBuf"
|
||||
},
|
||||
@@ -9147,6 +9291,15 @@
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"shareTargets": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/PluginShareTarget"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -9172,6 +9325,57 @@
|
||||
"title": "PluginShareSaveResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareTarget": {
|
||||
"properties": {
|
||||
"principalId": {
|
||||
"type": "string"
|
||||
},
|
||||
"principalType": {
|
||||
"$ref": "#/definitions/PluginSharePrincipalType"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"principalId",
|
||||
"principalType"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareUpdateTargetsParams": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"remotePluginId": {
|
||||
"type": "string"
|
||||
},
|
||||
"shareTargets": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/PluginShareTarget"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"remotePluginId",
|
||||
"shareTargets"
|
||||
],
|
||||
"title": "PluginShareUpdateTargetsParams",
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareUpdateTargetsResponse": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"principals": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/PluginSharePrincipal"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"principals"
|
||||
],
|
||||
"title": "PluginShareUpdateTargetsResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"PluginSkillReadParams": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
@@ -9321,9 +9525,27 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"keywords": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"shareContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/PluginShareContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Remote sharing context associated with this plugin when available."
|
||||
},
|
||||
"source": {
|
||||
"$ref": "#/definitions/PluginSource"
|
||||
}
|
||||
@@ -9564,13 +9786,9 @@
|
||||
]
|
||||
},
|
||||
"service_tier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"tools": {
|
||||
@@ -12374,13 +12592,6 @@
|
||||
"title": "ServerRequestResolvedNotification",
|
||||
"type": "object"
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"SessionMigration": {
|
||||
"properties": {
|
||||
"cwd": {
|
||||
@@ -13095,6 +13306,10 @@
|
||||
"description": "Usually the first user message in the thread, if available.",
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"allOf": [
|
||||
{
|
||||
@@ -13111,6 +13326,17 @@
|
||||
],
|
||||
"description": "Current runtime status for the thread."
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional analytics source classification for this thread."
|
||||
},
|
||||
"turns": {
|
||||
"description": "Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` (when `includeTurns` is true) responses. For all other responses and notifications returning a Thread, the turns field will be an empty list.",
|
||||
"items": {
|
||||
@@ -13132,6 +13358,7 @@
|
||||
"id",
|
||||
"modelProvider",
|
||||
"preview",
|
||||
"sessionId",
|
||||
"source",
|
||||
"status",
|
||||
"turns",
|
||||
@@ -13307,24 +13534,24 @@
|
||||
]
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional client-supplied analytics source classification for this forked thread."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -13383,13 +13610,9 @@
|
||||
"description": "Legacy sandbox policy retained for compatibility. Experimental clients should prefer `permissionProfile` when they need exact runtime permissions."
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"thread": {
|
||||
@@ -14814,20 +15037,9 @@
|
||||
]
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"threadId": {
|
||||
@@ -14890,13 +15102,9 @@
|
||||
"description": "Legacy sandbox policy retained for compatibility. Experimental clients should prefer `permissionProfile` when they need exact runtime permissions."
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"thread": {
|
||||
@@ -15005,6 +15213,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadSourceKind": {
|
||||
"enum": [
|
||||
"cli",
|
||||
@@ -15114,20 +15330,9 @@
|
||||
]
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"sessionStartSource": {
|
||||
@@ -15139,6 +15344,17 @@
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional client-supplied analytics source classification for this thread."
|
||||
}
|
||||
},
|
||||
"title": "ThreadStartParams",
|
||||
@@ -15194,13 +15410,9 @@
|
||||
"description": "Legacy sandbox policy retained for compatibility. Experimental clients should prefer `permissionProfile` when they need exact runtime permissions."
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"thread": {
|
||||
@@ -15867,22 +16079,11 @@
|
||||
"description": "Override the sandbox policy for this turn and subsequent turns."
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Override the service tier for this turn and subsequent turns."
|
||||
"description": "Override the service tier for this turn and subsequent turns.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"anyOf": [
|
||||
@@ -16438,4 +16639,4 @@
|
||||
},
|
||||
"title": "CodexAppServerProtocolV2",
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
@@ -352,13 +352,9 @@
|
||||
]
|
||||
},
|
||||
"service_tier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"tools": {
|
||||
@@ -658,13 +654,9 @@
|
||||
]
|
||||
},
|
||||
"service_tier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"tools": {
|
||||
@@ -754,13 +746,6 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ToolsV2": {
|
||||
"properties": {
|
||||
"view_image": {
|
||||
|
||||
@@ -213,12 +213,24 @@
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PostCompact": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PostToolUse": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PreCompact": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"PreToolUse": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||
@@ -258,7 +270,9 @@
|
||||
},
|
||||
"required": [
|
||||
"PermissionRequest",
|
||||
"PostCompact",
|
||||
"PostToolUse",
|
||||
"PreCompact",
|
||||
"PreToolUse",
|
||||
"SessionStart",
|
||||
"Stop",
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
"preToolUse",
|
||||
"permissionRequest",
|
||||
"postToolUse",
|
||||
"preCompact",
|
||||
"postCompact",
|
||||
"sessionStart",
|
||||
"userPromptSubmit",
|
||||
"stop"
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
"preToolUse",
|
||||
"permissionRequest",
|
||||
"postToolUse",
|
||||
"preCompact",
|
||||
"postCompact",
|
||||
"sessionStart",
|
||||
"userPromptSubmit",
|
||||
"stop"
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
"preToolUse",
|
||||
"permissionRequest",
|
||||
"postToolUse",
|
||||
"preCompact",
|
||||
"postCompact",
|
||||
"sessionStart",
|
||||
"userPromptSubmit",
|
||||
"stop"
|
||||
|
||||
@@ -1393,4 +1393,4 @@
|
||||
],
|
||||
"title": "ItemCompletedNotification",
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
@@ -1393,4 +1393,4 @@
|
||||
],
|
||||
"title": "ItemStartedNotification",
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,14 @@
|
||||
"AbsolutePathBuf": {
|
||||
"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"
|
||||
},
|
||||
"PluginListMarketplaceKind": {
|
||||
"enum": [
|
||||
"local",
|
||||
"workspace-directory",
|
||||
"shared-with-me"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
@@ -16,6 +24,16 @@
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"marketplaceKinds": {
|
||||
"description": "Optional marketplace kind filter. When omitted, only local marketplaces are queried, plus the default remote catalog when enabled by feature flag.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/PluginListMarketplaceKind"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"title": "PluginListParams",
|
||||
|
||||
@@ -232,6 +232,29 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareContext": {
|
||||
"properties": {
|
||||
"creatorAccountUserId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"creatorName": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"remotePluginId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"remotePluginId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginSource": {
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -347,9 +370,27 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"keywords": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"shareContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/PluginShareContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Remote sharing context associated with this plugin when available."
|
||||
},
|
||||
"source": {
|
||||
"$ref": "#/definitions/PluginSource"
|
||||
}
|
||||
|
||||
@@ -37,6 +37,19 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"HookEventName": {
|
||||
"enum": [
|
||||
"preToolUse",
|
||||
"permissionRequest",
|
||||
"postToolUse",
|
||||
"preCompact",
|
||||
"postCompact",
|
||||
"sessionStart",
|
||||
"userPromptSubmit",
|
||||
"stop"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PluginAuthPolicy": {
|
||||
"enum": [
|
||||
"ON_INSTALL",
|
||||
@@ -75,6 +88,12 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"hooks": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/PluginHookSummary"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"marketplaceName": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -106,6 +125,7 @@
|
||||
},
|
||||
"required": [
|
||||
"apps",
|
||||
"hooks",
|
||||
"marketplaceName",
|
||||
"mcpServers",
|
||||
"skills",
|
||||
@@ -113,6 +133,21 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginHookSummary": {
|
||||
"properties": {
|
||||
"eventName": {
|
||||
"$ref": "#/definitions/HookEventName"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"eventName",
|
||||
"key"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginInstallPolicy": {
|
||||
"enum": [
|
||||
"NOT_AVAILABLE",
|
||||
@@ -251,6 +286,29 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareContext": {
|
||||
"properties": {
|
||||
"creatorAccountUserId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"creatorName": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"remotePluginId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"remotePluginId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginSource": {
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -366,9 +424,27 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"keywords": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"shareContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/PluginShareContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Remote sharing context associated with this plugin when available."
|
||||
},
|
||||
"source": {
|
||||
"$ref": "#/definitions/PluginSource"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,29 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareContext": {
|
||||
"properties": {
|
||||
"creatorAccountUserId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"creatorName": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"remotePluginId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"remotePluginId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginShareListItem": {
|
||||
"properties": {
|
||||
"localPluginPath": {
|
||||
@@ -307,9 +330,27 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"keywords": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"shareContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/PluginShareContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Remote sharing context associated with this plugin when available."
|
||||
},
|
||||
"source": {
|
||||
"$ref": "#/definitions/PluginSource"
|
||||
}
|
||||
|
||||
@@ -4,9 +4,50 @@
|
||||
"AbsolutePathBuf": {
|
||||
"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"
|
||||
},
|
||||
"PluginShareDiscoverability": {
|
||||
"enum": [
|
||||
"LISTED",
|
||||
"UNLISTED",
|
||||
"PRIVATE"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PluginSharePrincipalType": {
|
||||
"enum": [
|
||||
"user",
|
||||
"group",
|
||||
"workspace"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PluginShareTarget": {
|
||||
"properties": {
|
||||
"principalId": {
|
||||
"type": "string"
|
||||
},
|
||||
"principalType": {
|
||||
"$ref": "#/definitions/PluginSharePrincipalType"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"principalId",
|
||||
"principalType"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"discoverability": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/PluginShareDiscoverability"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pluginPath": {
|
||||
"$ref": "#/definitions/AbsolutePathBuf"
|
||||
},
|
||||
@@ -15,6 +56,15 @@
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"shareTargets": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/PluginShareTarget"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
||||
45
codex-rs/app-server-protocol/schema/json/v2/PluginShareUpdateTargetsParams.json
generated
Normal file
45
codex-rs/app-server-protocol/schema/json/v2/PluginShareUpdateTargetsParams.json
generated
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"definitions": {
|
||||
"PluginSharePrincipalType": {
|
||||
"enum": [
|
||||
"user",
|
||||
"group",
|
||||
"workspace"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PluginShareTarget": {
|
||||
"properties": {
|
||||
"principalId": {
|
||||
"type": "string"
|
||||
},
|
||||
"principalType": {
|
||||
"$ref": "#/definitions/PluginSharePrincipalType"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"principalId",
|
||||
"principalType"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"remotePluginId": {
|
||||
"type": "string"
|
||||
},
|
||||
"shareTargets": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/PluginShareTarget"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"remotePluginId",
|
||||
"shareTargets"
|
||||
],
|
||||
"title": "PluginShareUpdateTargetsParams",
|
||||
"type": "object"
|
||||
}
|
||||
45
codex-rs/app-server-protocol/schema/json/v2/PluginShareUpdateTargetsResponse.json
generated
Normal file
45
codex-rs/app-server-protocol/schema/json/v2/PluginShareUpdateTargetsResponse.json
generated
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"definitions": {
|
||||
"PluginSharePrincipal": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"principalId": {
|
||||
"type": "string"
|
||||
},
|
||||
"principalType": {
|
||||
"$ref": "#/definitions/PluginSharePrincipalType"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"principalId",
|
||||
"principalType"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"PluginSharePrincipalType": {
|
||||
"enum": [
|
||||
"user",
|
||||
"group",
|
||||
"workspace"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"principals": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/PluginSharePrincipal"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"principals"
|
||||
],
|
||||
"title": "PluginShareUpdateTargetsResponse",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -131,10 +131,11 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ServiceTier": {
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"fast",
|
||||
"flex"
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
@@ -214,24 +215,24 @@
|
||||
]
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional client-supplied analytics source classification for this forked thread."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
||||
@@ -1177,13 +1177,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"SessionSource": {
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -1403,6 +1396,10 @@
|
||||
"description": "Usually the first user message in the thread, if available.",
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"allOf": [
|
||||
{
|
||||
@@ -1419,6 +1416,17 @@
|
||||
],
|
||||
"description": "Current runtime status for the thread."
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional analytics source classification for this thread."
|
||||
},
|
||||
"turns": {
|
||||
"description": "Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` (when `includeTurns` is true) responses. For all other responses and notifications returning a Thread, the turns field will be an empty list.",
|
||||
"items": {
|
||||
@@ -1440,6 +1448,7 @@
|
||||
"id",
|
||||
"modelProvider",
|
||||
"preview",
|
||||
"sessionId",
|
||||
"source",
|
||||
"status",
|
||||
"turns",
|
||||
@@ -2117,6 +2126,14 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadStatus": {
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -2591,13 +2608,9 @@
|
||||
"description": "Legacy sandbox policy retained for compatibility. Experimental clients should prefer `permissionProfile` when they need exact runtime permissions."
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"thread": {
|
||||
|
||||
@@ -853,6 +853,10 @@
|
||||
"description": "Usually the first user message in the thread, if available.",
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"allOf": [
|
||||
{
|
||||
@@ -869,6 +873,17 @@
|
||||
],
|
||||
"description": "Current runtime status for the thread."
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional analytics source classification for this thread."
|
||||
},
|
||||
"turns": {
|
||||
"description": "Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` (when `includeTurns` is true) responses. For all other responses and notifications returning a Thread, the turns field will be an empty list.",
|
||||
"items": {
|
||||
@@ -890,6 +905,7 @@
|
||||
"id",
|
||||
"modelProvider",
|
||||
"preview",
|
||||
"sessionId",
|
||||
"source",
|
||||
"status",
|
||||
"turns",
|
||||
@@ -1567,6 +1583,14 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadStatus": {
|
||||
"oneOf": [
|
||||
{
|
||||
|
||||
@@ -853,6 +853,10 @@
|
||||
"description": "Usually the first user message in the thread, if available.",
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"allOf": [
|
||||
{
|
||||
@@ -869,6 +873,17 @@
|
||||
],
|
||||
"description": "Current runtime status for the thread."
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional analytics source classification for this thread."
|
||||
},
|
||||
"turns": {
|
||||
"description": "Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` (when `includeTurns` is true) responses. For all other responses and notifications returning a Thread, the turns field will be an empty list.",
|
||||
"items": {
|
||||
@@ -890,6 +905,7 @@
|
||||
"id",
|
||||
"modelProvider",
|
||||
"preview",
|
||||
"sessionId",
|
||||
"source",
|
||||
"status",
|
||||
"turns",
|
||||
@@ -1567,6 +1583,14 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadStatus": {
|
||||
"oneOf": [
|
||||
{
|
||||
|
||||
@@ -853,6 +853,10 @@
|
||||
"description": "Usually the first user message in the thread, if available.",
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"allOf": [
|
||||
{
|
||||
@@ -869,6 +873,17 @@
|
||||
],
|
||||
"description": "Current runtime status for the thread."
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional analytics source classification for this thread."
|
||||
},
|
||||
"turns": {
|
||||
"description": "Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` (when `includeTurns` is true) responses. For all other responses and notifications returning a Thread, the turns field will be an empty list.",
|
||||
"items": {
|
||||
@@ -890,6 +905,7 @@
|
||||
"id",
|
||||
"modelProvider",
|
||||
"preview",
|
||||
"sessionId",
|
||||
"source",
|
||||
"status",
|
||||
"turns",
|
||||
@@ -1567,6 +1583,14 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadStatus": {
|
||||
"oneOf": [
|
||||
{
|
||||
|
||||
@@ -1010,13 +1010,6 @@
|
||||
"danger-full-access"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"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.",
|
||||
@@ -1101,20 +1094,9 @@
|
||||
]
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"threadId": {
|
||||
|
||||
@@ -1177,13 +1177,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"SessionSource": {
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -1403,6 +1396,10 @@
|
||||
"description": "Usually the first user message in the thread, if available.",
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"allOf": [
|
||||
{
|
||||
@@ -1419,6 +1416,17 @@
|
||||
],
|
||||
"description": "Current runtime status for the thread."
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional analytics source classification for this thread."
|
||||
},
|
||||
"turns": {
|
||||
"description": "Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` (when `includeTurns` is true) responses. For all other responses and notifications returning a Thread, the turns field will be an empty list.",
|
||||
"items": {
|
||||
@@ -1440,6 +1448,7 @@
|
||||
"id",
|
||||
"modelProvider",
|
||||
"preview",
|
||||
"sessionId",
|
||||
"source",
|
||||
"status",
|
||||
"turns",
|
||||
@@ -2117,6 +2126,14 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadStatus": {
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -2591,13 +2608,9 @@
|
||||
"description": "Legacy sandbox policy retained for compatibility. Experimental clients should prefer `permissionProfile` when they need exact runtime permissions."
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"thread": {
|
||||
|
||||
@@ -853,6 +853,10 @@
|
||||
"description": "Usually the first user message in the thread, if available.",
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"allOf": [
|
||||
{
|
||||
@@ -869,6 +873,17 @@
|
||||
],
|
||||
"description": "Current runtime status for the thread."
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional analytics source classification for this thread."
|
||||
},
|
||||
"turns": {
|
||||
"description": "Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` (when `includeTurns` is true) responses. For all other responses and notifications returning a Thread, the turns field will be an empty list.",
|
||||
"items": {
|
||||
@@ -890,6 +905,7 @@
|
||||
"id",
|
||||
"modelProvider",
|
||||
"preview",
|
||||
"sessionId",
|
||||
"source",
|
||||
"status",
|
||||
"turns",
|
||||
@@ -1567,6 +1583,14 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadStatus": {
|
||||
"oneOf": [
|
||||
{
|
||||
|
||||
@@ -165,10 +165,11 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ServiceTier": {
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"fast",
|
||||
"flex"
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -287,20 +288,9 @@
|
||||
]
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"sessionStartSource": {
|
||||
@@ -312,6 +302,17 @@
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional client-supplied analytics source classification for this thread."
|
||||
}
|
||||
},
|
||||
"title": "ThreadStartParams",
|
||||
|
||||
@@ -1177,13 +1177,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"SessionSource": {
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -1403,6 +1396,10 @@
|
||||
"description": "Usually the first user message in the thread, if available.",
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"allOf": [
|
||||
{
|
||||
@@ -1419,6 +1416,17 @@
|
||||
],
|
||||
"description": "Current runtime status for the thread."
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional analytics source classification for this thread."
|
||||
},
|
||||
"turns": {
|
||||
"description": "Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` (when `includeTurns` is true) responses. For all other responses and notifications returning a Thread, the turns field will be an empty list.",
|
||||
"items": {
|
||||
@@ -1440,6 +1448,7 @@
|
||||
"id",
|
||||
"modelProvider",
|
||||
"preview",
|
||||
"sessionId",
|
||||
"source",
|
||||
"status",
|
||||
"turns",
|
||||
@@ -2117,6 +2126,14 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadStatus": {
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -2591,13 +2608,9 @@
|
||||
"description": "Legacy sandbox policy retained for compatibility. Experimental clients should prefer `permissionProfile` when they need exact runtime permissions."
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"thread": {
|
||||
|
||||
@@ -853,6 +853,10 @@
|
||||
"description": "Usually the first user message in the thread, if available.",
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"allOf": [
|
||||
{
|
||||
@@ -869,6 +873,17 @@
|
||||
],
|
||||
"description": "Current runtime status for the thread."
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional analytics source classification for this thread."
|
||||
},
|
||||
"turns": {
|
||||
"description": "Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` (when `includeTurns` is true) responses. For all other responses and notifications returning a Thread, the turns field will be an empty list.",
|
||||
"items": {
|
||||
@@ -890,6 +905,7 @@
|
||||
"id",
|
||||
"modelProvider",
|
||||
"preview",
|
||||
"sessionId",
|
||||
"source",
|
||||
"status",
|
||||
"turns",
|
||||
@@ -1567,6 +1583,14 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadStatus": {
|
||||
"oneOf": [
|
||||
{
|
||||
|
||||
@@ -853,6 +853,10 @@
|
||||
"description": "Usually the first user message in the thread, if available.",
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"allOf": [
|
||||
{
|
||||
@@ -869,6 +873,17 @@
|
||||
],
|
||||
"description": "Current runtime status for the thread."
|
||||
},
|
||||
"threadSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Optional analytics source classification for this thread."
|
||||
},
|
||||
"turns": {
|
||||
"description": "Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` (when `includeTurns` is true) responses. For all other responses and notifications returning a Thread, the turns field will be an empty list.",
|
||||
"items": {
|
||||
@@ -890,6 +905,7 @@
|
||||
"id",
|
||||
"modelProvider",
|
||||
"preview",
|
||||
"sessionId",
|
||||
"source",
|
||||
"status",
|
||||
"turns",
|
||||
@@ -1567,6 +1583,14 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreadSource": {
|
||||
"enum": [
|
||||
"user",
|
||||
"subagent",
|
||||
"memory_consolidation"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadStatus": {
|
||||
"oneOf": [
|
||||
{
|
||||
|
||||
@@ -312,13 +312,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"Settings": {
|
||||
"description": "Settings for a collaboration mode.",
|
||||
"properties": {
|
||||
@@ -586,22 +579,11 @@
|
||||
"description": "Override the sandbox policy for this turn and subsequent turns."
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Override the service tier for this turn and subsequent turns."
|
||||
"description": "Override the service tier for this turn and subsequent turns.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"anyOf": [
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -64,7 +64,6 @@ export type { ResponseItem } from "./ResponseItem";
|
||||
export type { ReviewDecision } from "./ReviewDecision";
|
||||
export type { ServerNotification } from "./ServerNotification";
|
||||
export type { ServerRequest } from "./ServerRequest";
|
||||
export type { ServiceTier } from "./ServiceTier";
|
||||
export type { SessionSource } from "./SessionSource";
|
||||
export type { Settings } from "./Settings";
|
||||
export type { SubAgentSource } from "./SubAgentSource";
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import type { ForcedLoginMethod } from "../ForcedLoginMethod";
|
||||
import type { ReasoningEffort } from "../ReasoningEffort";
|
||||
import type { ReasoningSummary } from "../ReasoningSummary";
|
||||
import type { ServiceTier } from "../ServiceTier";
|
||||
import type { Verbosity } from "../Verbosity";
|
||||
import type { WebSearchMode } from "../WebSearchMode";
|
||||
import type { JsonValue } from "../serde_json/JsonValue";
|
||||
@@ -20,4 +19,4 @@ export type Config = {model: string | null, review_model: string | null, model_c
|
||||
* [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: string | null, analytics: AnalyticsConfig | null} & ({ [key in string]?: number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | 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 HookEventName = "preToolUse" | "permissionRequest" | "postToolUse" | "sessionStart" | "userPromptSubmit" | "stop";
|
||||
export type HookEventName = "preToolUse" | "permissionRequest" | "postToolUse" | "preCompact" | "postCompact" | "sessionStart" | "userPromptSubmit" | "stop";
|
||||
|
||||
@@ -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 { ConfiguredHookMatcherGroup } from "./ConfiguredHookMatcherGroup";
|
||||
|
||||
export type ManagedHooksRequirements = { managedDir: string | null, windowsManagedDir: string | null, PreToolUse: Array<ConfiguredHookMatcherGroup>, PermissionRequest: Array<ConfiguredHookMatcherGroup>, PostToolUse: Array<ConfiguredHookMatcherGroup>, SessionStart: Array<ConfiguredHookMatcherGroup>, UserPromptSubmit: Array<ConfiguredHookMatcherGroup>, Stop: Array<ConfiguredHookMatcherGroup>, };
|
||||
export type ManagedHooksRequirements = { managedDir: string | null, windowsManagedDir: string | null, PreToolUse: Array<ConfiguredHookMatcherGroup>, PermissionRequest: Array<ConfiguredHookMatcherGroup>, PostToolUse: Array<ConfiguredHookMatcherGroup>, PreCompact: Array<ConfiguredHookMatcherGroup>, PostCompact: Array<ConfiguredHookMatcherGroup>, SessionStart: Array<ConfiguredHookMatcherGroup>, UserPromptSubmit: Array<ConfiguredHookMatcherGroup>, Stop: Array<ConfiguredHookMatcherGroup>, };
|
||||
|
||||
@@ -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 { AbsolutePathBuf } from "../AbsolutePathBuf";
|
||||
import type { AppSummary } from "./AppSummary";
|
||||
import type { PluginHookSummary } from "./PluginHookSummary";
|
||||
import type { PluginSummary } from "./PluginSummary";
|
||||
import type { SkillSummary } from "./SkillSummary";
|
||||
|
||||
export type PluginDetail = { marketplaceName: string, marketplacePath: AbsolutePathBuf | null, summary: PluginSummary, description: string | null, skills: Array<SkillSummary>, apps: Array<AppSummary>, mcpServers: Array<string>, };
|
||||
export type PluginDetail = { marketplaceName: string, marketplacePath: AbsolutePathBuf | null, summary: PluginSummary, description: string | null, skills: Array<SkillSummary>, hooks: Array<PluginHookSummary>, apps: Array<AppSummary>, mcpServers: Array<string>, };
|
||||
|
||||
6
codex-rs/app-server-protocol/schema/typescript/v2/PluginHookSummary.ts
generated
Normal file
6
codex-rs/app-server-protocol/schema/typescript/v2/PluginHookSummary.ts
generated
Normal file
@@ -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 { HookEventName } from "./HookEventName";
|
||||
|
||||
export type PluginHookSummary = { key: string, eventName: HookEventName, };
|
||||
5
codex-rs/app-server-protocol/schema/typescript/v2/PluginListMarketplaceKind.ts
generated
Normal file
5
codex-rs/app-server-protocol/schema/typescript/v2/PluginListMarketplaceKind.ts
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
// GENERATED CODE! DO NOT MODIFY BY HAND!
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type PluginListMarketplaceKind = "local" | "workspace-directory" | "shared-with-me";
|
||||
@@ -2,10 +2,16 @@
|
||||
|
||||
// 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 { PluginListMarketplaceKind } from "./PluginListMarketplaceKind";
|
||||
|
||||
export type PluginListParams = {
|
||||
/**
|
||||
* Optional working directories used to discover repo marketplaces. When omitted,
|
||||
* only home-scoped marketplaces and the official curated marketplace are considered.
|
||||
*/
|
||||
cwds?: Array<AbsolutePathBuf> | null, };
|
||||
cwds?: Array<AbsolutePathBuf> | null,
|
||||
/**
|
||||
* Optional marketplace kind filter. When omitted, only local marketplaces are queried, plus
|
||||
* the default remote catalog when enabled by feature flag.
|
||||
*/
|
||||
marketplaceKinds?: Array<PluginListMarketplaceKind> | null, };
|
||||
|
||||
5
codex-rs/app-server-protocol/schema/typescript/v2/PluginShareContext.ts
generated
Normal file
5
codex-rs/app-server-protocol/schema/typescript/v2/PluginShareContext.ts
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
// GENERATED CODE! DO NOT MODIFY BY HAND!
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type PluginShareContext = { remotePluginId: string, creatorAccountUserId: string | null, creatorName: string | null, };
|
||||
5
codex-rs/app-server-protocol/schema/typescript/v2/PluginShareDiscoverability.ts
generated
Normal file
5
codex-rs/app-server-protocol/schema/typescript/v2/PluginShareDiscoverability.ts
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
// GENERATED CODE! DO NOT MODIFY BY HAND!
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type PluginShareDiscoverability = "LISTED" | "UNLISTED" | "PRIVATE";
|
||||
6
codex-rs/app-server-protocol/schema/typescript/v2/PluginSharePrincipal.ts
generated
Normal file
6
codex-rs/app-server-protocol/schema/typescript/v2/PluginSharePrincipal.ts
generated
Normal file
@@ -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 { PluginSharePrincipalType } from "./PluginSharePrincipalType";
|
||||
|
||||
export type PluginSharePrincipal = { principalType: PluginSharePrincipalType, principalId: string, name: 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 ServiceTier = "fast" | "flex";
|
||||
export type PluginSharePrincipalType = "user" | "group" | "workspace";
|
||||
@@ -2,5 +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 { PluginShareDiscoverability } from "./PluginShareDiscoverability";
|
||||
import type { PluginShareTarget } from "./PluginShareTarget";
|
||||
|
||||
export type PluginShareSaveParams = { pluginPath: AbsolutePathBuf, remotePluginId?: string | null, };
|
||||
export type PluginShareSaveParams = { pluginPath: AbsolutePathBuf, remotePluginId?: string | null, discoverability?: PluginShareDiscoverability | null, shareTargets?: Array<PluginShareTarget> | null, };
|
||||
|
||||
6
codex-rs/app-server-protocol/schema/typescript/v2/PluginShareTarget.ts
generated
Normal file
6
codex-rs/app-server-protocol/schema/typescript/v2/PluginShareTarget.ts
generated
Normal file
@@ -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 { PluginSharePrincipalType } from "./PluginSharePrincipalType";
|
||||
|
||||
export type PluginShareTarget = { principalType: PluginSharePrincipalType, principalId: string, };
|
||||
6
codex-rs/app-server-protocol/schema/typescript/v2/PluginShareUpdateTargetsParams.ts
generated
Normal file
6
codex-rs/app-server-protocol/schema/typescript/v2/PluginShareUpdateTargetsParams.ts
generated
Normal file
@@ -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 { PluginShareTarget } from "./PluginShareTarget";
|
||||
|
||||
export type PluginShareUpdateTargetsParams = { remotePluginId: string, shareTargets: Array<PluginShareTarget>, };
|
||||
6
codex-rs/app-server-protocol/schema/typescript/v2/PluginShareUpdateTargetsResponse.ts
generated
Normal file
6
codex-rs/app-server-protocol/schema/typescript/v2/PluginShareUpdateTargetsResponse.ts
generated
Normal file
@@ -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 { PluginSharePrincipal } from "./PluginSharePrincipal";
|
||||
|
||||
export type PluginShareUpdateTargetsResponse = { principals: Array<PluginSharePrincipal>, };
|
||||
@@ -5,10 +5,15 @@ import type { PluginAuthPolicy } from "./PluginAuthPolicy";
|
||||
import type { PluginAvailability } from "./PluginAvailability";
|
||||
import type { PluginInstallPolicy } from "./PluginInstallPolicy";
|
||||
import type { PluginInterface } from "./PluginInterface";
|
||||
import type { PluginShareContext } from "./PluginShareContext";
|
||||
import type { PluginSource } from "./PluginSource";
|
||||
|
||||
export type PluginSummary = { id: string, name: string, source: PluginSource, installed: boolean, enabled: boolean, installPolicy: PluginInstallPolicy, authPolicy: PluginAuthPolicy,
|
||||
export type PluginSummary = { id: string, name: string,
|
||||
/**
|
||||
* Remote sharing context associated with this plugin when available.
|
||||
*/
|
||||
shareContext: PluginShareContext | null, source: PluginSource, installed: boolean, enabled: boolean, installPolicy: PluginInstallPolicy, authPolicy: PluginAuthPolicy,
|
||||
/**
|
||||
* Availability state for installing and using the plugin.
|
||||
*/
|
||||
availability: PluginAvailability, interface: PluginInterface | null, };
|
||||
availability: PluginAvailability, interface: PluginInterface | null, keywords: Array<string>, };
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ReasoningEffort } from "../ReasoningEffort";
|
||||
import type { ReasoningSummary } from "../ReasoningSummary";
|
||||
import type { ServiceTier } from "../ServiceTier";
|
||||
import type { Verbosity } from "../Verbosity";
|
||||
import type { WebSearchMode } from "../WebSearchMode";
|
||||
import type { JsonValue } from "../serde_json/JsonValue";
|
||||
@@ -16,4 +15,4 @@ export type ProfileV2 = {model: string | null, model_provider: string | null, ap
|
||||
* 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: string | 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 });
|
||||
|
||||
@@ -4,10 +4,15 @@
|
||||
import type { AbsolutePathBuf } from "../AbsolutePathBuf";
|
||||
import type { GitInfo } from "./GitInfo";
|
||||
import type { SessionSource } from "./SessionSource";
|
||||
import type { ThreadSource } from "./ThreadSource";
|
||||
import type { ThreadStatus } from "./ThreadStatus";
|
||||
import type { Turn } from "./Turn";
|
||||
|
||||
export type Thread = { id: string,
|
||||
/**
|
||||
* Session id shared by threads that belong to the same session tree.
|
||||
*/
|
||||
sessionId: string,
|
||||
/**
|
||||
* Source thread id when this thread was created by forking another thread.
|
||||
*/
|
||||
@@ -52,6 +57,10 @@ cliVersion: string,
|
||||
* Origin of the thread (CLI, VSCode, codex exec, codex app-server, etc.).
|
||||
*/
|
||||
source: SessionSource,
|
||||
/**
|
||||
* Optional analytics source classification for this thread.
|
||||
*/
|
||||
threadSource: ThreadSource | null,
|
||||
/**
|
||||
* Optional random unique nickname assigned to an AgentControl-spawned sub-agent.
|
||||
*/
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// 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 { ServiceTier } from "../ServiceTier";
|
||||
import type { JsonValue } from "../serde_json/JsonValue";
|
||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
import type { SandboxMode } from "./SandboxMode";
|
||||
import type { ThreadSource } from "./ThreadSource";
|
||||
|
||||
/**
|
||||
* There are two ways to fork a thread:
|
||||
@@ -19,8 +19,11 @@ import type { SandboxMode } from "./SandboxMode";
|
||||
export type ThreadForkParams = {threadId: string, /**
|
||||
* 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?: string | 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, /**
|
||||
* Optional client-supplied analytics source classification for this forked thread.
|
||||
*/
|
||||
threadSource?: ThreadSource | null};
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
// 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 { ReasoningEffort } from "../ReasoningEffort";
|
||||
import type { ServiceTier } from "../ServiceTier";
|
||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
import type { SandboxPolicy } from "./SandboxPolicy";
|
||||
import type { Thread } from "./Thread";
|
||||
|
||||
export type ThreadForkResponse = {thread: Thread, model: string, modelProvider: string, serviceTier: ServiceTier | null, cwd: AbsolutePathBuf, /**
|
||||
export type ThreadForkResponse = {thread: Thread, model: string, modelProvider: string, serviceTier: string | null, cwd: AbsolutePathBuf, /**
|
||||
* Instruction source files currently loaded for this thread.
|
||||
*/
|
||||
instructionSources: Array<AbsolutePathBuf>, approvalPolicy: AskForApproval, /**
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Personality } from "../Personality";
|
||||
import type { ServiceTier } from "../ServiceTier";
|
||||
import type { JsonValue } from "../serde_json/JsonValue";
|
||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
@@ -22,7 +21,7 @@ import type { SandboxMode } from "./SandboxMode";
|
||||
export type ThreadResumeParams = {threadId: string, /**
|
||||
* 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?: string | null | null, cwd?: string | null, approvalPolicy?: AskForApproval | null, /**
|
||||
* Override where approval requests are routed for review on this thread
|
||||
* and subsequent turns.
|
||||
*/
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
// 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 { ReasoningEffort } from "../ReasoningEffort";
|
||||
import type { ServiceTier } from "../ServiceTier";
|
||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
import type { SandboxPolicy } from "./SandboxPolicy";
|
||||
import type { Thread } from "./Thread";
|
||||
|
||||
export type ThreadResumeResponse = {thread: Thread, model: string, modelProvider: string, serviceTier: ServiceTier | null, cwd: AbsolutePathBuf, /**
|
||||
export type ThreadResumeResponse = {thread: Thread, model: string, modelProvider: string, serviceTier: string | null, cwd: AbsolutePathBuf, /**
|
||||
* Instruction source files currently loaded for this thread.
|
||||
*/
|
||||
instructionSources: Array<AbsolutePathBuf>, approvalPolicy: AskForApproval, /**
|
||||
|
||||
5
codex-rs/app-server-protocol/schema/typescript/v2/ThreadSource.ts
generated
Normal file
5
codex-rs/app-server-protocol/schema/typescript/v2/ThreadSource.ts
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
// GENERATED CODE! DO NOT MODIFY BY HAND!
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ThreadSource = "user" | "subagent" | "memory_consolidation";
|
||||
@@ -2,15 +2,18 @@
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Personality } from "../Personality";
|
||||
import type { ServiceTier } from "../ServiceTier";
|
||||
import type { JsonValue } from "../serde_json/JsonValue";
|
||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
import type { SandboxMode } from "./SandboxMode";
|
||||
import type { ThreadSource } from "./ThreadSource";
|
||||
import type { ThreadStartSource } from "./ThreadStartSource";
|
||||
|
||||
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?: string | 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, sessionStartSource?: ThreadStartSource | 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, sessionStartSource?: ThreadStartSource | null, /**
|
||||
* Optional client-supplied analytics source classification for this thread.
|
||||
*/
|
||||
threadSource?: ThreadSource | null};
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
// 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 { ReasoningEffort } from "../ReasoningEffort";
|
||||
import type { ServiceTier } from "../ServiceTier";
|
||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
import type { SandboxPolicy } from "./SandboxPolicy";
|
||||
import type { Thread } from "./Thread";
|
||||
|
||||
export type ThreadStartResponse = {thread: Thread, model: string, modelProvider: string, serviceTier: ServiceTier | null, cwd: AbsolutePathBuf, /**
|
||||
export type ThreadStartResponse = {thread: Thread, model: string, modelProvider: string, serviceTier: string | null, cwd: AbsolutePathBuf, /**
|
||||
* Instruction source files currently loaded for this thread.
|
||||
*/
|
||||
instructionSources: Array<AbsolutePathBuf>, approvalPolicy: AskForApproval, /**
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import type { Personality } from "../Personality";
|
||||
import type { ReasoningEffort } from "../ReasoningEffort";
|
||||
import type { ReasoningSummary } from "../ReasoningSummary";
|
||||
import type { ServiceTier } from "../ServiceTier";
|
||||
import type { JsonValue } from "../serde_json/JsonValue";
|
||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
@@ -30,7 +29,7 @@ sandboxPolicy?: SandboxPolicy | null, /**
|
||||
model?: string | null, /**
|
||||
* Override the service tier for this turn and subsequent turns.
|
||||
*/
|
||||
serviceTier?: ServiceTier | null | null, /**
|
||||
serviceTier?: string | null | null, /**
|
||||
* Override the reasoning effort for this turn and subsequent turns.
|
||||
*/
|
||||
effort?: ReasoningEffort | null, /**
|
||||
|
||||
@@ -274,22 +274,31 @@ export type { PlanDeltaNotification } from "./PlanDeltaNotification";
|
||||
export type { PluginAuthPolicy } from "./PluginAuthPolicy";
|
||||
export type { PluginAvailability } from "./PluginAvailability";
|
||||
export type { PluginDetail } from "./PluginDetail";
|
||||
export type { PluginHookSummary } from "./PluginHookSummary";
|
||||
export type { PluginInstallParams } from "./PluginInstallParams";
|
||||
export type { PluginInstallPolicy } from "./PluginInstallPolicy";
|
||||
export type { PluginInstallResponse } from "./PluginInstallResponse";
|
||||
export type { PluginInterface } from "./PluginInterface";
|
||||
export type { PluginListMarketplaceKind } from "./PluginListMarketplaceKind";
|
||||
export type { PluginListParams } from "./PluginListParams";
|
||||
export type { PluginListResponse } from "./PluginListResponse";
|
||||
export type { PluginMarketplaceEntry } from "./PluginMarketplaceEntry";
|
||||
export type { PluginReadParams } from "./PluginReadParams";
|
||||
export type { PluginReadResponse } from "./PluginReadResponse";
|
||||
export type { PluginShareContext } from "./PluginShareContext";
|
||||
export type { PluginShareDeleteParams } from "./PluginShareDeleteParams";
|
||||
export type { PluginShareDeleteResponse } from "./PluginShareDeleteResponse";
|
||||
export type { PluginShareDiscoverability } from "./PluginShareDiscoverability";
|
||||
export type { PluginShareListItem } from "./PluginShareListItem";
|
||||
export type { PluginShareListParams } from "./PluginShareListParams";
|
||||
export type { PluginShareListResponse } from "./PluginShareListResponse";
|
||||
export type { PluginSharePrincipal } from "./PluginSharePrincipal";
|
||||
export type { PluginSharePrincipalType } from "./PluginSharePrincipalType";
|
||||
export type { PluginShareSaveParams } from "./PluginShareSaveParams";
|
||||
export type { PluginShareSaveResponse } from "./PluginShareSaveResponse";
|
||||
export type { PluginShareTarget } from "./PluginShareTarget";
|
||||
export type { PluginShareUpdateTargetsParams } from "./PluginShareUpdateTargetsParams";
|
||||
export type { PluginShareUpdateTargetsResponse } from "./PluginShareUpdateTargetsResponse";
|
||||
export type { PluginSkillReadParams } from "./PluginSkillReadParams";
|
||||
export type { PluginSkillReadResponse } from "./PluginSkillReadResponse";
|
||||
export type { PluginSource } from "./PluginSource";
|
||||
@@ -396,6 +405,7 @@ export type { ThreadSetNameResponse } from "./ThreadSetNameResponse";
|
||||
export type { ThreadShellCommandParams } from "./ThreadShellCommandParams";
|
||||
export type { ThreadShellCommandResponse } from "./ThreadShellCommandResponse";
|
||||
export type { ThreadSortKey } from "./ThreadSortKey";
|
||||
export type { ThreadSource } from "./ThreadSource";
|
||||
export type { ThreadSourceKind } from "./ThreadSourceKind";
|
||||
export type { ThreadStartParams } from "./ThreadStartParams";
|
||||
export type { ThreadStartResponse } from "./ThreadStartResponse";
|
||||
|
||||
@@ -77,6 +77,7 @@ macro_rules! experimental_type_entry {
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ClientRequestSerializationScope {
|
||||
Global(&'static str),
|
||||
GlobalSharedRead(&'static str),
|
||||
Thread { thread_id: String },
|
||||
ThreadPath { path: PathBuf },
|
||||
CommandExecProcess { process_id: String },
|
||||
@@ -93,6 +94,9 @@ macro_rules! serialization_scope_expr {
|
||||
($actual_params:ident, global($key:literal)) => {
|
||||
Some(ClientRequestSerializationScope::Global($key))
|
||||
};
|
||||
($actual_params:ident, global_shared_read($key:literal)) => {
|
||||
Some(ClientRequestSerializationScope::GlobalSharedRead($key))
|
||||
};
|
||||
($actual_params:ident, thread_id($params:ident . $field:ident)) => {
|
||||
Some(ClientRequestSerializationScope::Thread {
|
||||
thread_id: $actual_params.$field.clone(),
|
||||
@@ -585,7 +589,7 @@ client_request_definitions! {
|
||||
},
|
||||
SkillsList => "skills/list" {
|
||||
params: v2::SkillsListParams,
|
||||
serialization: global("config"),
|
||||
serialization: global_shared_read("config"),
|
||||
response: v2::SkillsListResponse,
|
||||
},
|
||||
HooksList => "hooks/list" {
|
||||
@@ -610,7 +614,7 @@ client_request_definitions! {
|
||||
},
|
||||
PluginList => "plugin/list" {
|
||||
params: v2::PluginListParams,
|
||||
serialization: global("config"),
|
||||
serialization: global_shared_read("config"),
|
||||
response: v2::PluginListResponse,
|
||||
},
|
||||
PluginRead => "plugin/read" {
|
||||
@@ -628,6 +632,11 @@ client_request_definitions! {
|
||||
serialization: global("config"),
|
||||
response: v2::PluginShareSaveResponse,
|
||||
},
|
||||
PluginShareUpdateTargets => "plugin/share/updateTargets" {
|
||||
params: v2::PluginShareUpdateTargetsParams,
|
||||
serialization: global("config"),
|
||||
response: v2::PluginShareUpdateTargetsResponse,
|
||||
},
|
||||
PluginShareList => "plugin/share/list" {
|
||||
params: v2::PluginShareListParams,
|
||||
serialization: global("config"),
|
||||
@@ -942,7 +951,7 @@ client_request_definitions! {
|
||||
|
||||
ConfigRead => "config/read" {
|
||||
params: v2::ConfigReadParams,
|
||||
serialization: global("config"),
|
||||
serialization: global_shared_read("config"),
|
||||
response: v2::ConfigReadResponse,
|
||||
},
|
||||
ExternalAgentConfigDetect => "externalAgentConfig/detect" {
|
||||
@@ -1650,6 +1659,31 @@ mod tests {
|
||||
Some(ClientRequestSerializationScope::Global("config"))
|
||||
);
|
||||
|
||||
let skills_list = ClientRequest::SkillsList {
|
||||
request_id: request_id(),
|
||||
params: v2::SkillsListParams {
|
||||
cwds: Vec::new(),
|
||||
force_reload: false,
|
||||
per_cwd_extra_user_roots: None,
|
||||
},
|
||||
};
|
||||
assert_eq!(
|
||||
skills_list.serialization_scope(),
|
||||
Some(ClientRequestSerializationScope::GlobalSharedRead("config"))
|
||||
);
|
||||
|
||||
let plugin_list = ClientRequest::PluginList {
|
||||
request_id: request_id(),
|
||||
params: v2::PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
},
|
||||
};
|
||||
assert_eq!(
|
||||
plugin_list.serialization_scope(),
|
||||
Some(ClientRequestSerializationScope::GlobalSharedRead("config"))
|
||||
);
|
||||
|
||||
let plugin_uninstall = ClientRequest::PluginUninstall {
|
||||
request_id: request_id(),
|
||||
params: v2::PluginUninstallParams {
|
||||
@@ -1700,7 +1734,7 @@ mod tests {
|
||||
};
|
||||
assert_eq!(
|
||||
config_read.serialization_scope(),
|
||||
Some(ClientRequestSerializationScope::Global("config"))
|
||||
Some(ClientRequestSerializationScope::GlobalSharedRead("config"))
|
||||
);
|
||||
|
||||
let account_read = ClientRequest::GetAccount {
|
||||
@@ -2173,6 +2207,7 @@ mod tests {
|
||||
response: v2::ThreadStartResponse {
|
||||
thread: v2::Thread {
|
||||
id: "67e55044-10b1-426f-9247-bb680e5fe0c8".to_string(),
|
||||
session_id: "67e55044-10b1-426f-9247-bb680e5fe0c7".to_string(),
|
||||
forked_from_id: None,
|
||||
preview: "first prompt".to_string(),
|
||||
ephemeral: true,
|
||||
@@ -2184,6 +2219,7 @@ mod tests {
|
||||
cwd: cwd.clone(),
|
||||
cli_version: "0.0.0".to_string(),
|
||||
source: v2::SessionSource::Exec,
|
||||
thread_source: None,
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
git_info: None,
|
||||
@@ -2213,6 +2249,7 @@ mod tests {
|
||||
"response": {
|
||||
"thread": {
|
||||
"id": "67e55044-10b1-426f-9247-bb680e5fe0c8",
|
||||
"sessionId": "67e55044-10b1-426f-9247-bb680e5fe0c7",
|
||||
"forkedFromId": null,
|
||||
"preview": "first prompt",
|
||||
"ephemeral": true,
|
||||
@@ -2226,6 +2263,7 @@ mod tests {
|
||||
"cwd": absolute_path_string("tmp"),
|
||||
"cliVersion": "0.0.0",
|
||||
"source": "exec",
|
||||
"threadSource": null,
|
||||
"agentNickname": null,
|
||||
"agentRole": null,
|
||||
"gitInfo": null,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
383
codex-rs/app-server-protocol/src/protocol/v2/account.rs
Normal file
383
codex-rs/app-server-protocol/src/protocol/v2/account.rs
Normal file
@@ -0,0 +1,383 @@
|
||||
use crate::protocol::common::AuthMode;
|
||||
use codex_experimental_api_macros::ExperimentalApi;
|
||||
use codex_protocol::account::PlanType;
|
||||
use codex_protocol::account::ProviderAccount;
|
||||
use codex_protocol::protocol::CreditsSnapshot as CoreCreditsSnapshot;
|
||||
use codex_protocol::protocol::RateLimitReachedType as CoreRateLimitReachedType;
|
||||
use codex_protocol::protocol::RateLimitSnapshot as CoreRateLimitSnapshot;
|
||||
use codex_protocol::protocol::RateLimitWindow as CoreRateLimitWindow;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[ts(tag = "type")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum Account {
|
||||
#[serde(rename = "apiKey", rename_all = "camelCase")]
|
||||
#[ts(rename = "apiKey", rename_all = "camelCase")]
|
||||
ApiKey {},
|
||||
|
||||
#[serde(rename = "chatgpt", rename_all = "camelCase")]
|
||||
#[ts(rename = "chatgpt", rename_all = "camelCase")]
|
||||
Chatgpt { email: String, plan_type: PlanType },
|
||||
|
||||
#[serde(rename = "amazonBedrock", rename_all = "camelCase")]
|
||||
#[ts(rename = "amazonBedrock", rename_all = "camelCase")]
|
||||
AmazonBedrock {},
|
||||
}
|
||||
|
||||
impl From<ProviderAccount> for Account {
|
||||
fn from(account: ProviderAccount) -> Self {
|
||||
match account {
|
||||
ProviderAccount::ApiKey => Self::ApiKey {},
|
||||
ProviderAccount::Chatgpt { email, plan_type } => Self::Chatgpt { email, plan_type },
|
||||
ProviderAccount::AmazonBedrock => Self::AmazonBedrock {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
||||
#[serde(tag = "type")]
|
||||
#[ts(tag = "type")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum LoginAccountParams {
|
||||
#[serde(rename = "apiKey", rename_all = "camelCase")]
|
||||
#[ts(rename = "apiKey", rename_all = "camelCase")]
|
||||
ApiKey {
|
||||
#[serde(rename = "apiKey")]
|
||||
#[ts(rename = "apiKey")]
|
||||
api_key: String,
|
||||
},
|
||||
#[serde(rename = "chatgpt", rename_all = "camelCase")]
|
||||
#[ts(rename = "chatgpt", rename_all = "camelCase")]
|
||||
Chatgpt {
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
codex_streamlined_login: bool,
|
||||
},
|
||||
#[serde(rename = "chatgptDeviceCode")]
|
||||
#[ts(rename = "chatgptDeviceCode")]
|
||||
ChatgptDeviceCode,
|
||||
/// [UNSTABLE] FOR OPENAI INTERNAL USE ONLY - DO NOT USE.
|
||||
/// The access token must contain the same scopes that Codex-managed ChatGPT auth tokens have.
|
||||
#[experimental("account/login/start.chatgptAuthTokens")]
|
||||
#[serde(rename = "chatgptAuthTokens", rename_all = "camelCase")]
|
||||
#[ts(rename = "chatgptAuthTokens", rename_all = "camelCase")]
|
||||
ChatgptAuthTokens {
|
||||
/// Access token (JWT) supplied by the client.
|
||||
/// This token is used for backend API requests and email extraction.
|
||||
access_token: String,
|
||||
/// Workspace/account identifier supplied by the client.
|
||||
chatgpt_account_id: String,
|
||||
/// Optional plan type supplied by the client.
|
||||
///
|
||||
/// When `null`, Codex attempts to derive the plan type from access-token
|
||||
/// claims. If unavailable, the plan defaults to `unknown`.
|
||||
#[ts(optional = nullable)]
|
||||
chatgpt_plan_type: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[ts(tag = "type")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum LoginAccountResponse {
|
||||
#[serde(rename = "apiKey", rename_all = "camelCase")]
|
||||
#[ts(rename = "apiKey", rename_all = "camelCase")]
|
||||
ApiKey {},
|
||||
#[serde(rename = "chatgpt", rename_all = "camelCase")]
|
||||
#[ts(rename = "chatgpt", rename_all = "camelCase")]
|
||||
Chatgpt {
|
||||
// Use plain String for identifiers to avoid TS/JSON Schema quirks around uuid-specific types.
|
||||
// Convert to/from UUIDs at the application layer as needed.
|
||||
login_id: String,
|
||||
/// URL the client should open in a browser to initiate the OAuth flow.
|
||||
auth_url: String,
|
||||
},
|
||||
#[serde(rename = "chatgptDeviceCode", rename_all = "camelCase")]
|
||||
#[ts(rename = "chatgptDeviceCode", rename_all = "camelCase")]
|
||||
ChatgptDeviceCode {
|
||||
// Use plain String for identifiers to avoid TS/JSON Schema quirks around uuid-specific types.
|
||||
// Convert to/from UUIDs at the application layer as needed.
|
||||
login_id: String,
|
||||
/// URL the client should open in a browser to complete device code authorization.
|
||||
verification_url: String,
|
||||
/// One-time code the user must enter after signing in.
|
||||
user_code: String,
|
||||
},
|
||||
#[serde(rename = "chatgptAuthTokens", rename_all = "camelCase")]
|
||||
#[ts(rename = "chatgptAuthTokens", rename_all = "camelCase")]
|
||||
ChatgptAuthTokens {},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CancelLoginAccountParams {
|
||||
pub login_id: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum CancelLoginAccountStatus {
|
||||
Canceled,
|
||||
NotFound,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CancelLoginAccountResponse {
|
||||
pub status: CancelLoginAccountStatus,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct LogoutAccountResponse {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum ChatgptAuthTokensRefreshReason {
|
||||
/// Codex attempted a backend request and received `401 Unauthorized`.
|
||||
Unauthorized,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ChatgptAuthTokensRefreshParams {
|
||||
pub reason: ChatgptAuthTokensRefreshReason,
|
||||
/// Workspace/account identifier that Codex was previously using.
|
||||
///
|
||||
/// Clients that manage multiple accounts/workspaces can use this as a hint
|
||||
/// to refresh the token for the correct workspace.
|
||||
///
|
||||
/// This may be `null` when the prior auth state did not include a workspace
|
||||
/// identifier (`chatgpt_account_id`).
|
||||
#[ts(optional = nullable)]
|
||||
pub previous_account_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ChatgptAuthTokensRefreshResponse {
|
||||
pub access_token: String,
|
||||
pub chatgpt_account_id: String,
|
||||
pub chatgpt_plan_type: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct GetAccountRateLimitsResponse {
|
||||
/// Backward-compatible single-bucket view; mirrors the historical payload.
|
||||
pub rate_limits: RateLimitSnapshot,
|
||||
/// Multi-bucket view keyed by metered `limit_id` (for example, `codex`).
|
||||
pub rate_limits_by_limit_id: Option<HashMap<String, RateLimitSnapshot>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SendAddCreditsNudgeEmailParams {
|
||||
pub credit_type: AddCreditsNudgeCreditType,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/", rename_all = "snake_case")]
|
||||
pub enum AddCreditsNudgeCreditType {
|
||||
Credits,
|
||||
UsageLimit,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SendAddCreditsNudgeEmailResponse {
|
||||
pub status: AddCreditsNudgeEmailStatus,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/", rename_all = "snake_case")]
|
||||
pub enum AddCreditsNudgeEmailStatus {
|
||||
Sent,
|
||||
CooldownActive,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct GetAccountParams {
|
||||
/// When `true`, requests a proactive token refresh before returning.
|
||||
///
|
||||
/// In managed auth mode this triggers the normal refresh-token flow. In
|
||||
/// external auth mode this flag is ignored. Clients should refresh tokens
|
||||
/// themselves and call `account/login/start` with `chatgptAuthTokens`.
|
||||
#[serde(default)]
|
||||
pub refresh_token: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct GetAccountResponse {
|
||||
pub account: Option<Account>,
|
||||
pub requires_openai_auth: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AccountUpdatedNotification {
|
||||
pub auth_mode: Option<AuthMode>,
|
||||
pub plan_type: Option<PlanType>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AccountRateLimitsUpdatedNotification {
|
||||
pub rate_limits: RateLimitSnapshot,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct RateLimitSnapshot {
|
||||
pub limit_id: Option<String>,
|
||||
pub limit_name: Option<String>,
|
||||
pub primary: Option<RateLimitWindow>,
|
||||
pub secondary: Option<RateLimitWindow>,
|
||||
pub credits: Option<CreditsSnapshot>,
|
||||
pub plan_type: Option<PlanType>,
|
||||
pub rate_limit_reached_type: Option<RateLimitReachedType>,
|
||||
}
|
||||
|
||||
impl From<CoreRateLimitSnapshot> for RateLimitSnapshot {
|
||||
fn from(value: CoreRateLimitSnapshot) -> Self {
|
||||
Self {
|
||||
limit_id: value.limit_id,
|
||||
limit_name: value.limit_name,
|
||||
primary: value.primary.map(RateLimitWindow::from),
|
||||
secondary: value.secondary.map(RateLimitWindow::from),
|
||||
credits: value.credits.map(CreditsSnapshot::from),
|
||||
plan_type: value.plan_type,
|
||||
rate_limit_reached_type: value
|
||||
.rate_limit_reached_type
|
||||
.map(RateLimitReachedType::from),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/", rename_all = "snake_case")]
|
||||
pub enum RateLimitReachedType {
|
||||
RateLimitReached,
|
||||
WorkspaceOwnerCreditsDepleted,
|
||||
WorkspaceMemberCreditsDepleted,
|
||||
WorkspaceOwnerUsageLimitReached,
|
||||
WorkspaceMemberUsageLimitReached,
|
||||
}
|
||||
|
||||
impl From<CoreRateLimitReachedType> for RateLimitReachedType {
|
||||
fn from(value: CoreRateLimitReachedType) -> Self {
|
||||
match value {
|
||||
CoreRateLimitReachedType::RateLimitReached => Self::RateLimitReached,
|
||||
CoreRateLimitReachedType::WorkspaceOwnerCreditsDepleted => {
|
||||
Self::WorkspaceOwnerCreditsDepleted
|
||||
}
|
||||
CoreRateLimitReachedType::WorkspaceMemberCreditsDepleted => {
|
||||
Self::WorkspaceMemberCreditsDepleted
|
||||
}
|
||||
CoreRateLimitReachedType::WorkspaceOwnerUsageLimitReached => {
|
||||
Self::WorkspaceOwnerUsageLimitReached
|
||||
}
|
||||
CoreRateLimitReachedType::WorkspaceMemberUsageLimitReached => {
|
||||
Self::WorkspaceMemberUsageLimitReached
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RateLimitReachedType> for CoreRateLimitReachedType {
|
||||
fn from(value: RateLimitReachedType) -> Self {
|
||||
match value {
|
||||
RateLimitReachedType::RateLimitReached => Self::RateLimitReached,
|
||||
RateLimitReachedType::WorkspaceOwnerCreditsDepleted => {
|
||||
Self::WorkspaceOwnerCreditsDepleted
|
||||
}
|
||||
RateLimitReachedType::WorkspaceMemberCreditsDepleted => {
|
||||
Self::WorkspaceMemberCreditsDepleted
|
||||
}
|
||||
RateLimitReachedType::WorkspaceOwnerUsageLimitReached => {
|
||||
Self::WorkspaceOwnerUsageLimitReached
|
||||
}
|
||||
RateLimitReachedType::WorkspaceMemberUsageLimitReached => {
|
||||
Self::WorkspaceMemberUsageLimitReached
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct RateLimitWindow {
|
||||
pub used_percent: i32,
|
||||
#[ts(type = "number | null")]
|
||||
pub window_duration_mins: Option<i64>,
|
||||
#[ts(type = "number | null")]
|
||||
pub resets_at: Option<i64>,
|
||||
}
|
||||
|
||||
impl From<CoreRateLimitWindow> for RateLimitWindow {
|
||||
fn from(value: CoreRateLimitWindow) -> Self {
|
||||
Self {
|
||||
used_percent: value.used_percent.round() as i32,
|
||||
window_duration_mins: value.window_minutes,
|
||||
resets_at: value.resets_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CreditsSnapshot {
|
||||
pub has_credits: bool,
|
||||
pub unlimited: bool,
|
||||
pub balance: Option<String>,
|
||||
}
|
||||
|
||||
impl From<CoreCreditsSnapshot> for CreditsSnapshot {
|
||||
fn from(value: CoreCreditsSnapshot) -> Self {
|
||||
Self {
|
||||
has_credits: value.has_credits,
|
||||
unlimited: value.unlimited,
|
||||
balance: value.balance,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AccountLoginCompletedNotification {
|
||||
// Use plain String for identifiers to avoid TS/JSON Schema quirks around uuid-specific types.
|
||||
// Convert to/from UUIDs at the application layer as needed.
|
||||
pub login_id: Option<String>,
|
||||
pub success: bool,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
146
codex-rs/app-server-protocol/src/protocol/v2/apps.rs
Normal file
146
codex-rs/app-server-protocol/src/protocol/v2/apps.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
use super::shared::default_enabled;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
/// EXPERIMENTAL - list available apps/connectors.
|
||||
pub struct AppsListParams {
|
||||
/// Opaque pagination cursor returned by a previous call.
|
||||
#[ts(optional = nullable)]
|
||||
pub cursor: Option<String>,
|
||||
/// Optional page size; defaults to a reasonable server-side value.
|
||||
#[ts(optional = nullable)]
|
||||
pub limit: Option<u32>,
|
||||
/// Optional thread id used to evaluate app feature gating from that thread's config.
|
||||
#[ts(optional = nullable)]
|
||||
pub thread_id: Option<String>,
|
||||
/// When true, bypass app caches and fetch the latest data from sources.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub force_refetch: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
/// EXPERIMENTAL - app metadata returned by app-list APIs.
|
||||
pub struct AppBranding {
|
||||
pub category: Option<String>,
|
||||
pub developer: Option<String>,
|
||||
pub website: Option<String>,
|
||||
pub privacy_policy: Option<String>,
|
||||
pub terms_of_service: Option<String>,
|
||||
pub is_discoverable_app: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AppReview {
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AppScreenshot {
|
||||
pub url: Option<String>,
|
||||
#[serde(alias = "file_id")]
|
||||
pub file_id: Option<String>,
|
||||
#[serde(alias = "user_prompt")]
|
||||
pub user_prompt: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AppMetadata {
|
||||
pub review: Option<AppReview>,
|
||||
pub categories: Option<Vec<String>>,
|
||||
pub sub_categories: Option<Vec<String>>,
|
||||
pub seo_description: Option<String>,
|
||||
pub screenshots: Option<Vec<AppScreenshot>>,
|
||||
pub developer: Option<String>,
|
||||
pub version: Option<String>,
|
||||
pub version_id: Option<String>,
|
||||
pub version_notes: Option<String>,
|
||||
pub first_party_type: Option<String>,
|
||||
pub first_party_requires_install: Option<bool>,
|
||||
pub show_in_composer_when_unlinked: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
/// EXPERIMENTAL - app metadata returned by app-list APIs.
|
||||
pub struct AppInfo {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub logo_url: Option<String>,
|
||||
pub logo_url_dark: Option<String>,
|
||||
pub distribution_channel: Option<String>,
|
||||
pub branding: Option<AppBranding>,
|
||||
pub app_metadata: Option<AppMetadata>,
|
||||
pub labels: Option<HashMap<String, String>>,
|
||||
pub install_url: Option<String>,
|
||||
#[serde(default)]
|
||||
pub is_accessible: bool,
|
||||
/// Whether this app is enabled in config.toml.
|
||||
/// Example:
|
||||
/// ```toml
|
||||
/// [apps.bad_app]
|
||||
/// enabled = false
|
||||
/// ```
|
||||
#[serde(default = "default_enabled")]
|
||||
pub is_enabled: bool,
|
||||
#[serde(default)]
|
||||
pub plugin_display_names: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
/// EXPERIMENTAL - app metadata summary for plugin responses.
|
||||
pub struct AppSummary {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub install_url: Option<String>,
|
||||
pub needs_auth: bool,
|
||||
}
|
||||
|
||||
impl From<AppInfo> for AppSummary {
|
||||
fn from(value: AppInfo) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
name: value.name,
|
||||
description: value.description,
|
||||
install_url: value.install_url,
|
||||
needs_auth: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
/// EXPERIMENTAL - app list response.
|
||||
pub struct AppsListResponse {
|
||||
pub data: Vec<AppInfo>,
|
||||
/// Opaque cursor to pass to the next call to continue after the last item.
|
||||
/// If None, there are no more items to return.
|
||||
pub next_cursor: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
/// EXPERIMENTAL - notification emitted when the app list changes.
|
||||
pub struct AppListUpdatedNotification {
|
||||
pub data: Vec<AppInfo>,
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
use codex_protocol::config_types::CollaborationModeMask as CoreCollaborationModeMask;
|
||||
use codex_protocol::config_types::ModeKind;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use ts_rs::TS;
|
||||
|
||||
/// EXPERIMENTAL - list collaboration mode presets.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CollaborationModeListParams {}
|
||||
|
||||
/// EXPERIMENTAL - collaboration mode preset metadata for clients.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CollaborationModeMask {
|
||||
pub name: String,
|
||||
pub mode: Option<ModeKind>,
|
||||
pub model: Option<String>,
|
||||
#[serde(rename = "reasoning_effort")]
|
||||
#[ts(rename = "reasoning_effort")]
|
||||
pub reasoning_effort: Option<Option<ReasoningEffort>>,
|
||||
}
|
||||
|
||||
impl From<CoreCollaborationModeMask> for CollaborationModeMask {
|
||||
fn from(value: CoreCollaborationModeMask) -> Self {
|
||||
Self {
|
||||
name: value.name,
|
||||
mode: value.mode,
|
||||
model: value.model,
|
||||
reasoning_effort: value.reasoning_effort,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - collaboration mode presets response.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CollaborationModeListResponse {
|
||||
pub data: Vec<CollaborationModeMask>,
|
||||
}
|
||||
214
codex-rs/app-server-protocol/src/protocol/v2/command_exec.rs
Normal file
214
codex-rs/app-server-protocol/src/protocol/v2/command_exec.rs
Normal file
@@ -0,0 +1,214 @@
|
||||
use super::PermissionProfile;
|
||||
use super::SandboxPolicy;
|
||||
use codex_experimental_api_macros::ExperimentalApi;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use ts_rs::TS;
|
||||
|
||||
/// PTY size in character cells for `command/exec` PTY sessions.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CommandExecTerminalSize {
|
||||
/// Terminal height in character cells.
|
||||
pub rows: u16,
|
||||
/// Terminal width in character cells.
|
||||
pub cols: u16,
|
||||
}
|
||||
|
||||
/// Run a standalone command (argv vector) in the server sandbox without
|
||||
/// creating a thread or turn.
|
||||
///
|
||||
/// The 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.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CommandExecParams {
|
||||
/// Command argv vector. Empty arrays are rejected.
|
||||
pub command: Vec<String>,
|
||||
/// Optional client-supplied, connection-scoped process id.
|
||||
///
|
||||
/// Required for `tty`, `streamStdin`, `streamStdoutStderr`, and follow-up
|
||||
/// `command/exec/write`, `command/exec/resize`, and
|
||||
/// `command/exec/terminate` calls. When omitted, buffered execution gets an
|
||||
/// internal id that is not exposed to the client.
|
||||
#[ts(optional = nullable)]
|
||||
pub process_id: Option<String>,
|
||||
/// Enable PTY mode.
|
||||
///
|
||||
/// This implies `streamStdin` and `streamStdoutStderr`.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub tty: bool,
|
||||
/// Allow follow-up `command/exec/write` requests to write stdin bytes.
|
||||
///
|
||||
/// Requires a client-supplied `processId`.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub stream_stdin: bool,
|
||||
/// Stream stdout/stderr via `command/exec/outputDelta` notifications.
|
||||
///
|
||||
/// Streamed bytes are not duplicated into the final response and require a
|
||||
/// client-supplied `processId`.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub stream_stdout_stderr: bool,
|
||||
/// Optional per-stream stdout/stderr capture cap in bytes.
|
||||
///
|
||||
/// When omitted, the server default applies. Cannot be combined with
|
||||
/// `disableOutputCap`.
|
||||
#[ts(type = "number | null")]
|
||||
#[ts(optional = nullable)]
|
||||
pub output_bytes_cap: Option<usize>,
|
||||
/// Disable stdout/stderr capture truncation for this request.
|
||||
///
|
||||
/// Cannot be combined with `outputBytesCap`.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub disable_output_cap: bool,
|
||||
/// Disable the timeout entirely for this request.
|
||||
///
|
||||
/// Cannot be combined with `timeoutMs`.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub disable_timeout: bool,
|
||||
/// Optional timeout in milliseconds.
|
||||
///
|
||||
/// When omitted, the server default applies. Cannot be combined with
|
||||
/// `disableTimeout`.
|
||||
#[ts(type = "number | null")]
|
||||
#[ts(optional = nullable)]
|
||||
pub timeout_ms: Option<i64>,
|
||||
/// Optional working directory. Defaults to the server cwd.
|
||||
#[ts(optional = nullable)]
|
||||
pub cwd: Option<PathBuf>,
|
||||
/// Optional environment overrides merged into the server-computed
|
||||
/// environment.
|
||||
///
|
||||
/// Matching names override inherited values. Set a key to `null` to unset
|
||||
/// an inherited variable.
|
||||
#[ts(optional = nullable)]
|
||||
pub env: Option<HashMap<String, Option<String>>>,
|
||||
/// Optional initial PTY size in character cells. Only valid when `tty` is
|
||||
/// true.
|
||||
#[ts(optional = nullable)]
|
||||
pub size: Option<CommandExecTerminalSize>,
|
||||
/// Optional sandbox policy for this command.
|
||||
///
|
||||
/// Uses the same shape as thread/turn execution sandbox configuration and
|
||||
/// defaults to the user's configured policy when omitted. Cannot be
|
||||
/// combined with `permissionProfile`.
|
||||
#[ts(optional = nullable)]
|
||||
pub sandbox_policy: Option<SandboxPolicy>,
|
||||
/// Optional full permissions profile for this command.
|
||||
///
|
||||
/// Defaults to the user's configured permissions when omitted. Cannot be
|
||||
/// combined with `sandboxPolicy`.
|
||||
#[experimental("command/exec.permissionProfile")]
|
||||
#[ts(optional = nullable)]
|
||||
pub permission_profile: Option<PermissionProfile>,
|
||||
}
|
||||
|
||||
/// Final buffered result for `command/exec`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CommandExecResponse {
|
||||
/// Process exit code.
|
||||
pub exit_code: i32,
|
||||
/// Buffered stdout capture.
|
||||
///
|
||||
/// Empty when stdout was streamed via `command/exec/outputDelta`.
|
||||
pub stdout: String,
|
||||
/// Buffered stderr capture.
|
||||
///
|
||||
/// Empty when stderr was streamed via `command/exec/outputDelta`.
|
||||
pub stderr: String,
|
||||
}
|
||||
|
||||
/// Write stdin bytes to a running `command/exec` session, close stdin, or
|
||||
/// both.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CommandExecWriteParams {
|
||||
/// Client-supplied, connection-scoped `processId` from the original
|
||||
/// `command/exec` request.
|
||||
pub process_id: String,
|
||||
/// Optional base64-encoded stdin bytes to write.
|
||||
#[ts(optional = nullable)]
|
||||
pub delta_base64: Option<String>,
|
||||
/// Close stdin after writing `deltaBase64`, if present.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub close_stdin: bool,
|
||||
}
|
||||
|
||||
/// Empty success response for `command/exec/write`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CommandExecWriteResponse {}
|
||||
|
||||
/// Terminate a running `command/exec` session.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CommandExecTerminateParams {
|
||||
/// Client-supplied, connection-scoped `processId` from the original
|
||||
/// `command/exec` request.
|
||||
pub process_id: String,
|
||||
}
|
||||
|
||||
/// Empty success response for `command/exec/terminate`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CommandExecTerminateResponse {}
|
||||
|
||||
/// Resize a running PTY-backed `command/exec` session.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CommandExecResizeParams {
|
||||
/// Client-supplied, connection-scoped `processId` from the original
|
||||
/// `command/exec` request.
|
||||
pub process_id: String,
|
||||
/// New PTY size in character cells.
|
||||
pub size: CommandExecTerminalSize,
|
||||
}
|
||||
|
||||
/// Empty success response for `command/exec/resize`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CommandExecResizeResponse {}
|
||||
|
||||
/// Stream label for `command/exec/outputDelta` notifications.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum CommandExecOutputStream {
|
||||
/// stdout stream. PTY mode multiplexes terminal output here.
|
||||
Stdout,
|
||||
/// stderr stream.
|
||||
Stderr,
|
||||
}
|
||||
/// Base64-encoded output chunk emitted for a streaming `command/exec` request.
|
||||
///
|
||||
/// These notifications are connection-scoped. If the originating connection
|
||||
/// closes, the server terminates the process.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CommandExecOutputDeltaNotification {
|
||||
/// Client-supplied, connection-scoped `processId` from the original
|
||||
/// `command/exec` request.
|
||||
pub process_id: String,
|
||||
/// Output stream for this chunk.
|
||||
pub stream: CommandExecOutputStream,
|
||||
/// Base64-encoded output bytes.
|
||||
pub delta_base64: String,
|
||||
/// `true` on the final streamed chunk for a stream when `outputBytesCap`
|
||||
/// truncated later output on that stream.
|
||||
pub cap_reached: bool,
|
||||
}
|
||||
708
codex-rs/app-server-protocol/src/protocol/v2/config.rs
Normal file
708
codex-rs/app-server-protocol/src/protocol/v2/config.rs
Normal file
@@ -0,0 +1,708 @@
|
||||
use super::ApprovalsReviewer;
|
||||
use super::AskForApproval;
|
||||
use super::SandboxMode;
|
||||
use super::shared::default_enabled;
|
||||
use codex_experimental_api_macros::ExperimentalApi;
|
||||
use codex_protocol::config_types::ForcedLoginMethod;
|
||||
use codex_protocol::config_types::ReasoningSummary;
|
||||
use codex_protocol::config_types::Verbosity;
|
||||
use codex_protocol::config_types::WebSearchMode;
|
||||
use codex_protocol::config_types::WebSearchToolConfig;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[ts(tag = "type")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum ConfigLayerSource {
|
||||
/// Managed preferences layer delivered by MDM (macOS only).
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
Mdm {
|
||||
domain: String,
|
||||
key: String,
|
||||
},
|
||||
|
||||
/// Managed config layer from a file (usually `managed_config.toml`).
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
System {
|
||||
/// This is the path to the system config.toml file, though it is not
|
||||
/// guaranteed to exist.
|
||||
file: AbsolutePathBuf,
|
||||
},
|
||||
|
||||
/// User config layer from $CODEX_HOME/config.toml. This layer is special
|
||||
/// in that it is expected to be:
|
||||
/// - writable by the user
|
||||
/// - generally outside the workspace directory
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
User {
|
||||
/// This is the path to the user's config.toml file, though it is not
|
||||
/// guaranteed to exist.
|
||||
file: AbsolutePathBuf,
|
||||
},
|
||||
|
||||
/// Path to a .codex/ folder within a project. There could be multiple of
|
||||
/// these between `cwd` and the project/repo root.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
Project {
|
||||
dot_codex_folder: AbsolutePathBuf,
|
||||
},
|
||||
|
||||
/// Session-layer overrides supplied via `-c`/`--config`.
|
||||
SessionFlags,
|
||||
|
||||
/// `managed_config.toml` was designed to be a config that was loaded
|
||||
/// as the last layer on top of everything else. This scheme did not quite
|
||||
/// work out as intended, but we keep this variant as a "best effort" while
|
||||
/// we phase out `managed_config.toml` in favor of `requirements.toml`.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
LegacyManagedConfigTomlFromFile {
|
||||
file: AbsolutePathBuf,
|
||||
},
|
||||
|
||||
LegacyManagedConfigTomlFromMdm,
|
||||
}
|
||||
|
||||
impl ConfigLayerSource {
|
||||
/// A settings from a layer with a higher precedence will override a setting
|
||||
/// from a layer with a lower precedence.
|
||||
pub fn precedence(&self) -> i16 {
|
||||
match self {
|
||||
ConfigLayerSource::Mdm { .. } => 0,
|
||||
ConfigLayerSource::System { .. } => 10,
|
||||
ConfigLayerSource::User { .. } => 20,
|
||||
ConfigLayerSource::Project { .. } => 25,
|
||||
ConfigLayerSource::SessionFlags => 30,
|
||||
ConfigLayerSource::LegacyManagedConfigTomlFromFile { .. } => 40,
|
||||
ConfigLayerSource::LegacyManagedConfigTomlFromMdm => 50,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compares [ConfigLayerSource] by precedence, so `A < B` means settings from
|
||||
/// layer `A` will be overridden by settings from layer `B`.
|
||||
impl PartialOrd for ConfigLayerSource {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.precedence().cmp(&other.precedence()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SandboxWorkspaceWrite {
|
||||
#[serde(default)]
|
||||
pub writable_roots: Vec<PathBuf>,
|
||||
#[serde(default)]
|
||||
pub network_access: bool,
|
||||
#[serde(default)]
|
||||
pub exclude_tmpdir_env_var: bool,
|
||||
#[serde(default)]
|
||||
pub exclude_slash_tmp: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ToolsV2 {
|
||||
pub web_search: Option<WebSearchToolConfig>,
|
||||
pub view_image: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ProfileV2 {
|
||||
pub model: Option<String>,
|
||||
pub model_provider: Option<String>,
|
||||
#[experimental(nested)]
|
||||
pub approval_policy: Option<AskForApproval>,
|
||||
/// [UNSTABLE] Optional profile-level override for where approval requests
|
||||
/// are routed for review. If omitted, the enclosing config default is
|
||||
/// used.
|
||||
#[experimental("config/read.approvalsReviewer")]
|
||||
pub approvals_reviewer: Option<ApprovalsReviewer>,
|
||||
pub service_tier: Option<String>,
|
||||
pub model_reasoning_effort: Option<ReasoningEffort>,
|
||||
pub model_reasoning_summary: Option<ReasoningSummary>,
|
||||
pub model_verbosity: Option<Verbosity>,
|
||||
pub web_search: Option<WebSearchMode>,
|
||||
pub tools: Option<ToolsV2>,
|
||||
pub chatgpt_base_url: Option<String>,
|
||||
#[serde(default, flatten)]
|
||||
pub additional: HashMap<String, JsonValue>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AnalyticsConfig {
|
||||
pub enabled: Option<bool>,
|
||||
#[serde(default, flatten)]
|
||||
pub additional: HashMap<String, JsonValue>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum AppToolApproval {
|
||||
Auto,
|
||||
Prompt,
|
||||
Approve,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AppsDefaultConfig {
|
||||
#[serde(default = "default_enabled")]
|
||||
pub enabled: bool,
|
||||
#[serde(default = "default_enabled")]
|
||||
pub destructive_enabled: bool,
|
||||
#[serde(default = "default_enabled")]
|
||||
pub open_world_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AppToolConfig {
|
||||
pub enabled: Option<bool>,
|
||||
pub approval_mode: Option<AppToolApproval>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AppToolsConfig {
|
||||
#[serde(default, flatten)]
|
||||
pub tools: HashMap<String, AppToolConfig>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AppConfig {
|
||||
#[serde(default = "default_enabled")]
|
||||
pub enabled: bool,
|
||||
pub destructive_enabled: Option<bool>,
|
||||
pub open_world_enabled: Option<bool>,
|
||||
pub default_tools_approval_mode: Option<AppToolApproval>,
|
||||
pub default_tools_enabled: Option<bool>,
|
||||
pub tools: Option<AppToolsConfig>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AppsConfig {
|
||||
#[serde(default, rename = "_default")]
|
||||
pub default: Option<AppsDefaultConfig>,
|
||||
#[serde(default, flatten)]
|
||||
pub apps: HashMap<String, AppConfig>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct Config {
|
||||
pub model: Option<String>,
|
||||
pub review_model: Option<String>,
|
||||
pub model_context_window: Option<i64>,
|
||||
pub model_auto_compact_token_limit: Option<i64>,
|
||||
pub model_provider: Option<String>,
|
||||
#[experimental(nested)]
|
||||
pub approval_policy: Option<AskForApproval>,
|
||||
/// [UNSTABLE] Optional default for where approval requests are routed for
|
||||
/// review.
|
||||
#[experimental("config/read.approvalsReviewer")]
|
||||
pub approvals_reviewer: Option<ApprovalsReviewer>,
|
||||
pub sandbox_mode: Option<SandboxMode>,
|
||||
pub sandbox_workspace_write: Option<SandboxWorkspaceWrite>,
|
||||
pub forced_chatgpt_workspace_id: Option<String>,
|
||||
pub forced_login_method: Option<ForcedLoginMethod>,
|
||||
pub web_search: Option<WebSearchMode>,
|
||||
pub tools: Option<ToolsV2>,
|
||||
pub profile: Option<String>,
|
||||
#[experimental(nested)]
|
||||
#[serde(default)]
|
||||
pub profiles: HashMap<String, ProfileV2>,
|
||||
pub instructions: Option<String>,
|
||||
pub developer_instructions: Option<String>,
|
||||
pub compact_prompt: Option<String>,
|
||||
pub model_reasoning_effort: Option<ReasoningEffort>,
|
||||
pub model_reasoning_summary: Option<ReasoningSummary>,
|
||||
pub model_verbosity: Option<Verbosity>,
|
||||
pub service_tier: Option<String>,
|
||||
pub analytics: Option<AnalyticsConfig>,
|
||||
#[experimental("config/read.apps")]
|
||||
#[serde(default)]
|
||||
pub apps: Option<AppsConfig>,
|
||||
#[serde(default, flatten)]
|
||||
pub additional: HashMap<String, JsonValue>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ConfigLayerMetadata {
|
||||
pub name: ConfigLayerSource,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ConfigLayer {
|
||||
pub name: ConfigLayerSource,
|
||||
pub version: String,
|
||||
pub config: JsonValue,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub disabled_reason: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum MergeStrategy {
|
||||
Replace,
|
||||
Upsert,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum WriteStatus {
|
||||
Ok,
|
||||
OkOverridden,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct OverriddenMetadata {
|
||||
pub message: String,
|
||||
pub overriding_layer: ConfigLayerMetadata,
|
||||
pub effective_value: JsonValue,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ConfigWriteResponse {
|
||||
pub status: WriteStatus,
|
||||
pub version: String,
|
||||
/// Canonical path to the config file that was written.
|
||||
pub file_path: AbsolutePathBuf,
|
||||
pub overridden_metadata: Option<OverriddenMetadata>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum ConfigWriteErrorCode {
|
||||
ConfigLayerReadonly,
|
||||
ConfigVersionConflict,
|
||||
ConfigValidationError,
|
||||
ConfigPathNotFound,
|
||||
ConfigSchemaUnknownKey,
|
||||
UserLayerNotFound,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ConfigReadParams {
|
||||
#[serde(default)]
|
||||
pub include_layers: bool,
|
||||
/// Optional working directory to resolve project config layers. If specified,
|
||||
/// return the effective config as seen from that directory (i.e., including any
|
||||
/// project layers between `cwd` and the project/repo root).
|
||||
#[ts(optional = nullable)]
|
||||
pub cwd: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ConfigReadResponse {
|
||||
#[experimental(nested)]
|
||||
pub config: Config,
|
||||
pub origins: HashMap<String, ConfigLayerMetadata>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub layers: Option<Vec<ConfigLayer>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ConfigRequirements {
|
||||
#[experimental(nested)]
|
||||
pub allowed_approval_policies: Option<Vec<AskForApproval>>,
|
||||
#[experimental("configRequirements/read.allowedApprovalsReviewers")]
|
||||
pub allowed_approvals_reviewers: Option<Vec<ApprovalsReviewer>>,
|
||||
pub allowed_sandbox_modes: Option<Vec<SandboxMode>>,
|
||||
pub allowed_web_search_modes: Option<Vec<WebSearchMode>>,
|
||||
pub feature_requirements: Option<BTreeMap<String, bool>>,
|
||||
#[experimental("configRequirements/read.hooks")]
|
||||
pub hooks: Option<ManagedHooksRequirements>,
|
||||
pub enforce_residency: Option<ResidencyRequirement>,
|
||||
#[experimental("configRequirements/read.network")]
|
||||
pub network: Option<NetworkRequirements>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ManagedHooksRequirements {
|
||||
pub managed_dir: Option<PathBuf>,
|
||||
pub windows_managed_dir: Option<PathBuf>,
|
||||
#[serde(rename = "PreToolUse")]
|
||||
#[ts(rename = "PreToolUse")]
|
||||
pub pre_tool_use: Vec<ConfiguredHookMatcherGroup>,
|
||||
#[serde(rename = "PermissionRequest")]
|
||||
#[ts(rename = "PermissionRequest")]
|
||||
pub permission_request: Vec<ConfiguredHookMatcherGroup>,
|
||||
#[serde(rename = "PostToolUse")]
|
||||
#[ts(rename = "PostToolUse")]
|
||||
pub post_tool_use: Vec<ConfiguredHookMatcherGroup>,
|
||||
#[serde(rename = "PreCompact")]
|
||||
#[ts(rename = "PreCompact")]
|
||||
pub pre_compact: Vec<ConfiguredHookMatcherGroup>,
|
||||
#[serde(rename = "PostCompact")]
|
||||
#[ts(rename = "PostCompact")]
|
||||
pub post_compact: Vec<ConfiguredHookMatcherGroup>,
|
||||
#[serde(rename = "SessionStart")]
|
||||
#[ts(rename = "SessionStart")]
|
||||
pub session_start: Vec<ConfiguredHookMatcherGroup>,
|
||||
#[serde(rename = "UserPromptSubmit")]
|
||||
#[ts(rename = "UserPromptSubmit")]
|
||||
pub user_prompt_submit: Vec<ConfiguredHookMatcherGroup>,
|
||||
#[serde(rename = "Stop")]
|
||||
#[ts(rename = "Stop")]
|
||||
pub stop: Vec<ConfiguredHookMatcherGroup>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ConfiguredHookMatcherGroup {
|
||||
pub matcher: Option<String>,
|
||||
pub hooks: Vec<ConfiguredHookHandler>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(tag = "type")]
|
||||
#[ts(tag = "type", export_to = "v2/")]
|
||||
pub enum ConfiguredHookHandler {
|
||||
#[serde(rename = "command")]
|
||||
#[ts(rename = "command")]
|
||||
Command {
|
||||
command: String,
|
||||
#[serde(rename = "timeoutSec")]
|
||||
#[ts(rename = "timeoutSec")]
|
||||
timeout_sec: Option<u64>,
|
||||
r#async: bool,
|
||||
#[serde(rename = "statusMessage")]
|
||||
#[ts(rename = "statusMessage")]
|
||||
status_message: Option<String>,
|
||||
},
|
||||
#[serde(rename = "prompt")]
|
||||
#[ts(rename = "prompt")]
|
||||
Prompt {},
|
||||
#[serde(rename = "agent")]
|
||||
#[ts(rename = "agent")]
|
||||
Agent {},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct NetworkRequirements {
|
||||
pub enabled: Option<bool>,
|
||||
pub http_port: Option<u16>,
|
||||
pub socks_port: Option<u16>,
|
||||
pub allow_upstream_proxy: Option<bool>,
|
||||
pub dangerously_allow_non_loopback_proxy: Option<bool>,
|
||||
pub dangerously_allow_all_unix_sockets: Option<bool>,
|
||||
/// Canonical network permission map for `experimental_network`.
|
||||
pub domains: Option<BTreeMap<String, NetworkDomainPermission>>,
|
||||
/// When true, only managed allowlist entries are respected while managed
|
||||
/// network enforcement is active.
|
||||
pub managed_allowed_domains_only: Option<bool>,
|
||||
/// Legacy compatibility view derived from `domains`.
|
||||
pub allowed_domains: Option<Vec<String>>,
|
||||
/// Legacy compatibility view derived from `domains`.
|
||||
pub denied_domains: Option<Vec<String>>,
|
||||
/// Canonical unix socket permission map for `experimental_network`.
|
||||
pub unix_sockets: Option<BTreeMap<String, NetworkUnixSocketPermission>>,
|
||||
/// Legacy compatibility view derived from `unix_sockets`.
|
||||
pub allow_unix_sockets: Option<Vec<String>>,
|
||||
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,
|
||||
}
|
||||
|
||||
#[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/")]
|
||||
pub enum ResidencyRequirement {
|
||||
Us,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ConfigRequirementsReadResponse {
|
||||
/// Null if no requirements are configured (e.g. no requirements.toml/MDM entries).
|
||||
#[experimental(nested)]
|
||||
pub requirements: Option<ConfigRequirements>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, JsonSchema, TS)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum ExternalAgentConfigMigrationItemType {
|
||||
#[serde(rename = "AGENTS_MD")]
|
||||
#[ts(rename = "AGENTS_MD")]
|
||||
AgentsMd,
|
||||
#[serde(rename = "CONFIG")]
|
||||
#[ts(rename = "CONFIG")]
|
||||
Config,
|
||||
#[serde(rename = "SKILLS")]
|
||||
#[ts(rename = "SKILLS")]
|
||||
Skills,
|
||||
#[serde(rename = "PLUGINS")]
|
||||
#[ts(rename = "PLUGINS")]
|
||||
Plugins,
|
||||
#[serde(rename = "MCP_SERVER_CONFIG")]
|
||||
#[ts(rename = "MCP_SERVER_CONFIG")]
|
||||
McpServerConfig,
|
||||
#[serde(rename = "SUBAGENTS")]
|
||||
#[ts(rename = "SUBAGENTS")]
|
||||
Subagents,
|
||||
#[serde(rename = "HOOKS")]
|
||||
#[ts(rename = "HOOKS")]
|
||||
Hooks,
|
||||
#[serde(rename = "COMMANDS")]
|
||||
#[ts(rename = "COMMANDS")]
|
||||
Commands,
|
||||
#[serde(rename = "SESSIONS")]
|
||||
#[ts(rename = "SESSIONS")]
|
||||
Sessions,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginsMigration {
|
||||
#[serde(rename = "marketplaceName")]
|
||||
#[ts(rename = "marketplaceName")]
|
||||
pub marketplace_name: String,
|
||||
#[serde(rename = "pluginNames")]
|
||||
#[ts(rename = "pluginNames")]
|
||||
pub plugin_names: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SessionMigration {
|
||||
pub path: PathBuf,
|
||||
pub cwd: PathBuf,
|
||||
pub title: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpServerMigration {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct HookMigration {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SubagentMigration {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct CommandMigration {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct MigrationDetails {
|
||||
#[serde(default)]
|
||||
pub plugins: Vec<PluginsMigration>,
|
||||
#[serde(default)]
|
||||
pub sessions: Vec<SessionMigration>,
|
||||
#[serde(default)]
|
||||
pub mcp_servers: Vec<McpServerMigration>,
|
||||
#[serde(default)]
|
||||
pub hooks: Vec<HookMigration>,
|
||||
#[serde(default)]
|
||||
pub subagents: Vec<SubagentMigration>,
|
||||
#[serde(default)]
|
||||
pub commands: Vec<CommandMigration>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ExternalAgentConfigMigrationItem {
|
||||
pub item_type: ExternalAgentConfigMigrationItemType,
|
||||
pub description: String,
|
||||
/// Null or empty means home-scoped migration; non-empty means repo-scoped migration.
|
||||
pub cwd: Option<PathBuf>,
|
||||
pub details: Option<MigrationDetails>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ExternalAgentConfigDetectResponse {
|
||||
pub items: Vec<ExternalAgentConfigMigrationItem>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ExternalAgentConfigDetectParams {
|
||||
/// If true, include detection under the user's home (~/.claude, ~/.codex, etc.).
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub include_home: bool,
|
||||
/// Zero or more working directories to include for repo-scoped detection.
|
||||
#[ts(optional = nullable)]
|
||||
pub cwds: Option<Vec<PathBuf>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ExternalAgentConfigImportParams {
|
||||
pub migration_items: Vec<ExternalAgentConfigMigrationItem>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ExternalAgentConfigImportResponse {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ExternalAgentConfigImportCompletedNotification {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ConfigValueWriteParams {
|
||||
pub key_path: String,
|
||||
pub value: JsonValue,
|
||||
pub merge_strategy: MergeStrategy,
|
||||
/// Path to the config file to write; defaults to the user's `config.toml` when omitted.
|
||||
#[ts(optional = nullable)]
|
||||
pub file_path: Option<String>,
|
||||
#[ts(optional = nullable)]
|
||||
pub expected_version: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ConfigBatchWriteParams {
|
||||
pub edits: Vec<ConfigEdit>,
|
||||
/// Path to the config file to write; defaults to the user's `config.toml` when omitted.
|
||||
#[ts(optional = nullable)]
|
||||
pub file_path: Option<String>,
|
||||
#[ts(optional = nullable)]
|
||||
pub expected_version: Option<String>,
|
||||
/// When true, hot-reload the updated user config into all loaded threads after writing.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub reload_user_config: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ConfigEdit {
|
||||
pub key_path: String,
|
||||
pub value: JsonValue,
|
||||
pub merge_strategy: MergeStrategy,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct TextPosition {
|
||||
/// 1-based line number.
|
||||
pub line: usize,
|
||||
/// 1-based column number (in Unicode scalar values).
|
||||
pub column: usize,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct TextRange {
|
||||
pub start: TextPosition,
|
||||
pub end: TextPosition,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ConfigWarningNotification {
|
||||
/// Concise summary of the warning.
|
||||
pub summary: String,
|
||||
/// Optional extra guidance or error details.
|
||||
pub details: Option<String>,
|
||||
/// Optional path to the config file that triggered the warning.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub path: Option<String>,
|
||||
/// Optional range for the error location inside the config file.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub range: Option<TextRange>,
|
||||
}
|
||||
181
codex-rs/app-server-protocol/src/protocol/v2/device_key.rs
Normal file
181
codex-rs/app-server-protocol/src/protocol/v2/device_key.rs
Normal file
@@ -0,0 +1,181 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use ts_rs::TS;
|
||||
|
||||
/// Device-key algorithm reported at enrollment and signing boundaries.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(rename_all = "snake_case", export_to = "v2/")]
|
||||
pub enum DeviceKeyAlgorithm {
|
||||
EcdsaP256Sha256,
|
||||
}
|
||||
|
||||
/// Platform protection class for a controller-local device key.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(rename_all = "snake_case", export_to = "v2/")]
|
||||
pub enum DeviceKeyProtectionClass {
|
||||
HardwareSecureEnclave,
|
||||
HardwareTpm,
|
||||
OsProtectedNonextractable,
|
||||
}
|
||||
|
||||
/// Protection policy for creating or loading a controller-local device key.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(rename_all = "snake_case", export_to = "v2/")]
|
||||
pub enum DeviceKeyProtectionPolicy {
|
||||
HardwareOnly,
|
||||
AllowOsProtectedNonextractable,
|
||||
}
|
||||
|
||||
/// Create a controller-local device key with a random key id.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct DeviceKeyCreateParams {
|
||||
/// Defaults to `hardware_only` when omitted.
|
||||
#[ts(optional = nullable)]
|
||||
pub protection_policy: Option<DeviceKeyProtectionPolicy>,
|
||||
pub account_user_id: String,
|
||||
pub client_id: String,
|
||||
}
|
||||
|
||||
/// Device-key metadata and public key returned by create/public APIs.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct DeviceKeyCreateResponse {
|
||||
pub key_id: String,
|
||||
/// SubjectPublicKeyInfo DER encoded as base64.
|
||||
pub public_key_spki_der_base64: String,
|
||||
pub algorithm: DeviceKeyAlgorithm,
|
||||
pub protection_class: DeviceKeyProtectionClass,
|
||||
}
|
||||
|
||||
/// Fetch a controller-local device key public key by id.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct DeviceKeyPublicParams {
|
||||
pub key_id: String,
|
||||
}
|
||||
|
||||
/// Device-key public metadata returned by `device/key/public`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct DeviceKeyPublicResponse {
|
||||
pub key_id: String,
|
||||
/// SubjectPublicKeyInfo DER encoded as base64.
|
||||
pub public_key_spki_der_base64: String,
|
||||
pub algorithm: DeviceKeyAlgorithm,
|
||||
pub protection_class: DeviceKeyProtectionClass,
|
||||
}
|
||||
|
||||
/// Current remote-control connection status and environment id exposed to clients.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct RemoteControlStatusChangedNotification {
|
||||
pub status: RemoteControlConnectionStatus,
|
||||
pub environment_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase", export_to = "v2/")]
|
||||
pub enum RemoteControlConnectionStatus {
|
||||
Disabled,
|
||||
Connecting,
|
||||
Connected,
|
||||
Errored,
|
||||
}
|
||||
|
||||
/// Audience for a remote-control client connection device-key proof.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(rename_all = "snake_case", export_to = "v2/")]
|
||||
pub enum RemoteControlClientConnectionAudience {
|
||||
RemoteControlClientWebsocket,
|
||||
}
|
||||
|
||||
/// Audience for a remote-control client enrollment device-key proof.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(rename_all = "snake_case", export_to = "v2/")]
|
||||
pub enum RemoteControlClientEnrollmentAudience {
|
||||
RemoteControlClientEnrollment,
|
||||
}
|
||||
|
||||
/// Structured payloads accepted by `device/key/sign`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[ts(tag = "type", export_to = "v2/")]
|
||||
pub enum DeviceKeySignPayload {
|
||||
/// Payload bound to one remote-control controller websocket `/client` connection challenge.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
RemoteControlClientConnection {
|
||||
nonce: String,
|
||||
audience: RemoteControlClientConnectionAudience,
|
||||
/// Backend-issued websocket session id that this proof authorizes.
|
||||
session_id: String,
|
||||
/// Origin of the backend endpoint that issued the challenge and will verify this proof.
|
||||
target_origin: String,
|
||||
/// Websocket route path that this proof authorizes.
|
||||
target_path: String,
|
||||
account_user_id: String,
|
||||
client_id: String,
|
||||
/// Remote-control token expiration as Unix seconds.
|
||||
#[ts(type = "number")]
|
||||
token_expires_at: i64,
|
||||
/// SHA-256 of the controller-scoped remote-control token, encoded as unpadded base64url.
|
||||
token_sha256_base64url: String,
|
||||
/// Must contain exactly `remote_control_controller_websocket`.
|
||||
scopes: Vec<String>,
|
||||
},
|
||||
/// Payload bound to a remote-control client `/client/enroll` ownership challenge.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
RemoteControlClientEnrollment {
|
||||
nonce: String,
|
||||
audience: RemoteControlClientEnrollmentAudience,
|
||||
/// Backend-issued enrollment challenge id that this proof authorizes.
|
||||
challenge_id: String,
|
||||
/// Origin of the backend endpoint that issued the challenge and will verify this proof.
|
||||
target_origin: String,
|
||||
/// HTTP route path that this proof authorizes.
|
||||
target_path: String,
|
||||
account_user_id: String,
|
||||
client_id: String,
|
||||
/// SHA-256 of the requested device identity operation, encoded as unpadded base64url.
|
||||
device_identity_sha256_base64url: String,
|
||||
/// Enrollment challenge expiration as Unix seconds.
|
||||
#[ts(type = "number")]
|
||||
challenge_expires_at: i64,
|
||||
},
|
||||
}
|
||||
|
||||
/// Sign an accepted structured payload with a controller-local device key.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct DeviceKeySignParams {
|
||||
pub key_id: String,
|
||||
pub payload: DeviceKeySignPayload,
|
||||
}
|
||||
|
||||
/// ASN.1 DER signature returned by `device/key/sign`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct DeviceKeySignResponse {
|
||||
/// ECDSA signature DER encoded as base64.
|
||||
pub signature_der_base64: String,
|
||||
/// Exact bytes signed by the device key, encoded as base64. Verifiers must verify this byte
|
||||
/// string directly and must not reserialize `payload`.
|
||||
pub signed_payload_base64: String,
|
||||
pub algorithm: DeviceKeyAlgorithm,
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::BTreeMap;
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ExperimentalFeatureListParams {
|
||||
/// Opaque pagination cursor returned by a previous call.
|
||||
#[ts(optional = nullable)]
|
||||
pub cursor: Option<String>,
|
||||
/// Optional page size; defaults to a reasonable server-side value.
|
||||
#[ts(optional = nullable)]
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum ExperimentalFeatureStage {
|
||||
/// Feature is available for user testing and feedback.
|
||||
Beta,
|
||||
/// Feature is still being built and not ready for broad use.
|
||||
UnderDevelopment,
|
||||
/// Feature is production-ready.
|
||||
Stable,
|
||||
/// Feature is deprecated and should be avoided.
|
||||
Deprecated,
|
||||
/// Feature flag is retained only for backwards compatibility.
|
||||
Removed,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ExperimentalFeature {
|
||||
/// Stable key used in config.toml and CLI flag toggles.
|
||||
pub name: String,
|
||||
/// Lifecycle stage of this feature flag.
|
||||
pub stage: ExperimentalFeatureStage,
|
||||
/// User-facing display name shown in the experimental features UI.
|
||||
/// Null when this feature is not in beta.
|
||||
pub display_name: Option<String>,
|
||||
/// Short summary describing what the feature does.
|
||||
/// Null when this feature is not in beta.
|
||||
pub description: Option<String>,
|
||||
/// Announcement copy shown to users when the feature is introduced.
|
||||
/// Null when this feature is not in beta.
|
||||
pub announcement: Option<String>,
|
||||
/// Whether this feature is currently enabled in the loaded config.
|
||||
pub enabled: bool,
|
||||
/// Whether this feature is enabled by default.
|
||||
pub default_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ExperimentalFeatureListResponse {
|
||||
pub data: Vec<ExperimentalFeature>,
|
||||
/// Opaque cursor to pass to the next call to continue after the last item.
|
||||
/// If None, there are no more items to return.
|
||||
pub next_cursor: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ExperimentalFeatureEnablementSetParams {
|
||||
/// Process-wide runtime feature enablement keyed by canonical feature name.
|
||||
///
|
||||
/// Only named features are updated. Omitted features are left unchanged.
|
||||
/// Send an empty map for a no-op.
|
||||
pub enablement: BTreeMap<String, bool>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ExperimentalFeatureEnablementSetResponse {
|
||||
/// Feature enablement entries updated by this request.
|
||||
pub enablement: BTreeMap<String, bool>,
|
||||
}
|
||||
29
codex-rs/app-server-protocol/src/protocol/v2/feedback.rs
Normal file
29
codex-rs/app-server-protocol/src/protocol/v2/feedback.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::PathBuf;
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FeedbackUploadParams {
|
||||
pub classification: String,
|
||||
#[ts(optional = nullable)]
|
||||
pub reason: Option<String>,
|
||||
#[ts(optional = nullable)]
|
||||
pub thread_id: Option<String>,
|
||||
pub include_logs: bool,
|
||||
#[ts(optional = nullable)]
|
||||
pub extra_log_files: Option<Vec<PathBuf>>,
|
||||
#[ts(optional = nullable)]
|
||||
pub tags: Option<BTreeMap<String, String>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FeedbackUploadResponse {
|
||||
pub thread_id: String,
|
||||
}
|
||||
204
codex-rs/app-server-protocol/src/protocol/v2/fs.rs
Normal file
204
codex-rs/app-server-protocol/src/protocol/v2/fs.rs
Normal file
@@ -0,0 +1,204 @@
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use ts_rs::TS;
|
||||
|
||||
/// Read a file from the host filesystem.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsReadFileParams {
|
||||
/// Absolute path to read.
|
||||
pub path: AbsolutePathBuf,
|
||||
}
|
||||
|
||||
/// Base64-encoded file contents returned by `fs/readFile`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsReadFileResponse {
|
||||
/// File contents encoded as base64.
|
||||
pub data_base64: String,
|
||||
}
|
||||
|
||||
/// Write a file on the host filesystem.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsWriteFileParams {
|
||||
/// Absolute path to write.
|
||||
pub path: AbsolutePathBuf,
|
||||
/// File contents encoded as base64.
|
||||
pub data_base64: String,
|
||||
}
|
||||
|
||||
/// Successful response for `fs/writeFile`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsWriteFileResponse {}
|
||||
|
||||
/// Create a directory on the host filesystem.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsCreateDirectoryParams {
|
||||
/// Absolute directory path to create.
|
||||
pub path: AbsolutePathBuf,
|
||||
/// Whether parent directories should also be created. Defaults to `true`.
|
||||
#[ts(optional = nullable)]
|
||||
pub recursive: Option<bool>,
|
||||
}
|
||||
|
||||
/// Successful response for `fs/createDirectory`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsCreateDirectoryResponse {}
|
||||
|
||||
/// Request metadata for an absolute path.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsGetMetadataParams {
|
||||
/// Absolute path to inspect.
|
||||
pub path: AbsolutePathBuf,
|
||||
}
|
||||
|
||||
/// Metadata returned by `fs/getMetadata`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsGetMetadataResponse {
|
||||
/// Whether the path resolves to a directory.
|
||||
pub is_directory: bool,
|
||||
/// Whether the path resolves to a regular file.
|
||||
pub is_file: bool,
|
||||
/// Whether the path itself is a symbolic link.
|
||||
pub is_symlink: bool,
|
||||
/// File creation time in Unix milliseconds when available, otherwise `0`.
|
||||
#[ts(type = "number")]
|
||||
pub created_at_ms: i64,
|
||||
/// File modification time in Unix milliseconds when available, otherwise `0`.
|
||||
#[ts(type = "number")]
|
||||
pub modified_at_ms: i64,
|
||||
}
|
||||
|
||||
/// List direct child names for a directory.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsReadDirectoryParams {
|
||||
/// Absolute directory path to read.
|
||||
pub path: AbsolutePathBuf,
|
||||
}
|
||||
|
||||
/// A directory entry returned by `fs/readDirectory`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsReadDirectoryEntry {
|
||||
/// Direct child entry name only, not an absolute or relative path.
|
||||
pub file_name: String,
|
||||
/// Whether this entry resolves to a directory.
|
||||
pub is_directory: bool,
|
||||
/// Whether this entry resolves to a regular file.
|
||||
pub is_file: bool,
|
||||
}
|
||||
|
||||
/// Directory entries returned by `fs/readDirectory`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsReadDirectoryResponse {
|
||||
/// Direct child entries in the requested directory.
|
||||
pub entries: Vec<FsReadDirectoryEntry>,
|
||||
}
|
||||
|
||||
/// Remove a file or directory tree from the host filesystem.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsRemoveParams {
|
||||
/// Absolute path to remove.
|
||||
pub path: AbsolutePathBuf,
|
||||
/// Whether directory removal should recurse. Defaults to `true`.
|
||||
#[ts(optional = nullable)]
|
||||
pub recursive: Option<bool>,
|
||||
/// Whether missing paths should be ignored. Defaults to `true`.
|
||||
#[ts(optional = nullable)]
|
||||
pub force: Option<bool>,
|
||||
}
|
||||
|
||||
/// Successful response for `fs/remove`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsRemoveResponse {}
|
||||
|
||||
/// Copy a file or directory tree on the host filesystem.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsCopyParams {
|
||||
/// Absolute source path.
|
||||
pub source_path: AbsolutePathBuf,
|
||||
/// Absolute destination path.
|
||||
pub destination_path: AbsolutePathBuf,
|
||||
/// Required for directory copies; ignored for file copies.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub recursive: bool,
|
||||
}
|
||||
|
||||
/// Successful response for `fs/copy`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsCopyResponse {}
|
||||
|
||||
/// Start filesystem watch notifications for an absolute path.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsWatchParams {
|
||||
/// Connection-scoped watch identifier used for `fs/unwatch` and `fs/changed`.
|
||||
pub watch_id: String,
|
||||
/// Absolute file or directory path to watch.
|
||||
pub path: AbsolutePathBuf,
|
||||
}
|
||||
|
||||
/// Successful response for `fs/watch`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsWatchResponse {
|
||||
/// Canonicalized path associated with the watch.
|
||||
pub path: AbsolutePathBuf,
|
||||
}
|
||||
|
||||
/// Stop filesystem watch notifications for a prior `fs/watch`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsUnwatchParams {
|
||||
/// Watch identifier previously provided to `fs/watch`.
|
||||
pub watch_id: String,
|
||||
}
|
||||
|
||||
/// Successful response for `fs/unwatch`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsUnwatchResponse {}
|
||||
|
||||
/// Filesystem watch notification emitted for `fs/watch` subscribers.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FsChangedNotification {
|
||||
/// Watch identifier previously provided to `fs/watch`.
|
||||
pub watch_id: String,
|
||||
/// File or directory paths associated with this event.
|
||||
pub changed_paths: Vec<AbsolutePathBuf>,
|
||||
}
|
||||
154
codex-rs/app-server-protocol/src/protocol/v2/hook.rs
Normal file
154
codex-rs/app-server-protocol/src/protocol/v2/hook.rs
Normal file
@@ -0,0 +1,154 @@
|
||||
use super::shared::v2_enum_from_core;
|
||||
use codex_protocol::protocol::HookEventName as CoreHookEventName;
|
||||
use codex_protocol::protocol::HookExecutionMode as CoreHookExecutionMode;
|
||||
use codex_protocol::protocol::HookHandlerType as CoreHookHandlerType;
|
||||
use codex_protocol::protocol::HookOutputEntry as CoreHookOutputEntry;
|
||||
use codex_protocol::protocol::HookOutputEntryKind as CoreHookOutputEntryKind;
|
||||
use codex_protocol::protocol::HookRunStatus as CoreHookRunStatus;
|
||||
use codex_protocol::protocol::HookRunSummary as CoreHookRunSummary;
|
||||
use codex_protocol::protocol::HookScope as CoreHookScope;
|
||||
use codex_protocol::protocol::HookSource as CoreHookSource;
|
||||
use codex_protocol::protocol::HookTrustStatus as CoreHookTrustStatus;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use ts_rs::TS;
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum HookEventName from CoreHookEventName {
|
||||
PreToolUse, PermissionRequest, PostToolUse, PreCompact, PostCompact, SessionStart, UserPromptSubmit, Stop
|
||||
}
|
||||
);
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum HookHandlerType from CoreHookHandlerType {
|
||||
Command, Prompt, Agent
|
||||
}
|
||||
);
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum HookExecutionMode from CoreHookExecutionMode {
|
||||
Sync, Async
|
||||
}
|
||||
);
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum HookScope from CoreHookScope {
|
||||
Thread, Turn
|
||||
}
|
||||
);
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum HookSource from CoreHookSource {
|
||||
System,
|
||||
User,
|
||||
Project,
|
||||
Mdm,
|
||||
SessionFlags,
|
||||
Plugin,
|
||||
CloudRequirements,
|
||||
LegacyManagedConfigFile,
|
||||
LegacyManagedConfigMdm,
|
||||
Unknown,
|
||||
}
|
||||
);
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum HookTrustStatus from CoreHookTrustStatus {
|
||||
Managed, Untrusted, Trusted, Modified
|
||||
}
|
||||
);
|
||||
|
||||
fn default_hook_source() -> HookSource {
|
||||
HookSource::Unknown
|
||||
}
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum HookRunStatus from CoreHookRunStatus {
|
||||
Running, Completed, Failed, Blocked, Stopped
|
||||
}
|
||||
);
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum HookOutputEntryKind from CoreHookOutputEntryKind {
|
||||
Warning, Stop, Feedback, Context, Error
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct HookOutputEntry {
|
||||
pub kind: HookOutputEntryKind,
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl From<CoreHookOutputEntry> for HookOutputEntry {
|
||||
fn from(value: CoreHookOutputEntry) -> Self {
|
||||
Self {
|
||||
kind: value.kind.into(),
|
||||
text: value.text,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct HookRunSummary {
|
||||
pub id: String,
|
||||
pub event_name: HookEventName,
|
||||
pub handler_type: HookHandlerType,
|
||||
pub execution_mode: HookExecutionMode,
|
||||
pub scope: HookScope,
|
||||
pub source_path: AbsolutePathBuf,
|
||||
#[serde(default = "default_hook_source")]
|
||||
pub source: HookSource,
|
||||
pub display_order: i64,
|
||||
pub status: HookRunStatus,
|
||||
pub status_message: Option<String>,
|
||||
pub started_at: i64,
|
||||
pub completed_at: Option<i64>,
|
||||
pub duration_ms: Option<i64>,
|
||||
pub entries: Vec<HookOutputEntry>,
|
||||
}
|
||||
|
||||
impl From<CoreHookRunSummary> for HookRunSummary {
|
||||
fn from(value: CoreHookRunSummary) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
event_name: value.event_name.into(),
|
||||
handler_type: value.handler_type.into(),
|
||||
execution_mode: value.execution_mode.into(),
|
||||
scope: value.scope.into(),
|
||||
source_path: value.source_path,
|
||||
source: value.source.into(),
|
||||
display_order: value.display_order,
|
||||
status: value.status.into(),
|
||||
status_message: value.status_message,
|
||||
started_at: value.started_at,
|
||||
completed_at: value.completed_at,
|
||||
duration_ms: value.duration_ms,
|
||||
entries: value.entries.into_iter().map(Into::into).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct HookStartedNotification {
|
||||
pub thread_id: String,
|
||||
pub turn_id: Option<String>,
|
||||
pub run: HookRunSummary,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct HookCompletedNotification {
|
||||
pub thread_id: String,
|
||||
pub turn_id: Option<String>,
|
||||
pub run: HookRunSummary,
|
||||
}
|
||||
1432
codex-rs/app-server-protocol/src/protocol/v2/item.rs
Normal file
1432
codex-rs/app-server-protocol/src/protocol/v2/item.rs
Normal file
File diff suppressed because it is too large
Load Diff
703
codex-rs/app-server-protocol/src/protocol/v2/mcp.rs
Normal file
703
codex-rs/app-server-protocol/src/protocol/v2/mcp.rs
Normal file
@@ -0,0 +1,703 @@
|
||||
use super::shared::v2_enum_from_core;
|
||||
use codex_protocol::approvals::ElicitationRequest as CoreElicitationRequest;
|
||||
use codex_protocol::items::McpToolCallError as CoreMcpToolCallError;
|
||||
use codex_protocol::mcp::CallToolResult as CoreMcpCallToolResult;
|
||||
use codex_protocol::mcp::Resource as McpResource;
|
||||
pub use codex_protocol::mcp::ResourceContent as McpResourceContent;
|
||||
use codex_protocol::mcp::ResourceTemplate as McpResourceTemplate;
|
||||
use codex_protocol::mcp::Tool as McpTool;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
use std::collections::BTreeMap;
|
||||
use ts_rs::TS;
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum McpAuthStatus from codex_protocol::protocol::McpAuthStatus {
|
||||
Unsupported,
|
||||
NotLoggedIn,
|
||||
BearerToken,
|
||||
OAuth
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ListMcpServerStatusParams {
|
||||
/// Opaque pagination cursor returned by a previous call.
|
||||
#[ts(optional = nullable)]
|
||||
pub cursor: Option<String>,
|
||||
/// Optional page size; defaults to a server-defined value.
|
||||
#[ts(optional = nullable)]
|
||||
pub limit: Option<u32>,
|
||||
/// Controls how much MCP inventory data to fetch for each server.
|
||||
/// Defaults to `Full` when omitted.
|
||||
#[ts(optional = nullable)]
|
||||
pub detail: Option<McpServerStatusDetail>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase", export_to = "v2/")]
|
||||
pub enum McpServerStatusDetail {
|
||||
Full,
|
||||
ToolsAndAuthOnly,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpServerStatus {
|
||||
pub name: String,
|
||||
pub tools: std::collections::HashMap<String, McpTool>,
|
||||
pub resources: Vec<McpResource>,
|
||||
pub resource_templates: Vec<McpResourceTemplate>,
|
||||
pub auth_status: McpAuthStatus,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ListMcpServerStatusResponse {
|
||||
pub data: Vec<McpServerStatus>,
|
||||
/// Opaque cursor to pass to the next call to continue after the last item.
|
||||
/// If None, there are no more items to return.
|
||||
pub next_cursor: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpResourceReadParams {
|
||||
#[ts(optional = nullable)]
|
||||
pub thread_id: Option<String>,
|
||||
pub server: String,
|
||||
pub uri: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpResourceReadResponse {
|
||||
pub contents: Vec<McpResourceContent>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpServerToolCallParams {
|
||||
pub thread_id: String,
|
||||
pub server: String,
|
||||
pub tool: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub arguments: Option<JsonValue>,
|
||||
#[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub meta: Option<JsonValue>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpServerToolCallResponse {
|
||||
pub content: Vec<JsonValue>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub structured_content: Option<JsonValue>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub is_error: Option<bool>,
|
||||
#[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub meta: Option<JsonValue>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpToolCallResult {
|
||||
// NOTE: `rmcp::model::Content` (and its `RawContent` variants) would be a more precise Rust
|
||||
// representation of MCP content blocks. We intentionally use `serde_json::Value` here because
|
||||
// this crate exports JSON schema + TS types (`schemars`/`ts-rs`), and the rmcp model types
|
||||
// aren't set up to be schema/TS friendly (and would introduce heavier coupling to rmcp's Rust
|
||||
// representations). Using `JsonValue` keeps the payload wire-shaped and easy to export.
|
||||
pub content: Vec<JsonValue>,
|
||||
pub structured_content: Option<JsonValue>,
|
||||
#[serde(rename = "_meta")]
|
||||
#[ts(rename = "_meta")]
|
||||
pub meta: Option<JsonValue>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpToolCallError {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl From<CoreMcpCallToolResult> for McpServerToolCallResponse {
|
||||
fn from(result: CoreMcpCallToolResult) -> Self {
|
||||
Self {
|
||||
content: result.content,
|
||||
structured_content: result.structured_content,
|
||||
is_error: result.is_error,
|
||||
meta: result.meta,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreMcpCallToolResult> for McpToolCallResult {
|
||||
fn from(result: CoreMcpCallToolResult) -> Self {
|
||||
Self {
|
||||
content: result.content,
|
||||
structured_content: result.structured_content,
|
||||
meta: result.meta,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreMcpToolCallError> for McpToolCallError {
|
||||
fn from(error: CoreMcpToolCallError) -> Self {
|
||||
Self {
|
||||
message: error.message,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpServerRefreshParams {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpServerRefreshResponse {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpServerOauthLoginParams {
|
||||
pub name: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional = nullable)]
|
||||
pub scopes: Option<Vec<String>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional = nullable)]
|
||||
pub timeout_secs: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpServerOauthLoginResponse {
|
||||
pub authorization_url: String,
|
||||
}
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpToolCallProgressNotification {
|
||||
pub thread_id: String,
|
||||
pub turn_id: String,
|
||||
pub item_id: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpServerOauthLoginCompletedNotification {
|
||||
pub name: String,
|
||||
pub success: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum McpServerStartupState {
|
||||
Starting,
|
||||
Ready,
|
||||
Failed,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpServerStatusUpdatedNotification {
|
||||
pub name: String,
|
||||
pub status: McpServerStartupState,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum McpServerElicitationAction {
|
||||
Accept,
|
||||
Decline,
|
||||
Cancel,
|
||||
}
|
||||
|
||||
impl McpServerElicitationAction {
|
||||
pub fn to_core(self) -> codex_protocol::approvals::ElicitationAction {
|
||||
match self {
|
||||
Self::Accept => codex_protocol::approvals::ElicitationAction::Accept,
|
||||
Self::Decline => codex_protocol::approvals::ElicitationAction::Decline,
|
||||
Self::Cancel => codex_protocol::approvals::ElicitationAction::Cancel,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<McpServerElicitationAction> for rmcp::model::ElicitationAction {
|
||||
fn from(value: McpServerElicitationAction) -> Self {
|
||||
match value {
|
||||
McpServerElicitationAction::Accept => Self::Accept,
|
||||
McpServerElicitationAction::Decline => Self::Decline,
|
||||
McpServerElicitationAction::Cancel => Self::Cancel,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rmcp::model::ElicitationAction> for McpServerElicitationAction {
|
||||
fn from(value: rmcp::model::ElicitationAction) -> Self {
|
||||
match value {
|
||||
rmcp::model::ElicitationAction::Accept => Self::Accept,
|
||||
rmcp::model::ElicitationAction::Decline => Self::Decline,
|
||||
rmcp::model::ElicitationAction::Cancel => Self::Cancel,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpServerElicitationRequestParams {
|
||||
pub thread_id: String,
|
||||
/// Active Codex turn when this elicitation was observed, if app-server could correlate one.
|
||||
///
|
||||
/// This is nullable because MCP models elicitation as a standalone server-to-client request
|
||||
/// identified by the MCP server request id. It may be triggered during a turn, but turn
|
||||
/// context is app-server correlation rather than part of the protocol identity of the
|
||||
/// elicitation itself.
|
||||
pub turn_id: Option<String>,
|
||||
pub server_name: String,
|
||||
#[serde(flatten)]
|
||||
pub request: McpServerElicitationRequest,
|
||||
// TODO: When core can correlate an elicitation with an MCP tool call, expose the associated
|
||||
// McpToolCall item id here as an optional field. The current core event does not carry that
|
||||
// association.
|
||||
}
|
||||
|
||||
/// Typed form schema for MCP `elicitation/create` requests.
|
||||
///
|
||||
/// This matches the `requestedSchema` shape from the MCP 2025-11-25
|
||||
/// `ElicitRequestFormParams` schema.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpElicitationSchema {
|
||||
#[serde(rename = "$schema", skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional, rename = "$schema")]
|
||||
pub schema_uri: Option<String>,
|
||||
#[serde(rename = "type")]
|
||||
#[ts(rename = "type")]
|
||||
pub type_: McpElicitationObjectType,
|
||||
pub properties: BTreeMap<String, McpElicitationPrimitiveSchema>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub required: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum McpElicitationObjectType {
|
||||
Object,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(untagged)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum McpElicitationPrimitiveSchema {
|
||||
Enum(McpElicitationEnumSchema),
|
||||
String(McpElicitationStringSchema),
|
||||
Number(McpElicitationNumberSchema),
|
||||
Boolean(McpElicitationBooleanSchema),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpElicitationStringSchema {
|
||||
#[serde(rename = "type")]
|
||||
#[ts(rename = "type")]
|
||||
pub type_: McpElicitationStringType,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub title: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub description: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub min_length: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub max_length: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub format: Option<McpElicitationStringFormat>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub default: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum McpElicitationStringType {
|
||||
String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[ts(rename_all = "kebab-case", export_to = "v2/")]
|
||||
pub enum McpElicitationStringFormat {
|
||||
Email,
|
||||
Uri,
|
||||
Date,
|
||||
DateTime,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpElicitationNumberSchema {
|
||||
#[serde(rename = "type")]
|
||||
#[ts(rename = "type")]
|
||||
pub type_: McpElicitationNumberType,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub title: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub description: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub minimum: Option<f64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub maximum: Option<f64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub default: Option<f64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum McpElicitationNumberType {
|
||||
Number,
|
||||
Integer,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpElicitationBooleanSchema {
|
||||
#[serde(rename = "type")]
|
||||
#[ts(rename = "type")]
|
||||
pub type_: McpElicitationBooleanType,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub title: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub description: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub default: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum McpElicitationBooleanType {
|
||||
Boolean,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(untagged)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum McpElicitationEnumSchema {
|
||||
SingleSelect(McpElicitationSingleSelectEnumSchema),
|
||||
MultiSelect(McpElicitationMultiSelectEnumSchema),
|
||||
Legacy(McpElicitationLegacyTitledEnumSchema),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpElicitationLegacyTitledEnumSchema {
|
||||
#[serde(rename = "type")]
|
||||
#[ts(rename = "type")]
|
||||
pub type_: McpElicitationStringType,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub title: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub description: Option<String>,
|
||||
#[serde(rename = "enum")]
|
||||
#[ts(rename = "enum")]
|
||||
pub enum_: Vec<String>,
|
||||
#[serde(rename = "enumNames", skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional, rename = "enumNames")]
|
||||
pub enum_names: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub default: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(untagged)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum McpElicitationSingleSelectEnumSchema {
|
||||
Untitled(McpElicitationUntitledSingleSelectEnumSchema),
|
||||
Titled(McpElicitationTitledSingleSelectEnumSchema),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpElicitationUntitledSingleSelectEnumSchema {
|
||||
#[serde(rename = "type")]
|
||||
#[ts(rename = "type")]
|
||||
pub type_: McpElicitationStringType,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub title: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub description: Option<String>,
|
||||
#[serde(rename = "enum")]
|
||||
#[ts(rename = "enum")]
|
||||
pub enum_: Vec<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub default: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpElicitationTitledSingleSelectEnumSchema {
|
||||
#[serde(rename = "type")]
|
||||
#[ts(rename = "type")]
|
||||
pub type_: McpElicitationStringType,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub title: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub description: Option<String>,
|
||||
#[serde(rename = "oneOf")]
|
||||
#[ts(rename = "oneOf")]
|
||||
pub one_of: Vec<McpElicitationConstOption>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub default: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(untagged)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum McpElicitationMultiSelectEnumSchema {
|
||||
Untitled(McpElicitationUntitledMultiSelectEnumSchema),
|
||||
Titled(McpElicitationTitledMultiSelectEnumSchema),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpElicitationUntitledMultiSelectEnumSchema {
|
||||
#[serde(rename = "type")]
|
||||
#[ts(rename = "type")]
|
||||
pub type_: McpElicitationArrayType,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub title: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub description: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub min_items: Option<u64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub max_items: Option<u64>,
|
||||
pub items: McpElicitationUntitledEnumItems,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub default: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpElicitationTitledMultiSelectEnumSchema {
|
||||
#[serde(rename = "type")]
|
||||
#[ts(rename = "type")]
|
||||
pub type_: McpElicitationArrayType,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub title: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub description: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub min_items: Option<u64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub max_items: Option<u64>,
|
||||
pub items: McpElicitationTitledEnumItems,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub default: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum McpElicitationArrayType {
|
||||
Array,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpElicitationUntitledEnumItems {
|
||||
#[serde(rename = "type")]
|
||||
#[ts(rename = "type")]
|
||||
pub type_: McpElicitationStringType,
|
||||
#[serde(rename = "enum")]
|
||||
#[ts(rename = "enum")]
|
||||
pub enum_: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpElicitationTitledEnumItems {
|
||||
#[serde(rename = "anyOf", alias = "oneOf")]
|
||||
#[ts(rename = "anyOf")]
|
||||
pub any_of: Vec<McpElicitationConstOption>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpElicitationConstOption {
|
||||
#[serde(rename = "const")]
|
||||
#[ts(rename = "const")]
|
||||
pub const_: String,
|
||||
pub title: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(tag = "mode", rename_all = "camelCase")]
|
||||
#[ts(tag = "mode")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum McpServerElicitationRequest {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
Form {
|
||||
#[serde(rename = "_meta")]
|
||||
#[ts(rename = "_meta")]
|
||||
meta: Option<JsonValue>,
|
||||
message: String,
|
||||
requested_schema: McpElicitationSchema,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
Url {
|
||||
#[serde(rename = "_meta")]
|
||||
#[ts(rename = "_meta")]
|
||||
meta: Option<JsonValue>,
|
||||
message: String,
|
||||
url: String,
|
||||
elicitation_id: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl TryFrom<CoreElicitationRequest> for McpServerElicitationRequest {
|
||||
type Error = serde_json::Error;
|
||||
|
||||
fn try_from(value: CoreElicitationRequest) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
CoreElicitationRequest::Form {
|
||||
meta,
|
||||
message,
|
||||
requested_schema,
|
||||
} => Ok(Self::Form {
|
||||
meta,
|
||||
message,
|
||||
requested_schema: serde_json::from_value(requested_schema)?,
|
||||
}),
|
||||
CoreElicitationRequest::Url {
|
||||
meta,
|
||||
message,
|
||||
url,
|
||||
elicitation_id,
|
||||
} => Ok(Self::Url {
|
||||
meta,
|
||||
message,
|
||||
url,
|
||||
elicitation_id,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct McpServerElicitationRequestResponse {
|
||||
pub action: McpServerElicitationAction,
|
||||
/// Structured user input for accepted elicitations, mirroring RMCP `CreateElicitationResult`.
|
||||
///
|
||||
/// This is nullable because decline/cancel responses have no content.
|
||||
pub content: Option<JsonValue>,
|
||||
/// Optional client metadata for form-mode action handling.
|
||||
#[serde(rename = "_meta")]
|
||||
#[ts(rename = "_meta")]
|
||||
pub meta: Option<JsonValue>,
|
||||
}
|
||||
|
||||
impl From<McpServerElicitationRequestResponse> for rmcp::model::CreateElicitationResult {
|
||||
fn from(value: McpServerElicitationRequestResponse) -> Self {
|
||||
Self {
|
||||
action: value.action.into(),
|
||||
content: value.content,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rmcp::model::CreateElicitationResult> for McpServerElicitationRequestResponse {
|
||||
fn from(value: rmcp::model::CreateElicitationResult) -> Self {
|
||||
Self {
|
||||
action: value.action.into(),
|
||||
content: value.content,
|
||||
meta: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
53
codex-rs/app-server-protocol/src/protocol/v2/mod.rs
Normal file
53
codex-rs/app-server-protocol/src/protocol/v2/mod.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
mod shared;
|
||||
|
||||
mod account;
|
||||
mod apps;
|
||||
mod collaboration_mode;
|
||||
mod command_exec;
|
||||
mod config;
|
||||
mod device_key;
|
||||
mod experimental_feature;
|
||||
mod feedback;
|
||||
mod fs;
|
||||
mod hook;
|
||||
mod item;
|
||||
mod mcp;
|
||||
mod model;
|
||||
mod notification;
|
||||
mod permissions;
|
||||
mod plugin;
|
||||
mod process;
|
||||
mod realtime;
|
||||
mod review;
|
||||
mod thread;
|
||||
mod thread_data;
|
||||
mod turn;
|
||||
mod windows_sandbox;
|
||||
|
||||
pub use account::*;
|
||||
pub use apps::*;
|
||||
pub use collaboration_mode::*;
|
||||
pub use command_exec::*;
|
||||
pub use config::*;
|
||||
pub use device_key::*;
|
||||
pub use experimental_feature::*;
|
||||
pub use feedback::*;
|
||||
pub use fs::*;
|
||||
pub use hook::*;
|
||||
pub use item::*;
|
||||
pub use mcp::*;
|
||||
pub use model::*;
|
||||
pub use notification::*;
|
||||
pub use permissions::*;
|
||||
pub use plugin::*;
|
||||
pub use process::*;
|
||||
pub use realtime::*;
|
||||
pub use review::*;
|
||||
pub use shared::*;
|
||||
pub use thread::*;
|
||||
pub use thread_data::*;
|
||||
pub use turn::*;
|
||||
pub use windows_sandbox::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
151
codex-rs/app-server-protocol/src/protocol/v2/model.rs
Normal file
151
codex-rs/app-server-protocol/src/protocol/v2/model.rs
Normal file
@@ -0,0 +1,151 @@
|
||||
use super::shared::v2_enum_from_core;
|
||||
use codex_protocol::openai_models::InputModality;
|
||||
use codex_protocol::openai_models::ModelAvailabilityNux as CoreModelAvailabilityNux;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
use codex_protocol::openai_models::default_input_modalities;
|
||||
use codex_protocol::protocol::ModelRerouteReason as CoreModelRerouteReason;
|
||||
use codex_protocol::protocol::ModelVerification as CoreModelVerification;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use ts_rs::TS;
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum ModelRerouteReason from CoreModelRerouteReason {
|
||||
HighRiskCyberActivity
|
||||
}
|
||||
);
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum ModelVerification from CoreModelVerification {
|
||||
TrustedAccessForCyber
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ModelProviderCapabilitiesReadParams {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ModelProviderCapabilitiesReadResponse {
|
||||
pub namespace_tools: bool,
|
||||
pub image_generation: bool,
|
||||
pub web_search: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ModelListParams {
|
||||
/// Opaque pagination cursor returned by a previous call.
|
||||
#[ts(optional = nullable)]
|
||||
pub cursor: Option<String>,
|
||||
/// Optional page size; defaults to a reasonable server-side value.
|
||||
#[ts(optional = nullable)]
|
||||
pub limit: Option<u32>,
|
||||
/// When true, include models that are hidden from the default picker list.
|
||||
#[ts(optional = nullable)]
|
||||
pub include_hidden: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ModelAvailabilityNux {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl From<CoreModelAvailabilityNux> for ModelAvailabilityNux {
|
||||
fn from(value: CoreModelAvailabilityNux) -> Self {
|
||||
Self {
|
||||
message: value.message,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ModelServiceTier {
|
||||
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 Model {
|
||||
pub id: String,
|
||||
pub model: String,
|
||||
pub upgrade: Option<String>,
|
||||
pub upgrade_info: Option<ModelUpgradeInfo>,
|
||||
pub availability_nux: Option<ModelAvailabilityNux>,
|
||||
pub display_name: String,
|
||||
pub description: String,
|
||||
pub hidden: bool,
|
||||
pub supported_reasoning_efforts: Vec<ReasoningEffortOption>,
|
||||
pub default_reasoning_effort: ReasoningEffort,
|
||||
#[serde(default = "default_input_modalities")]
|
||||
pub input_modalities: Vec<InputModality>,
|
||||
#[serde(default)]
|
||||
pub supports_personality: bool,
|
||||
/// Deprecated: use `serviceTiers` instead.
|
||||
#[serde(default)]
|
||||
pub additional_speed_tiers: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub service_tiers: Vec<ModelServiceTier>,
|
||||
// Only one model should be marked as default.
|
||||
pub is_default: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ModelUpgradeInfo {
|
||||
pub model: String,
|
||||
pub upgrade_copy: Option<String>,
|
||||
pub model_link: Option<String>,
|
||||
pub migration_markdown: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ReasoningEffortOption {
|
||||
pub reasoning_effort: ReasoningEffort,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ModelListResponse {
|
||||
pub data: Vec<Model>,
|
||||
/// Opaque cursor to pass to the next call to continue after the last item.
|
||||
/// If None, there are no more items to return.
|
||||
pub next_cursor: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ModelReroutedNotification {
|
||||
pub thread_id: String,
|
||||
pub turn_id: String,
|
||||
pub from_model: String,
|
||||
pub to_model: String,
|
||||
pub reason: ModelRerouteReason,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ModelVerificationNotification {
|
||||
pub thread_id: String,
|
||||
pub turn_id: String,
|
||||
pub verifications: Vec<ModelVerification>,
|
||||
}
|
||||
56
codex-rs/app-server-protocol/src/protocol/v2/notification.rs
Normal file
56
codex-rs/app-server-protocol/src/protocol/v2/notification.rs
Normal file
@@ -0,0 +1,56 @@
|
||||
use super::TurnError;
|
||||
use crate::RequestId;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct DeprecationNoticeNotification {
|
||||
/// Concise summary of what is deprecated.
|
||||
pub summary: String,
|
||||
/// Optional extra guidance, such as migration steps or rationale.
|
||||
pub details: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct WarningNotification {
|
||||
/// Optional thread target when the warning applies to a specific thread.
|
||||
pub thread_id: Option<String>,
|
||||
/// Concise warning message for the user.
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct GuardianWarningNotification {
|
||||
/// Thread target for the guardian warning.
|
||||
pub thread_id: String,
|
||||
/// Concise guardian warning message for the user.
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ErrorNotification {
|
||||
pub error: TurnError,
|
||||
// Set to true if the error is transient and the app-server process will automatically retry.
|
||||
// If true, this will not interrupt a turn.
|
||||
pub will_retry: bool,
|
||||
pub thread_id: String,
|
||||
pub turn_id: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ServerRequestResolvedNotification {
|
||||
pub thread_id: String,
|
||||
pub request_id: RequestId,
|
||||
}
|
||||
854
codex-rs/app-server-protocol/src/protocol/v2/permissions.rs
Normal file
854
codex-rs/app-server-protocol/src/protocol/v2/permissions.rs
Normal file
@@ -0,0 +1,854 @@
|
||||
use super::shared::v2_enum_from_core;
|
||||
use codex_protocol::approvals::ExecPolicyAmendment as CoreExecPolicyAmendment;
|
||||
use codex_protocol::approvals::NetworkApprovalContext as CoreNetworkApprovalContext;
|
||||
use codex_protocol::approvals::NetworkApprovalProtocol as CoreNetworkApprovalProtocol;
|
||||
use codex_protocol::approvals::NetworkPolicyAmendment as CoreNetworkPolicyAmendment;
|
||||
use codex_protocol::approvals::NetworkPolicyRuleAction as CoreNetworkPolicyRuleAction;
|
||||
use codex_protocol::models::ActivePermissionProfile as CoreActivePermissionProfile;
|
||||
use codex_protocol::models::ActivePermissionProfileModification as CoreActivePermissionProfileModification;
|
||||
use codex_protocol::models::AdditionalPermissionProfile as CoreAdditionalPermissionProfile;
|
||||
use codex_protocol::models::FileSystemPermissions as CoreFileSystemPermissions;
|
||||
use codex_protocol::models::ManagedFileSystemPermissions as CoreManagedFileSystemPermissions;
|
||||
use codex_protocol::models::NetworkPermissions as CoreNetworkPermissions;
|
||||
use codex_protocol::models::PermissionProfile as CorePermissionProfile;
|
||||
use codex_protocol::permissions::FileSystemAccessMode as CoreFileSystemAccessMode;
|
||||
use codex_protocol::permissions::FileSystemPath as CoreFileSystemPath;
|
||||
use codex_protocol::permissions::FileSystemSandboxEntry as CoreFileSystemSandboxEntry;
|
||||
use codex_protocol::permissions::FileSystemSpecialPath as CoreFileSystemSpecialPath;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy as CoreNetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::NetworkAccess as CoreNetworkAccess;
|
||||
use codex_protocol::request_permissions::PermissionGrantScope as CorePermissionGrantScope;
|
||||
use codex_protocol::request_permissions::RequestPermissionProfile as CoreRequestPermissionProfile;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::path::PathBuf;
|
||||
use ts_rs::TS;
|
||||
|
||||
v2_enum_from_core! {
|
||||
pub enum NetworkApprovalProtocol from CoreNetworkApprovalProtocol {
|
||||
Http,
|
||||
Https,
|
||||
Socks5Tcp,
|
||||
Socks5Udp,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct NetworkApprovalContext {
|
||||
pub host: String,
|
||||
pub protocol: NetworkApprovalProtocol,
|
||||
}
|
||||
|
||||
impl From<CoreNetworkApprovalContext> for NetworkApprovalContext {
|
||||
fn from(value: CoreNetworkApprovalContext) -> Self {
|
||||
Self {
|
||||
host: value.host,
|
||||
protocol: value.protocol.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AdditionalFileSystemPermissions {
|
||||
/// This will be removed in favor of `entries`.
|
||||
pub read: Option<Vec<AbsolutePathBuf>>,
|
||||
/// This will be removed in favor of `entries`.
|
||||
pub write: Option<Vec<AbsolutePathBuf>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub glob_scan_max_depth: Option<NonZeroUsize>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub entries: Option<Vec<FileSystemSandboxEntry>>,
|
||||
}
|
||||
|
||||
impl From<CoreFileSystemPermissions> for AdditionalFileSystemPermissions {
|
||||
fn from(value: CoreFileSystemPermissions) -> Self {
|
||||
if let Some((read, write)) = value.legacy_read_write_roots() {
|
||||
let mut entries = Vec::with_capacity(
|
||||
read.as_ref().map_or(0, Vec::len) + write.as_ref().map_or(0, Vec::len),
|
||||
);
|
||||
if let Some(paths) = read.as_ref() {
|
||||
entries.extend(paths.iter().map(|path| FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: path.clone() },
|
||||
access: FileSystemAccessMode::Read,
|
||||
}));
|
||||
}
|
||||
if let Some(paths) = write.as_ref() {
|
||||
entries.extend(paths.iter().map(|path| FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: path.clone() },
|
||||
access: FileSystemAccessMode::Write,
|
||||
}));
|
||||
}
|
||||
Self {
|
||||
read,
|
||||
write,
|
||||
glob_scan_max_depth: None,
|
||||
entries: Some(entries),
|
||||
}
|
||||
} else {
|
||||
Self {
|
||||
read: None,
|
||||
write: None,
|
||||
glob_scan_max_depth: value.glob_scan_max_depth,
|
||||
entries: Some(
|
||||
value
|
||||
.entries
|
||||
.into_iter()
|
||||
.map(FileSystemSandboxEntry::from)
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AdditionalFileSystemPermissions> for CoreFileSystemPermissions {
|
||||
fn from(value: AdditionalFileSystemPermissions) -> Self {
|
||||
let mut permissions = if let Some(entries) = value.entries {
|
||||
Self {
|
||||
entries: entries
|
||||
.into_iter()
|
||||
.map(CoreFileSystemSandboxEntry::from)
|
||||
.collect(),
|
||||
glob_scan_max_depth: None,
|
||||
}
|
||||
} else {
|
||||
CoreFileSystemPermissions::from_read_write_roots(value.read, value.write)
|
||||
};
|
||||
permissions.glob_scan_max_depth = value.glob_scan_max_depth;
|
||||
permissions
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AdditionalNetworkPermissions {
|
||||
pub enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PermissionProfileNetworkPermissions {
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
impl From<CoreNetworkPermissions> for AdditionalNetworkPermissions {
|
||||
fn from(value: CoreNetworkPermissions) -> Self {
|
||||
Self {
|
||||
enabled: value.enabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AdditionalNetworkPermissions> for CoreNetworkPermissions {
|
||||
fn from(value: AdditionalNetworkPermissions) -> Self {
|
||||
Self {
|
||||
enabled: value.enabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreNetworkSandboxPolicy> for PermissionProfileNetworkPermissions {
|
||||
fn from(value: CoreNetworkSandboxPolicy) -> Self {
|
||||
Self {
|
||||
enabled: value.is_enabled(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PermissionProfileNetworkPermissions> for CoreNetworkSandboxPolicy {
|
||||
fn from(value: PermissionProfileNetworkPermissions) -> Self {
|
||||
if value.enabled {
|
||||
Self::Enabled
|
||||
} else {
|
||||
Self::Restricted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum FileSystemAccessMode from CoreFileSystemAccessMode {
|
||||
Read,
|
||||
Write,
|
||||
None
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||
#[ts(tag = "kind")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum FileSystemSpecialPath {
|
||||
Root,
|
||||
Minimal,
|
||||
#[serde(alias = "current_working_directory")]
|
||||
ProjectRoots {
|
||||
subpath: Option<PathBuf>,
|
||||
},
|
||||
Tmpdir,
|
||||
SlashTmp,
|
||||
Unknown {
|
||||
path: String,
|
||||
subpath: Option<PathBuf>,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<CoreFileSystemSpecialPath> for FileSystemSpecialPath {
|
||||
fn from(value: CoreFileSystemSpecialPath) -> Self {
|
||||
match value {
|
||||
CoreFileSystemSpecialPath::Root => Self::Root,
|
||||
CoreFileSystemSpecialPath::Minimal => Self::Minimal,
|
||||
CoreFileSystemSpecialPath::ProjectRoots { subpath } => Self::ProjectRoots { subpath },
|
||||
CoreFileSystemSpecialPath::Tmpdir => Self::Tmpdir,
|
||||
CoreFileSystemSpecialPath::SlashTmp => Self::SlashTmp,
|
||||
CoreFileSystemSpecialPath::Unknown { path, subpath } => Self::Unknown { path, subpath },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FileSystemSpecialPath> for CoreFileSystemSpecialPath {
|
||||
fn from(value: FileSystemSpecialPath) -> Self {
|
||||
match value {
|
||||
FileSystemSpecialPath::Root => Self::Root,
|
||||
FileSystemSpecialPath::Minimal => Self::Minimal,
|
||||
FileSystemSpecialPath::ProjectRoots { subpath } => Self::ProjectRoots { subpath },
|
||||
FileSystemSpecialPath::Tmpdir => Self::Tmpdir,
|
||||
FileSystemSpecialPath::SlashTmp => Self::SlashTmp,
|
||||
FileSystemSpecialPath::Unknown { path, subpath } => Self::Unknown { path, subpath },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
#[ts(tag = "type")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum FileSystemPath {
|
||||
Path { path: AbsolutePathBuf },
|
||||
GlobPattern { pattern: String },
|
||||
Special { value: FileSystemSpecialPath },
|
||||
}
|
||||
|
||||
impl From<CoreFileSystemPath> for FileSystemPath {
|
||||
fn from(value: CoreFileSystemPath) -> Self {
|
||||
match value {
|
||||
CoreFileSystemPath::Path { path } => Self::Path { path },
|
||||
CoreFileSystemPath::GlobPattern { pattern } => Self::GlobPattern { pattern },
|
||||
CoreFileSystemPath::Special { value } => Self::Special {
|
||||
value: value.into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FileSystemPath> for CoreFileSystemPath {
|
||||
fn from(value: FileSystemPath) -> Self {
|
||||
match value {
|
||||
FileSystemPath::Path { path } => Self::Path { path },
|
||||
FileSystemPath::GlobPattern { pattern } => Self::GlobPattern { pattern },
|
||||
FileSystemPath::Special { value } => Self::Special {
|
||||
value: value.into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct FileSystemSandboxEntry {
|
||||
pub path: FileSystemPath,
|
||||
pub access: FileSystemAccessMode,
|
||||
}
|
||||
|
||||
impl From<CoreFileSystemSandboxEntry> for FileSystemSandboxEntry {
|
||||
fn from(value: CoreFileSystemSandboxEntry) -> Self {
|
||||
Self {
|
||||
path: value.path.into(),
|
||||
access: value.access.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FileSystemSandboxEntry> for CoreFileSystemSandboxEntry {
|
||||
fn from(value: FileSystemSandboxEntry) -> Self {
|
||||
Self {
|
||||
path: value.path.into(),
|
||||
access: value.access.to_core(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[ts(tag = "type")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum PermissionProfileFileSystemPermissions {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
Restricted {
|
||||
entries: Vec<FileSystemSandboxEntry>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
glob_scan_max_depth: Option<NonZeroUsize>,
|
||||
},
|
||||
Unrestricted,
|
||||
}
|
||||
|
||||
impl From<CoreManagedFileSystemPermissions> for PermissionProfileFileSystemPermissions {
|
||||
fn from(value: CoreManagedFileSystemPermissions) -> Self {
|
||||
match value {
|
||||
CoreManagedFileSystemPermissions::Restricted {
|
||||
entries,
|
||||
glob_scan_max_depth,
|
||||
} => Self::Restricted {
|
||||
entries: entries
|
||||
.into_iter()
|
||||
.map(FileSystemSandboxEntry::from)
|
||||
.collect(),
|
||||
glob_scan_max_depth,
|
||||
},
|
||||
CoreManagedFileSystemPermissions::Unrestricted => Self::Unrestricted,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PermissionProfileFileSystemPermissions> for CoreManagedFileSystemPermissions {
|
||||
fn from(value: PermissionProfileFileSystemPermissions) -> Self {
|
||||
match value {
|
||||
PermissionProfileFileSystemPermissions::Restricted {
|
||||
entries,
|
||||
glob_scan_max_depth,
|
||||
} => Self::Restricted {
|
||||
entries: entries
|
||||
.into_iter()
|
||||
.map(CoreFileSystemSandboxEntry::from)
|
||||
.collect(),
|
||||
glob_scan_max_depth,
|
||||
},
|
||||
PermissionProfileFileSystemPermissions::Unrestricted => Self::Unrestricted,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[ts(tag = "type")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum PermissionProfile {
|
||||
/// Codex owns sandbox construction for this profile.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
Managed {
|
||||
network: PermissionProfileNetworkPermissions,
|
||||
file_system: PermissionProfileFileSystemPermissions,
|
||||
},
|
||||
/// Do not apply an outer sandbox.
|
||||
Disabled,
|
||||
/// Filesystem isolation is enforced by an external caller.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
External {
|
||||
network: PermissionProfileNetworkPermissions,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<CorePermissionProfile> for PermissionProfile {
|
||||
fn from(value: CorePermissionProfile) -> Self {
|
||||
match value {
|
||||
CorePermissionProfile::Managed {
|
||||
file_system,
|
||||
network,
|
||||
} => Self::Managed {
|
||||
network: network.into(),
|
||||
file_system: file_system.into(),
|
||||
},
|
||||
CorePermissionProfile::Disabled => Self::Disabled,
|
||||
CorePermissionProfile::External { network } => Self::External {
|
||||
network: network.into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PermissionProfile> for CorePermissionProfile {
|
||||
fn from(value: PermissionProfile) -> Self {
|
||||
match value {
|
||||
PermissionProfile::Managed {
|
||||
file_system,
|
||||
network,
|
||||
} => Self::Managed {
|
||||
file_system: file_system.into(),
|
||||
network: network.into(),
|
||||
},
|
||||
PermissionProfile::Disabled => Self::Disabled,
|
||||
PermissionProfile::External { network } => Self::External {
|
||||
network: network.into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ActivePermissionProfile {
|
||||
/// Identifier from `default_permissions` or the implicit built-in default,
|
||||
/// such as `:workspace` or a user-defined `[permissions.<id>]` profile.
|
||||
pub id: String,
|
||||
/// Parent profile identifier once permissions profiles support
|
||||
/// inheritance. This is currently always `null`.
|
||||
#[serde(default)]
|
||||
pub extends: Option<String>,
|
||||
/// Bounded user-requested modifications applied on top of the named
|
||||
/// profile, if any.
|
||||
#[serde(default)]
|
||||
pub modifications: Vec<ActivePermissionProfileModification>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[ts(tag = "type")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum ActivePermissionProfileModification {
|
||||
/// Additional concrete directory that should be writable.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
AdditionalWritableRoot { path: AbsolutePathBuf },
|
||||
}
|
||||
|
||||
impl From<CoreActivePermissionProfileModification> for ActivePermissionProfileModification {
|
||||
fn from(value: CoreActivePermissionProfileModification) -> Self {
|
||||
match value {
|
||||
CoreActivePermissionProfileModification::AdditionalWritableRoot { path } => {
|
||||
Self::AdditionalWritableRoot { path }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ActivePermissionProfileModification> for CoreActivePermissionProfileModification {
|
||||
fn from(value: ActivePermissionProfileModification) -> Self {
|
||||
match value {
|
||||
ActivePermissionProfileModification::AdditionalWritableRoot { path } => {
|
||||
Self::AdditionalWritableRoot { path }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreActivePermissionProfile> for ActivePermissionProfile {
|
||||
fn from(value: CoreActivePermissionProfile) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
extends: value.extends,
|
||||
modifications: value
|
||||
.modifications
|
||||
.into_iter()
|
||||
.map(ActivePermissionProfileModification::from)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ActivePermissionProfile> for CoreActivePermissionProfile {
|
||||
fn from(value: ActivePermissionProfile) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
extends: value.extends,
|
||||
modifications: value
|
||||
.modifications
|
||||
.into_iter()
|
||||
.map(CoreActivePermissionProfileModification::from)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[ts(tag = "type")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum PermissionProfileSelectionParams {
|
||||
/// Select a named built-in or user-defined profile and optionally apply
|
||||
/// bounded modifications that Codex knows how to validate.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
Profile {
|
||||
id: String,
|
||||
#[ts(optional = nullable)]
|
||||
modifications: Option<Vec<PermissionProfileModificationParams>>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[ts(tag = "type")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum PermissionProfileModificationParams {
|
||||
/// Additional concrete directory that should be writable.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
AdditionalWritableRoot { path: AbsolutePathBuf },
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AdditionalPermissionProfile {
|
||||
/// Partial overlay used for per-command permission requests.
|
||||
pub network: Option<AdditionalNetworkPermissions>,
|
||||
pub file_system: Option<AdditionalFileSystemPermissions>,
|
||||
}
|
||||
|
||||
impl From<CoreAdditionalPermissionProfile> for AdditionalPermissionProfile {
|
||||
fn from(value: CoreAdditionalPermissionProfile) -> Self {
|
||||
Self {
|
||||
network: value.network.map(AdditionalNetworkPermissions::from),
|
||||
file_system: value.file_system.map(AdditionalFileSystemPermissions::from),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AdditionalPermissionProfile> for CoreAdditionalPermissionProfile {
|
||||
fn from(value: AdditionalPermissionProfile) -> Self {
|
||||
Self {
|
||||
network: value.network.map(CoreNetworkPermissions::from),
|
||||
file_system: value.file_system.map(CoreFileSystemPermissions::from),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct GrantedPermissionProfile {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub network: Option<AdditionalNetworkPermissions>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub file_system: Option<AdditionalFileSystemPermissions>,
|
||||
}
|
||||
|
||||
impl From<GrantedPermissionProfile> for CoreAdditionalPermissionProfile {
|
||||
fn from(value: GrantedPermissionProfile) -> Self {
|
||||
Self {
|
||||
network: value.network.map(CoreNetworkPermissions::from),
|
||||
file_system: value.file_system.map(CoreFileSystemPermissions::from),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum NetworkAccess {
|
||||
#[default]
|
||||
Restricted,
|
||||
Enabled,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[ts(tag = "type")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum SandboxPolicy {
|
||||
DangerFullAccess,
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
ReadOnly {
|
||||
#[serde(default)]
|
||||
network_access: bool,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
ExternalSandbox {
|
||||
#[serde(default)]
|
||||
network_access: NetworkAccess,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
WorkspaceWrite {
|
||||
#[serde(default)]
|
||||
writable_roots: Vec<AbsolutePathBuf>,
|
||||
#[serde(default)]
|
||||
network_access: bool,
|
||||
#[serde(default)]
|
||||
exclude_tmpdir_env_var: bool,
|
||||
#[serde(default)]
|
||||
exclude_slash_tmp: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
enum SandboxPolicyDeserialize {
|
||||
DangerFullAccess,
|
||||
#[serde(rename_all = "camelCase")]
|
||||
ReadOnly {
|
||||
#[serde(default)]
|
||||
network_access: bool,
|
||||
#[serde(default)]
|
||||
access: Option<LegacyReadOnlyAccess>,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
ExternalSandbox {
|
||||
#[serde(default)]
|
||||
network_access: NetworkAccess,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
WorkspaceWrite {
|
||||
#[serde(default)]
|
||||
writable_roots: Vec<AbsolutePathBuf>,
|
||||
#[serde(default)]
|
||||
read_only_access: Option<LegacyReadOnlyAccess>,
|
||||
#[serde(default)]
|
||||
network_access: bool,
|
||||
#[serde(default)]
|
||||
exclude_tmpdir_env_var: bool,
|
||||
#[serde(default)]
|
||||
exclude_slash_tmp: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
enum LegacyReadOnlyAccess {
|
||||
FullAccess,
|
||||
Restricted,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for SandboxPolicy {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
match SandboxPolicyDeserialize::deserialize(deserializer)? {
|
||||
SandboxPolicyDeserialize::DangerFullAccess => Ok(SandboxPolicy::DangerFullAccess),
|
||||
SandboxPolicyDeserialize::ReadOnly {
|
||||
network_access,
|
||||
access,
|
||||
} => {
|
||||
if matches!(access, Some(LegacyReadOnlyAccess::Restricted)) {
|
||||
return Err(serde::de::Error::custom(
|
||||
"readOnly.access is no longer supported; use permissionProfile for restricted reads",
|
||||
));
|
||||
}
|
||||
Ok(SandboxPolicy::ReadOnly { network_access })
|
||||
}
|
||||
SandboxPolicyDeserialize::ExternalSandbox { network_access } => {
|
||||
Ok(SandboxPolicy::ExternalSandbox { network_access })
|
||||
}
|
||||
SandboxPolicyDeserialize::WorkspaceWrite {
|
||||
writable_roots,
|
||||
read_only_access,
|
||||
network_access,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
} => {
|
||||
if matches!(read_only_access, Some(LegacyReadOnlyAccess::Restricted)) {
|
||||
return Err(serde::de::Error::custom(
|
||||
"workspaceWrite.readOnlyAccess is no longer supported; use permissionProfile for restricted reads",
|
||||
));
|
||||
}
|
||||
Ok(SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SandboxPolicy {
|
||||
pub fn to_core(&self) -> codex_protocol::protocol::SandboxPolicy {
|
||||
match self {
|
||||
SandboxPolicy::DangerFullAccess => {
|
||||
codex_protocol::protocol::SandboxPolicy::DangerFullAccess
|
||||
}
|
||||
SandboxPolicy::ReadOnly { network_access } => {
|
||||
codex_protocol::protocol::SandboxPolicy::ReadOnly {
|
||||
network_access: *network_access,
|
||||
}
|
||||
}
|
||||
SandboxPolicy::ExternalSandbox { network_access } => {
|
||||
codex_protocol::protocol::SandboxPolicy::ExternalSandbox {
|
||||
network_access: match network_access {
|
||||
NetworkAccess::Restricted => CoreNetworkAccess::Restricted,
|
||||
NetworkAccess::Enabled => CoreNetworkAccess::Enabled,
|
||||
},
|
||||
}
|
||||
}
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
} => codex_protocol::protocol::SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: writable_roots.clone(),
|
||||
network_access: *network_access,
|
||||
exclude_tmpdir_env_var: *exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp: *exclude_slash_tmp,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<codex_protocol::protocol::SandboxPolicy> for SandboxPolicy {
|
||||
fn from(value: codex_protocol::protocol::SandboxPolicy) -> Self {
|
||||
match value {
|
||||
codex_protocol::protocol::SandboxPolicy::DangerFullAccess => {
|
||||
SandboxPolicy::DangerFullAccess
|
||||
}
|
||||
codex_protocol::protocol::SandboxPolicy::ReadOnly { network_access } => {
|
||||
SandboxPolicy::ReadOnly { network_access }
|
||||
}
|
||||
codex_protocol::protocol::SandboxPolicy::ExternalSandbox { network_access } => {
|
||||
SandboxPolicy::ExternalSandbox {
|
||||
network_access: match network_access {
|
||||
CoreNetworkAccess::Restricted => NetworkAccess::Restricted,
|
||||
CoreNetworkAccess::Enabled => NetworkAccess::Enabled,
|
||||
},
|
||||
}
|
||||
}
|
||||
codex_protocol::protocol::SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
} => SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(transparent)]
|
||||
#[ts(type = "Array<string>", export_to = "v2/")]
|
||||
pub struct ExecPolicyAmendment {
|
||||
pub command: Vec<String>,
|
||||
}
|
||||
|
||||
impl ExecPolicyAmendment {
|
||||
pub fn into_core(self) -> CoreExecPolicyAmendment {
|
||||
CoreExecPolicyAmendment::new(self.command)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreExecPolicyAmendment> for ExecPolicyAmendment {
|
||||
fn from(value: CoreExecPolicyAmendment) -> Self {
|
||||
Self {
|
||||
command: value.command().to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum NetworkPolicyRuleAction from CoreNetworkPolicyRuleAction {
|
||||
Allow, Deny
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct NetworkPolicyAmendment {
|
||||
pub host: String,
|
||||
pub action: NetworkPolicyRuleAction,
|
||||
}
|
||||
|
||||
impl NetworkPolicyAmendment {
|
||||
pub fn into_core(self) -> CoreNetworkPolicyAmendment {
|
||||
CoreNetworkPolicyAmendment {
|
||||
host: self.host,
|
||||
action: self.action.to_core(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreNetworkPolicyAmendment> for NetworkPolicyAmendment {
|
||||
fn from(value: CoreNetworkPolicyAmendment) -> Self {
|
||||
Self {
|
||||
host: value.host,
|
||||
action: NetworkPolicyRuleAction::from(value.action),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PermissionsRequestApprovalParams {
|
||||
pub thread_id: String,
|
||||
pub turn_id: String,
|
||||
pub item_id: String,
|
||||
pub cwd: AbsolutePathBuf,
|
||||
pub reason: Option<String>,
|
||||
pub permissions: RequestPermissionProfile,
|
||||
}
|
||||
|
||||
v2_enum_from_core!(
|
||||
#[derive(Default)]
|
||||
pub enum PermissionGrantScope from CorePermissionGrantScope {
|
||||
#[default]
|
||||
Turn,
|
||||
Session
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PermissionsRequestApprovalResponse {
|
||||
pub permissions: GrantedPermissionProfile,
|
||||
#[serde(default)]
|
||||
pub scope: PermissionGrantScope,
|
||||
/// Review every subsequent command in this turn before normal sandboxed execution.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub strict_auto_review: Option<bool>,
|
||||
}
|
||||
753
codex-rs/app-server-protocol/src/protocol/v2/plugin.rs
Normal file
753
codex-rs/app-server-protocol/src/protocol/v2/plugin.rs
Normal file
@@ -0,0 +1,753 @@
|
||||
use super::AppSummary;
|
||||
use super::HookEventName;
|
||||
use super::HookHandlerType;
|
||||
use super::HookSource;
|
||||
use super::HookTrustStatus;
|
||||
use codex_protocol::protocol::SkillDependencies as CoreSkillDependencies;
|
||||
use codex_protocol::protocol::SkillInterface as CoreSkillInterface;
|
||||
use codex_protocol::protocol::SkillMetadata as CoreSkillMetadata;
|
||||
use codex_protocol::protocol::SkillScope as CoreSkillScope;
|
||||
use codex_protocol::protocol::SkillToolDependency as CoreSkillToolDependency;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::path::PathBuf;
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillsListParams {
|
||||
/// When empty, defaults to the current session working directory.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub cwds: Vec<PathBuf>,
|
||||
|
||||
/// When true, bypass the skills cache and re-scan skills from disk.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub force_reload: bool,
|
||||
|
||||
/// Optional per-cwd extra roots to scan as user-scoped skills.
|
||||
#[serde(default)]
|
||||
#[ts(optional = nullable)]
|
||||
pub per_cwd_extra_user_roots: Option<Vec<SkillsListExtraRootsForCwd>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillsListExtraRootsForCwd {
|
||||
pub cwd: PathBuf,
|
||||
pub extra_user_roots: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillsListResponse {
|
||||
pub data: Vec<SkillsListEntry>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct HooksListParams {
|
||||
/// When empty, defaults to the current session working directory.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub cwds: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct HooksListResponse {
|
||||
pub data: Vec<HooksListEntry>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct MarketplaceAddParams {
|
||||
pub source: String,
|
||||
#[ts(optional = nullable)]
|
||||
pub ref_name: Option<String>,
|
||||
#[ts(optional = nullable)]
|
||||
pub sparse_paths: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct MarketplaceAddResponse {
|
||||
pub marketplace_name: String,
|
||||
pub installed_root: AbsolutePathBuf,
|
||||
pub already_added: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct MarketplaceRemoveParams {
|
||||
pub marketplace_name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct MarketplaceRemoveResponse {
|
||||
pub marketplace_name: String,
|
||||
pub installed_root: Option<AbsolutePathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct MarketplaceUpgradeParams {
|
||||
#[ts(optional = nullable)]
|
||||
pub marketplace_name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct MarketplaceUpgradeResponse {
|
||||
pub selected_marketplaces: Vec<String>,
|
||||
pub upgraded_roots: Vec<AbsolutePathBuf>,
|
||||
pub errors: Vec<MarketplaceUpgradeErrorInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct MarketplaceUpgradeErrorInfo {
|
||||
pub marketplace_name: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginListParams {
|
||||
/// Optional working directories used to discover repo marketplaces. When omitted,
|
||||
/// only home-scoped marketplaces and the official curated marketplace are considered.
|
||||
#[ts(optional = nullable)]
|
||||
pub cwds: Option<Vec<AbsolutePathBuf>>,
|
||||
/// Optional marketplace kind filter. When omitted, only local marketplaces are queried, plus
|
||||
/// the default remote catalog when enabled by feature flag.
|
||||
#[ts(optional = nullable)]
|
||||
pub marketplace_kinds: Option<Vec<PluginListMarketplaceKind>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum PluginListMarketplaceKind {
|
||||
#[serde(rename = "local")]
|
||||
#[ts(rename = "local")]
|
||||
Local,
|
||||
#[serde(rename = "workspace-directory")]
|
||||
#[ts(rename = "workspace-directory")]
|
||||
WorkspaceDirectory,
|
||||
#[serde(rename = "shared-with-me")]
|
||||
#[ts(rename = "shared-with-me")]
|
||||
SharedWithMe,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginListResponse {
|
||||
pub marketplaces: Vec<PluginMarketplaceEntry>,
|
||||
#[serde(default)]
|
||||
pub marketplace_load_errors: Vec<MarketplaceLoadErrorInfo>,
|
||||
#[serde(default)]
|
||||
pub featured_plugin_ids: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct MarketplaceLoadErrorInfo {
|
||||
pub marketplace_path: AbsolutePathBuf,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginReadParams {
|
||||
#[ts(optional = nullable)]
|
||||
pub marketplace_path: Option<AbsolutePathBuf>,
|
||||
#[ts(optional = nullable)]
|
||||
pub remote_marketplace_name: Option<String>,
|
||||
pub plugin_name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginReadResponse {
|
||||
pub plugin: PluginDetail,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginSkillReadParams {
|
||||
pub remote_marketplace_name: String,
|
||||
pub remote_plugin_id: String,
|
||||
pub skill_name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginSkillReadResponse {
|
||||
pub contents: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginShareSaveParams {
|
||||
pub plugin_path: AbsolutePathBuf,
|
||||
#[ts(optional = nullable)]
|
||||
pub remote_plugin_id: Option<String>,
|
||||
#[ts(optional = nullable)]
|
||||
pub discoverability: Option<PluginShareDiscoverability>,
|
||||
#[ts(optional = nullable)]
|
||||
pub share_targets: Option<Vec<PluginShareTarget>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginShareSaveResponse {
|
||||
pub remote_plugin_id: String,
|
||||
pub share_url: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginShareUpdateTargetsParams {
|
||||
pub remote_plugin_id: String,
|
||||
pub share_targets: Vec<PluginShareTarget>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginShareUpdateTargetsResponse {
|
||||
pub principals: Vec<PluginSharePrincipal>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginShareListParams {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginShareListResponse {
|
||||
pub data: Vec<PluginShareListItem>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginShareDeleteParams {
|
||||
pub remote_plugin_id: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginShareDeleteResponse {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginShareListItem {
|
||||
pub plugin: PluginSummary,
|
||||
pub share_url: String,
|
||||
pub local_plugin_path: Option<AbsolutePathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum PluginShareDiscoverability {
|
||||
#[serde(rename = "LISTED")]
|
||||
#[ts(rename = "LISTED")]
|
||||
Listed,
|
||||
#[serde(rename = "UNLISTED")]
|
||||
#[ts(rename = "UNLISTED")]
|
||||
Unlisted,
|
||||
#[serde(rename = "PRIVATE")]
|
||||
#[ts(rename = "PRIVATE")]
|
||||
Private,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum PluginSharePrincipalType {
|
||||
#[serde(rename = "user")]
|
||||
#[ts(rename = "user")]
|
||||
User,
|
||||
#[serde(rename = "group")]
|
||||
#[ts(rename = "group")]
|
||||
Group,
|
||||
#[serde(rename = "workspace")]
|
||||
#[ts(rename = "workspace")]
|
||||
Workspace,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginShareTarget {
|
||||
pub principal_type: PluginSharePrincipalType,
|
||||
pub principal_id: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginSharePrincipal {
|
||||
pub principal_type: PluginSharePrincipalType,
|
||||
pub principal_id: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum SkillScope {
|
||||
User,
|
||||
Repo,
|
||||
System,
|
||||
Admin,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillMetadata {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
/// Legacy short_description from SKILL.md. Prefer SKILL.json interface.short_description.
|
||||
pub short_description: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub interface: Option<SkillInterface>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub dependencies: Option<SkillDependencies>,
|
||||
pub path: AbsolutePathBuf,
|
||||
pub scope: SkillScope,
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillInterface {
|
||||
#[ts(optional)]
|
||||
pub display_name: Option<String>,
|
||||
#[ts(optional)]
|
||||
pub short_description: Option<String>,
|
||||
#[ts(optional)]
|
||||
pub icon_small: Option<AbsolutePathBuf>,
|
||||
#[ts(optional)]
|
||||
pub icon_large: Option<AbsolutePathBuf>,
|
||||
#[ts(optional)]
|
||||
pub brand_color: Option<String>,
|
||||
#[ts(optional)]
|
||||
pub default_prompt: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillDependencies {
|
||||
pub tools: Vec<SkillToolDependency>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillToolDependency {
|
||||
#[serde(rename = "type")]
|
||||
#[ts(rename = "type")]
|
||||
pub r#type: String,
|
||||
pub value: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub description: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub transport: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub command: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillErrorInfo {
|
||||
pub path: PathBuf,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillsListEntry {
|
||||
pub cwd: PathBuf,
|
||||
pub skills: Vec<SkillMetadata>,
|
||||
pub errors: Vec<SkillErrorInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct HooksListEntry {
|
||||
pub cwd: PathBuf,
|
||||
pub hooks: Vec<HookMetadata>,
|
||||
pub warnings: Vec<String>,
|
||||
pub errors: Vec<HookErrorInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct HookMetadata {
|
||||
pub key: String,
|
||||
pub event_name: HookEventName,
|
||||
pub handler_type: HookHandlerType,
|
||||
pub matcher: Option<String>,
|
||||
pub command: Option<String>,
|
||||
pub timeout_sec: u64,
|
||||
pub status_message: Option<String>,
|
||||
pub source_path: AbsolutePathBuf,
|
||||
pub source: HookSource,
|
||||
pub plugin_id: Option<String>,
|
||||
pub display_order: i64,
|
||||
pub enabled: bool,
|
||||
pub is_managed: bool,
|
||||
pub current_hash: String,
|
||||
pub trust_status: HookTrustStatus,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct HookErrorInfo {
|
||||
pub path: PathBuf,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginMarketplaceEntry {
|
||||
pub name: String,
|
||||
/// Local marketplace file path when the marketplace is backed by a local file.
|
||||
/// Remote-only catalog marketplaces do not have a local path.
|
||||
pub path: Option<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 {
|
||||
#[serde(rename = "NOT_AVAILABLE")]
|
||||
#[ts(rename = "NOT_AVAILABLE")]
|
||||
NotAvailable,
|
||||
#[serde(rename = "AVAILABLE")]
|
||||
#[ts(rename = "AVAILABLE")]
|
||||
Available,
|
||||
#[serde(rename = "INSTALLED_BY_DEFAULT")]
|
||||
#[ts(rename = "INSTALLED_BY_DEFAULT")]
|
||||
InstalledByDefault,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum PluginAuthPolicy {
|
||||
#[serde(rename = "ON_INSTALL")]
|
||||
#[ts(rename = "ON_INSTALL")]
|
||||
OnInstall,
|
||||
#[serde(rename = "ON_USE")]
|
||||
#[ts(rename = "ON_USE")]
|
||||
OnUse,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Default, JsonSchema, TS)]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum PluginAvailability {
|
||||
/// Plugin-service currently sends `"ENABLED"` for available remote plugins.
|
||||
/// Codex app-server exposes `"AVAILABLE"` in its API; the alias keeps
|
||||
/// decoding compatible with that upstream response.
|
||||
#[serde(rename = "AVAILABLE", alias = "ENABLED")]
|
||||
#[ts(rename = "AVAILABLE")]
|
||||
#[default]
|
||||
Available,
|
||||
#[serde(rename = "DISABLED_BY_ADMIN")]
|
||||
#[ts(rename = "DISABLED_BY_ADMIN")]
|
||||
DisabledByAdmin,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginSummary {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
/// Remote sharing context associated with this plugin when available.
|
||||
pub share_context: Option<PluginShareContext>,
|
||||
pub source: PluginSource,
|
||||
pub installed: bool,
|
||||
pub enabled: bool,
|
||||
pub install_policy: PluginInstallPolicy,
|
||||
pub auth_policy: PluginAuthPolicy,
|
||||
/// Availability state for installing and using the plugin.
|
||||
#[serde(default)]
|
||||
pub availability: PluginAvailability,
|
||||
pub interface: Option<PluginInterface>,
|
||||
#[serde(default)]
|
||||
pub keywords: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginShareContext {
|
||||
pub remote_plugin_id: String,
|
||||
pub creator_account_user_id: Option<String>,
|
||||
pub creator_name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginDetail {
|
||||
pub marketplace_name: String,
|
||||
pub marketplace_path: Option<AbsolutePathBuf>,
|
||||
pub summary: PluginSummary,
|
||||
pub description: Option<String>,
|
||||
pub skills: Vec<SkillSummary>,
|
||||
pub hooks: Vec<PluginHookSummary>,
|
||||
pub apps: Vec<AppSummary>,
|
||||
pub mcp_servers: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginHookSummary {
|
||||
pub key: String,
|
||||
pub event_name: HookEventName,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillSummary {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub short_description: Option<String>,
|
||||
pub interface: Option<SkillInterface>,
|
||||
pub path: Option<AbsolutePathBuf>,
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginInterface {
|
||||
pub display_name: Option<String>,
|
||||
pub short_description: Option<String>,
|
||||
pub long_description: Option<String>,
|
||||
pub developer_name: Option<String>,
|
||||
pub category: Option<String>,
|
||||
pub capabilities: Vec<String>,
|
||||
pub website_url: Option<String>,
|
||||
pub privacy_policy_url: Option<String>,
|
||||
pub terms_of_service_url: Option<String>,
|
||||
/// Starter prompts for the plugin. Capped at 3 entries with a maximum of
|
||||
/// 128 characters per entry.
|
||||
pub default_prompt: Option<Vec<String>>,
|
||||
pub brand_color: Option<String>,
|
||||
/// Local composer icon path, resolved from the installed plugin package.
|
||||
pub composer_icon: Option<AbsolutePathBuf>,
|
||||
/// Remote composer icon URL from the plugin catalog.
|
||||
pub composer_icon_url: Option<String>,
|
||||
/// Local logo path, resolved from the installed plugin package.
|
||||
pub logo: Option<AbsolutePathBuf>,
|
||||
/// Remote logo URL from the plugin catalog.
|
||||
pub logo_url: Option<String>,
|
||||
/// Local screenshot paths, resolved from the installed plugin package.
|
||||
pub screenshots: Vec<AbsolutePathBuf>,
|
||||
/// Remote screenshot URLs from the plugin catalog.
|
||||
pub screenshot_urls: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[ts(tag = "type")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum PluginSource {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
Local { path: AbsolutePathBuf },
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
Git {
|
||||
url: String,
|
||||
path: Option<String>,
|
||||
ref_name: Option<String>,
|
||||
sha: Option<String>,
|
||||
},
|
||||
/// The plugin is available in the remote catalog. Download metadata is
|
||||
/// kept server-side and is not exposed through the app-server API.
|
||||
Remote,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillsConfigWriteParams {
|
||||
/// Path-based selector.
|
||||
#[ts(optional = nullable)]
|
||||
pub path: Option<AbsolutePathBuf>,
|
||||
/// Name-based selector.
|
||||
#[ts(optional = nullable)]
|
||||
pub name: Option<String>,
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct SkillsConfigWriteResponse {
|
||||
pub effective_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginInstallParams {
|
||||
#[ts(optional = nullable)]
|
||||
pub marketplace_path: Option<AbsolutePathBuf>,
|
||||
#[ts(optional = nullable)]
|
||||
pub remote_marketplace_name: Option<String>,
|
||||
pub plugin_name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginInstallResponse {
|
||||
pub auth_policy: PluginAuthPolicy,
|
||||
pub apps_needing_auth: Vec<AppSummary>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginUninstallParams {
|
||||
pub plugin_id: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct PluginUninstallResponse {}
|
||||
|
||||
impl From<CoreSkillMetadata> for SkillMetadata {
|
||||
fn from(value: CoreSkillMetadata) -> Self {
|
||||
Self {
|
||||
name: value.name,
|
||||
description: value.description,
|
||||
short_description: value.short_description,
|
||||
interface: value.interface.map(SkillInterface::from),
|
||||
dependencies: value.dependencies.map(SkillDependencies::from),
|
||||
path: value.path,
|
||||
scope: value.scope.into(),
|
||||
enabled: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreSkillInterface> for SkillInterface {
|
||||
fn from(value: CoreSkillInterface) -> Self {
|
||||
Self {
|
||||
display_name: value.display_name,
|
||||
short_description: value.short_description,
|
||||
brand_color: value.brand_color,
|
||||
default_prompt: value.default_prompt,
|
||||
icon_small: value.icon_small,
|
||||
icon_large: value.icon_large,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreSkillDependencies> for SkillDependencies {
|
||||
fn from(value: CoreSkillDependencies) -> Self {
|
||||
Self {
|
||||
tools: value
|
||||
.tools
|
||||
.into_iter()
|
||||
.map(SkillToolDependency::from)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreSkillToolDependency> for SkillToolDependency {
|
||||
fn from(value: CoreSkillToolDependency) -> Self {
|
||||
Self {
|
||||
r#type: value.r#type,
|
||||
value: value.value,
|
||||
description: value.description,
|
||||
transport: value.transport,
|
||||
command: value.command,
|
||||
url: value.url,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreSkillScope> for SkillScope {
|
||||
fn from(value: CoreSkillScope) -> Self {
|
||||
match value {
|
||||
CoreSkillScope::User => Self::User,
|
||||
CoreSkillScope::Repo => Self::Repo,
|
||||
CoreSkillScope::System => Self::System,
|
||||
CoreSkillScope::Admin => Self::Admin,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
/// Notification emitted when watched local skill files change.
|
||||
///
|
||||
/// Treat this as an invalidation signal and re-run `skills/list` with the
|
||||
/// client's current parameters when refreshed skill metadata is needed.
|
||||
pub struct SkillsChangedNotification {}
|
||||
204
codex-rs/app-server-protocol/src/protocol/v2/process.rs
Normal file
204
codex-rs/app-server-protocol/src/protocol/v2/process.rs
Normal file
@@ -0,0 +1,204 @@
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use ts_rs::TS;
|
||||
|
||||
/// PTY size in character cells for `process/spawn` PTY sessions.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ProcessTerminalSize {
|
||||
/// Terminal height in character cells.
|
||||
pub rows: u16,
|
||||
/// Terminal width in character cells.
|
||||
pub cols: u16,
|
||||
}
|
||||
|
||||
/// Spawn a standalone process (argv vector) without a Codex sandbox on the host
|
||||
/// where the app server is running.
|
||||
///
|
||||
/// `process/spawn` returns after the process has started and the connection-scoped
|
||||
/// `processHandle` has been registered. Process output and exit are reported via
|
||||
/// `process/outputDelta` and `process/exited` notifications.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ProcessSpawnParams {
|
||||
/// Command argv vector. Empty arrays are rejected.
|
||||
pub command: Vec<String>,
|
||||
/// Client-supplied, connection-scoped process handle.
|
||||
///
|
||||
/// Duplicate active handles are rejected on the same connection. The same
|
||||
/// handle can be reused after the prior process exits.
|
||||
pub process_handle: String,
|
||||
/// Absolute working directory for the process.
|
||||
pub cwd: AbsolutePathBuf,
|
||||
/// Enable PTY mode.
|
||||
///
|
||||
/// This implies `streamStdin` and `streamStdoutStderr`.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub tty: bool,
|
||||
/// Allow follow-up `process/writeStdin` requests to write stdin bytes.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub stream_stdin: bool,
|
||||
/// Stream stdout/stderr via `process/outputDelta` notifications.
|
||||
///
|
||||
/// Streamed bytes are not duplicated into the `process/exited` notification.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub stream_stdout_stderr: bool,
|
||||
/// Optional per-stream stdout/stderr capture cap in bytes.
|
||||
///
|
||||
/// When omitted, the server default applies. Set to `null` to disable the
|
||||
/// cap.
|
||||
#[serde(
|
||||
default,
|
||||
deserialize_with = "crate::protocol::serde_helpers::deserialize_double_option",
|
||||
serialize_with = "crate::protocol::serde_helpers::serialize_double_option",
|
||||
skip_serializing_if = "Option::is_none"
|
||||
)]
|
||||
#[ts(type = "number | null")]
|
||||
#[ts(optional = nullable)]
|
||||
pub output_bytes_cap: Option<Option<usize>>,
|
||||
/// Optional timeout in milliseconds.
|
||||
///
|
||||
/// When omitted, the server default applies. Set to `null` to disable the
|
||||
/// timeout.
|
||||
#[serde(
|
||||
default,
|
||||
deserialize_with = "crate::protocol::serde_helpers::deserialize_double_option",
|
||||
serialize_with = "crate::protocol::serde_helpers::serialize_double_option",
|
||||
skip_serializing_if = "Option::is_none"
|
||||
)]
|
||||
#[ts(type = "number | null")]
|
||||
#[ts(optional = nullable)]
|
||||
pub timeout_ms: Option<Option<i64>>,
|
||||
/// Optional environment overrides merged into the app-server process
|
||||
/// environment.
|
||||
///
|
||||
/// Matching names override inherited values. Set a key to `null` to unset
|
||||
/// an inherited variable.
|
||||
#[ts(optional = nullable)]
|
||||
pub env: Option<HashMap<String, Option<String>>>,
|
||||
/// Optional initial PTY size in character cells. Only valid when `tty` is
|
||||
/// true.
|
||||
#[ts(optional = nullable)]
|
||||
pub size: Option<ProcessTerminalSize>,
|
||||
}
|
||||
|
||||
/// Successful response for `process/spawn`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ProcessSpawnResponse {}
|
||||
|
||||
/// Write stdin bytes to a running `process/spawn` session, close stdin, or
|
||||
/// both.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ProcessWriteStdinParams {
|
||||
/// Client-supplied, connection-scoped `processHandle` from `process/spawn`.
|
||||
pub process_handle: String,
|
||||
/// Optional base64-encoded stdin bytes to write.
|
||||
#[ts(optional = nullable)]
|
||||
pub delta_base64: Option<String>,
|
||||
/// Close stdin after writing `deltaBase64`, if present.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub close_stdin: bool,
|
||||
}
|
||||
|
||||
/// Empty success response for `process/writeStdin`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ProcessWriteStdinResponse {}
|
||||
|
||||
/// Terminate a running `process/spawn` session.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ProcessKillParams {
|
||||
/// Client-supplied, connection-scoped `processHandle` from `process/spawn`.
|
||||
pub process_handle: String,
|
||||
}
|
||||
|
||||
/// Empty success response for `process/kill`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ProcessKillResponse {}
|
||||
|
||||
/// Resize a running PTY-backed `process/spawn` session.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ProcessResizePtyParams {
|
||||
/// Client-supplied, connection-scoped `processHandle` from `process/spawn`.
|
||||
pub process_handle: String,
|
||||
/// New PTY size in character cells.
|
||||
pub size: ProcessTerminalSize,
|
||||
}
|
||||
|
||||
/// Empty success response for `process/resizePty`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ProcessResizePtyResponse {}
|
||||
|
||||
/// Stream label for `process/outputDelta` notifications.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum ProcessOutputStream {
|
||||
/// stdout stream. PTY mode multiplexes terminal output here.
|
||||
Stdout,
|
||||
/// stderr stream.
|
||||
Stderr,
|
||||
}
|
||||
|
||||
/// Base64-encoded output chunk emitted for a streaming `process/spawn` request.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ProcessOutputDeltaNotification {
|
||||
/// Client-supplied, connection-scoped `processHandle` from `process/spawn`.
|
||||
pub process_handle: String,
|
||||
/// Output stream this chunk belongs to.
|
||||
pub stream: ProcessOutputStream,
|
||||
/// Base64-encoded output bytes.
|
||||
pub delta_base64: String,
|
||||
/// True on the final streamed chunk for this stream when output was
|
||||
/// truncated by `outputBytesCap`.
|
||||
pub cap_reached: bool,
|
||||
}
|
||||
|
||||
/// Final process exit notification for `process/spawn`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ProcessExitedNotification {
|
||||
/// Client-supplied, connection-scoped `processHandle` from `process/spawn`.
|
||||
pub process_handle: String,
|
||||
/// Process exit code.
|
||||
pub exit_code: i32,
|
||||
/// Buffered stdout capture.
|
||||
///
|
||||
/// Empty when stdout was streamed via `process/outputDelta`.
|
||||
pub stdout: String,
|
||||
/// Whether stdout reached `outputBytesCap`.
|
||||
///
|
||||
/// In streaming mode, stdout is empty and cap state is also reported on the
|
||||
/// final stdout `process/outputDelta` notification.
|
||||
pub stdout_cap_reached: bool,
|
||||
/// Buffered stderr capture.
|
||||
///
|
||||
/// Empty when stderr was streamed via `process/outputDelta`.
|
||||
pub stderr: String,
|
||||
/// Whether stderr reached `outputBytesCap`.
|
||||
///
|
||||
/// In streaming mode, stderr is empty and cap state is also reported on the
|
||||
/// final stderr `process/outputDelta` notification.
|
||||
pub stderr_cap_reached: bool,
|
||||
}
|
||||
241
codex-rs/app-server-protocol/src/protocol/v2/realtime.rs
Normal file
241
codex-rs/app-server-protocol/src/protocol/v2/realtime.rs
Normal file
@@ -0,0 +1,241 @@
|
||||
use codex_protocol::protocol::RealtimeAudioFrame as CoreRealtimeAudioFrame;
|
||||
use codex_protocol::protocol::RealtimeConversationVersion;
|
||||
use codex_protocol::protocol::RealtimeOutputModality;
|
||||
use codex_protocol::protocol::RealtimeVoice;
|
||||
use codex_protocol::protocol::RealtimeVoicesList;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
use ts_rs::TS;
|
||||
|
||||
/// EXPERIMENTAL - thread realtime audio chunk.
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeAudioChunk {
|
||||
pub data: String,
|
||||
pub sample_rate: u32,
|
||||
pub num_channels: u16,
|
||||
pub samples_per_channel: Option<u32>,
|
||||
pub item_id: Option<String>,
|
||||
}
|
||||
|
||||
impl From<CoreRealtimeAudioFrame> for ThreadRealtimeAudioChunk {
|
||||
fn from(value: CoreRealtimeAudioFrame) -> Self {
|
||||
let CoreRealtimeAudioFrame {
|
||||
data,
|
||||
sample_rate,
|
||||
num_channels,
|
||||
samples_per_channel,
|
||||
item_id,
|
||||
} = value;
|
||||
Self {
|
||||
data,
|
||||
sample_rate,
|
||||
num_channels,
|
||||
samples_per_channel,
|
||||
item_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ThreadRealtimeAudioChunk> for CoreRealtimeAudioFrame {
|
||||
fn from(value: ThreadRealtimeAudioChunk) -> Self {
|
||||
let ThreadRealtimeAudioChunk {
|
||||
data,
|
||||
sample_rate,
|
||||
num_channels,
|
||||
samples_per_channel,
|
||||
item_id,
|
||||
} = value;
|
||||
Self {
|
||||
data,
|
||||
sample_rate,
|
||||
num_channels,
|
||||
samples_per_channel,
|
||||
item_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - start a thread-scoped realtime session.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeStartParams {
|
||||
pub thread_id: String,
|
||||
/// Selects text or audio output for the realtime session. Transport and voice stay
|
||||
/// independent so clients can choose how they connect separately from what the model emits.
|
||||
pub output_modality: RealtimeOutputModality,
|
||||
#[serde(
|
||||
default,
|
||||
deserialize_with = "crate::protocol::serde_helpers::deserialize_double_option",
|
||||
serialize_with = "crate::protocol::serde_helpers::serialize_double_option",
|
||||
skip_serializing_if = "Option::is_none"
|
||||
)]
|
||||
#[ts(optional = nullable)]
|
||||
pub prompt: Option<Option<String>>,
|
||||
#[ts(optional = nullable)]
|
||||
pub realtime_session_id: Option<String>,
|
||||
#[ts(optional = nullable)]
|
||||
pub transport: Option<ThreadRealtimeStartTransport>,
|
||||
#[ts(optional = nullable)]
|
||||
pub voice: Option<RealtimeVoice>,
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - transport used by thread realtime.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/", tag = "type")]
|
||||
pub enum ThreadRealtimeStartTransport {
|
||||
Websocket,
|
||||
Webrtc {
|
||||
/// SDP offer generated by a WebRTC RTCPeerConnection after configuring audio and the
|
||||
/// realtime events data channel.
|
||||
sdp: String,
|
||||
},
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - response for starting thread realtime.
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeStartResponse {}
|
||||
|
||||
/// EXPERIMENTAL - append audio input to thread realtime.
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeAppendAudioParams {
|
||||
pub thread_id: String,
|
||||
pub audio: ThreadRealtimeAudioChunk,
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - response for appending realtime audio input.
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeAppendAudioResponse {}
|
||||
|
||||
/// EXPERIMENTAL - append text input to thread realtime.
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeAppendTextParams {
|
||||
pub thread_id: String,
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - response for appending realtime text input.
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeAppendTextResponse {}
|
||||
|
||||
/// EXPERIMENTAL - stop thread realtime.
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeStopParams {
|
||||
pub thread_id: String,
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - response for stopping thread realtime.
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeStopResponse {}
|
||||
|
||||
/// EXPERIMENTAL - list voices supported by thread realtime.
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeListVoicesParams {}
|
||||
|
||||
/// EXPERIMENTAL - response for listing supported realtime voices.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeListVoicesResponse {
|
||||
pub voices: RealtimeVoicesList,
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - emitted when thread realtime startup is accepted.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeStartedNotification {
|
||||
pub thread_id: String,
|
||||
pub realtime_session_id: Option<String>,
|
||||
pub version: RealtimeConversationVersion,
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - raw non-audio thread realtime item emitted by the backend.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeItemAddedNotification {
|
||||
pub thread_id: String,
|
||||
pub item: JsonValue,
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - flat transcript delta emitted whenever realtime
|
||||
/// transcript text changes.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeTranscriptDeltaNotification {
|
||||
pub thread_id: String,
|
||||
pub role: String,
|
||||
/// Live transcript delta from the realtime event.
|
||||
pub delta: String,
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - final transcript text emitted when realtime completes
|
||||
/// a transcript part.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeTranscriptDoneNotification {
|
||||
pub thread_id: String,
|
||||
pub role: String,
|
||||
/// Final complete text for the transcript part.
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - streamed output audio emitted by thread realtime.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeOutputAudioDeltaNotification {
|
||||
pub thread_id: String,
|
||||
pub audio: ThreadRealtimeAudioChunk,
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - emitted with the remote SDP for a WebRTC realtime session.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeSdpNotification {
|
||||
pub thread_id: String,
|
||||
pub sdp: String,
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - emitted when thread realtime encounters an error.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeErrorNotification {
|
||||
pub thread_id: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL - emitted when thread realtime transport closes.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadRealtimeClosedNotification {
|
||||
pub thread_id: String,
|
||||
pub reason: Option<String>,
|
||||
}
|
||||
65
codex-rs/app-server-protocol/src/protocol/v2/review.rs
Normal file
65
codex-rs/app-server-protocol/src/protocol/v2/review.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
use super::Turn;
|
||||
use super::shared::v2_enum_from_core;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use ts_rs::TS;
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum ReviewDelivery from codex_protocol::protocol::ReviewDelivery {
|
||||
Inline, Detached
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ReviewStartParams {
|
||||
pub thread_id: String,
|
||||
pub target: ReviewTarget,
|
||||
|
||||
/// Where to run the review: inline (default) on the current thread or
|
||||
/// detached on a new thread (returned in `reviewThreadId`).
|
||||
#[serde(default)]
|
||||
#[ts(optional = nullable)]
|
||||
pub delivery: Option<ReviewDelivery>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ReviewStartResponse {
|
||||
pub turn: Turn,
|
||||
/// Identifies the thread where the review runs.
|
||||
///
|
||||
/// For inline reviews, this is the original thread id.
|
||||
/// For detached reviews, this is the id of the new review thread.
|
||||
pub review_thread_id: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[ts(tag = "type", export_to = "v2/")]
|
||||
pub enum ReviewTarget {
|
||||
/// Review the working tree: staged, unstaged, and untracked files.
|
||||
UncommittedChanges,
|
||||
|
||||
/// Review changes between the current branch and the given base branch.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
BaseBranch { branch: String },
|
||||
|
||||
/// Review the changes introduced by a specific commit.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
Commit {
|
||||
sha: String,
|
||||
/// Optional human-readable label (e.g., commit subject) for UIs.
|
||||
title: Option<String>,
|
||||
},
|
||||
|
||||
/// Arbitrary instructions, equivalent to the old free-form prompt.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
Custom { instructions: String },
|
||||
}
|
||||
316
codex-rs/app-server-protocol/src/protocol/v2/shared.rs
Normal file
316
codex-rs/app-server-protocol/src/protocol/v2/shared.rs
Normal file
@@ -0,0 +1,316 @@
|
||||
use codex_experimental_api_macros::ExperimentalApi;
|
||||
use codex_protocol::config_types::ApprovalsReviewer as CoreApprovalsReviewer;
|
||||
use codex_protocol::config_types::SandboxMode as CoreSandboxMode;
|
||||
use codex_protocol::protocol::AskForApproval as CoreAskForApproval;
|
||||
use codex_protocol::protocol::CodexErrorInfo as CoreCodexErrorInfo;
|
||||
use codex_protocol::protocol::GranularApprovalConfig as CoreGranularApprovalConfig;
|
||||
use codex_protocol::protocol::NonSteerableTurnKind as CoreNonSteerableTurnKind;
|
||||
use schemars::JsonSchema;
|
||||
use schemars::r#gen::SchemaGenerator;
|
||||
use schemars::schema::InstanceType;
|
||||
use schemars::schema::Metadata;
|
||||
use schemars::schema::Schema;
|
||||
use schemars::schema::SchemaObject;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
use ts_rs::TS;
|
||||
|
||||
// Macro to declare a camelCased API v2 enum mirroring a core enum which
|
||||
// tends to use either snake_case or kebab-case.
|
||||
macro_rules! v2_enum_from_core {
|
||||
(
|
||||
$(#[$enum_meta:meta])*
|
||||
pub enum $Name:ident from $Src:path {
|
||||
$( $(#[$variant_meta:meta])* $Variant:ident ),+ $(,)?
|
||||
}
|
||||
) => {
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
$(#[$enum_meta])*
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum $Name {
|
||||
$( $(#[$variant_meta])* $Variant ),+
|
||||
}
|
||||
|
||||
impl $Name {
|
||||
pub fn to_core(self) -> $Src {
|
||||
match self { $( $Name::$Variant => <$Src>::$Variant ),+ }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$Src> for $Name {
|
||||
fn from(value: $Src) -> Self {
|
||||
match value { $( <$Src>::$Variant => $Name::$Variant ),+ }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(super) use v2_enum_from_core;
|
||||
|
||||
pub(super) const fn default_enabled() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum NonSteerableTurnKind {
|
||||
Review,
|
||||
Compact,
|
||||
}
|
||||
|
||||
/// This translation layer make sure that we expose codex error code in camel case.
|
||||
///
|
||||
/// When an upstream HTTP status is available (for example, from the Responses API or a provider),
|
||||
/// it is forwarded in `httpStatusCode` on the relevant `codexErrorInfo` variant.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum CodexErrorInfo {
|
||||
ContextWindowExceeded,
|
||||
UsageLimitExceeded,
|
||||
ServerOverloaded,
|
||||
CyberPolicy,
|
||||
HttpConnectionFailed {
|
||||
#[serde(rename = "httpStatusCode")]
|
||||
#[ts(rename = "httpStatusCode")]
|
||||
http_status_code: Option<u16>,
|
||||
},
|
||||
/// Failed to connect to the response SSE stream.
|
||||
ResponseStreamConnectionFailed {
|
||||
#[serde(rename = "httpStatusCode")]
|
||||
#[ts(rename = "httpStatusCode")]
|
||||
http_status_code: Option<u16>,
|
||||
},
|
||||
InternalServerError,
|
||||
Unauthorized,
|
||||
BadRequest,
|
||||
ThreadRollbackFailed,
|
||||
SandboxError,
|
||||
/// The response SSE stream disconnected in the middle of a turn before completion.
|
||||
ResponseStreamDisconnected {
|
||||
#[serde(rename = "httpStatusCode")]
|
||||
#[ts(rename = "httpStatusCode")]
|
||||
http_status_code: Option<u16>,
|
||||
},
|
||||
/// Reached the retry limit for responses.
|
||||
ResponseTooManyFailedAttempts {
|
||||
#[serde(rename = "httpStatusCode")]
|
||||
#[ts(rename = "httpStatusCode")]
|
||||
http_status_code: Option<u16>,
|
||||
},
|
||||
/// Returned when `turn/start` or `turn/steer` is submitted while the current active turn
|
||||
/// cannot accept same-turn steering, for example `/review` or manual `/compact`.
|
||||
ActiveTurnNotSteerable {
|
||||
#[serde(rename = "turnKind")]
|
||||
#[ts(rename = "turnKind")]
|
||||
turn_kind: NonSteerableTurnKind,
|
||||
},
|
||||
Other,
|
||||
}
|
||||
|
||||
impl From<CoreCodexErrorInfo> for CodexErrorInfo {
|
||||
fn from(value: CoreCodexErrorInfo) -> Self {
|
||||
match value {
|
||||
CoreCodexErrorInfo::ContextWindowExceeded => CodexErrorInfo::ContextWindowExceeded,
|
||||
CoreCodexErrorInfo::UsageLimitExceeded => CodexErrorInfo::UsageLimitExceeded,
|
||||
CoreCodexErrorInfo::ServerOverloaded => CodexErrorInfo::ServerOverloaded,
|
||||
CoreCodexErrorInfo::CyberPolicy => CodexErrorInfo::CyberPolicy,
|
||||
CoreCodexErrorInfo::HttpConnectionFailed { http_status_code } => {
|
||||
CodexErrorInfo::HttpConnectionFailed { http_status_code }
|
||||
}
|
||||
CoreCodexErrorInfo::ResponseStreamConnectionFailed { http_status_code } => {
|
||||
CodexErrorInfo::ResponseStreamConnectionFailed { http_status_code }
|
||||
}
|
||||
CoreCodexErrorInfo::InternalServerError => CodexErrorInfo::InternalServerError,
|
||||
CoreCodexErrorInfo::Unauthorized => CodexErrorInfo::Unauthorized,
|
||||
CoreCodexErrorInfo::BadRequest => CodexErrorInfo::BadRequest,
|
||||
CoreCodexErrorInfo::ThreadRollbackFailed => CodexErrorInfo::ThreadRollbackFailed,
|
||||
CoreCodexErrorInfo::SandboxError => CodexErrorInfo::SandboxError,
|
||||
CoreCodexErrorInfo::ResponseStreamDisconnected { http_status_code } => {
|
||||
CodexErrorInfo::ResponseStreamDisconnected { http_status_code }
|
||||
}
|
||||
CoreCodexErrorInfo::ResponseTooManyFailedAttempts { http_status_code } => {
|
||||
CodexErrorInfo::ResponseTooManyFailedAttempts { http_status_code }
|
||||
}
|
||||
CoreCodexErrorInfo::ActiveTurnNotSteerable { turn_kind } => {
|
||||
CodexErrorInfo::ActiveTurnNotSteerable {
|
||||
turn_kind: turn_kind.into(),
|
||||
}
|
||||
}
|
||||
CoreCodexErrorInfo::Other => CodexErrorInfo::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreNonSteerableTurnKind> for NonSteerableTurnKind {
|
||||
fn from(value: CoreNonSteerableTurnKind) -> Self {
|
||||
match value {
|
||||
CoreNonSteerableTurnKind::Review => Self::Review,
|
||||
CoreNonSteerableTurnKind::Compact => Self::Compact,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS, ExperimentalApi,
|
||||
)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[ts(rename_all = "kebab-case", export_to = "v2/")]
|
||||
pub enum AskForApproval {
|
||||
#[serde(rename = "untrusted")]
|
||||
#[ts(rename = "untrusted")]
|
||||
UnlessTrusted,
|
||||
OnFailure,
|
||||
OnRequest,
|
||||
#[experimental("askForApproval.granular")]
|
||||
Granular {
|
||||
sandbox_approval: bool,
|
||||
rules: bool,
|
||||
#[serde(default)]
|
||||
skill_approval: bool,
|
||||
#[serde(default)]
|
||||
request_permissions: bool,
|
||||
mcp_elicitations: bool,
|
||||
},
|
||||
Never,
|
||||
}
|
||||
|
||||
impl AskForApproval {
|
||||
pub fn to_core(self) -> CoreAskForApproval {
|
||||
match self {
|
||||
AskForApproval::UnlessTrusted => CoreAskForApproval::UnlessTrusted,
|
||||
AskForApproval::OnFailure => CoreAskForApproval::OnFailure,
|
||||
AskForApproval::OnRequest => CoreAskForApproval::OnRequest,
|
||||
AskForApproval::Granular {
|
||||
sandbox_approval,
|
||||
rules,
|
||||
skill_approval,
|
||||
request_permissions,
|
||||
mcp_elicitations,
|
||||
} => CoreAskForApproval::Granular(CoreGranularApprovalConfig {
|
||||
sandbox_approval,
|
||||
rules,
|
||||
skill_approval,
|
||||
request_permissions,
|
||||
mcp_elicitations,
|
||||
}),
|
||||
AskForApproval::Never => CoreAskForApproval::Never,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreAskForApproval> for AskForApproval {
|
||||
fn from(value: CoreAskForApproval) -> Self {
|
||||
match value {
|
||||
CoreAskForApproval::UnlessTrusted => AskForApproval::UnlessTrusted,
|
||||
CoreAskForApproval::OnFailure => AskForApproval::OnFailure,
|
||||
CoreAskForApproval::OnRequest => AskForApproval::OnRequest,
|
||||
CoreAskForApproval::Granular(granular_config) => AskForApproval::Granular {
|
||||
sandbox_approval: granular_config.sandbox_approval,
|
||||
rules: granular_config.rules,
|
||||
skill_approval: granular_config.skill_approval,
|
||||
request_permissions: granular_config.request_permissions,
|
||||
mcp_elicitations: granular_config.mcp_elicitations,
|
||||
},
|
||||
CoreAskForApproval::Never => AskForApproval::Never,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, TS)]
|
||||
#[ts(
|
||||
type = r#""user" | "auto_review" | "guardian_subagent""#,
|
||||
export_to = "v2/"
|
||||
)]
|
||||
/// Configures who approval requests are routed to for review. Examples
|
||||
/// include sandbox escapes, blocked network access, MCP approval prompts, and
|
||||
/// ARC escalations. Defaults to `user`. `auto_review` uses a carefully
|
||||
/// prompted subagent to gather relevant context and apply a risk-based
|
||||
/// decision framework before approving or denying the request.
|
||||
pub enum ApprovalsReviewer {
|
||||
#[serde(rename = "user")]
|
||||
User,
|
||||
#[serde(rename = "guardian_subagent", alias = "auto_review")]
|
||||
AutoReview,
|
||||
}
|
||||
|
||||
impl JsonSchema for ApprovalsReviewer {
|
||||
fn schema_name() -> String {
|
||||
"ApprovalsReviewer".to_string()
|
||||
}
|
||||
|
||||
fn json_schema(_generator: &mut SchemaGenerator) -> Schema {
|
||||
string_enum_schema_with_description(
|
||||
&["user", "auto_review", "guardian_subagent"],
|
||||
"Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `auto_review` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request. The legacy value `guardian_subagent` is accepted for compatibility.",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn string_enum_schema_with_description(values: &[&str], description: &str) -> Schema {
|
||||
let mut schema = SchemaObject {
|
||||
instance_type: Some(InstanceType::String.into()),
|
||||
metadata: Some(Box::new(Metadata {
|
||||
description: Some(description.to_string()),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
};
|
||||
schema.enum_values = Some(
|
||||
values
|
||||
.iter()
|
||||
.map(|value| JsonValue::String((*value).to_string()))
|
||||
.collect(),
|
||||
);
|
||||
Schema::Object(schema)
|
||||
}
|
||||
|
||||
impl ApprovalsReviewer {
|
||||
pub fn to_core(self) -> CoreApprovalsReviewer {
|
||||
match self {
|
||||
ApprovalsReviewer::User => CoreApprovalsReviewer::User,
|
||||
ApprovalsReviewer::AutoReview => CoreApprovalsReviewer::AutoReview,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreApprovalsReviewer> for ApprovalsReviewer {
|
||||
fn from(value: CoreApprovalsReviewer) -> Self {
|
||||
match value {
|
||||
CoreApprovalsReviewer::User => ApprovalsReviewer::User,
|
||||
CoreApprovalsReviewer::AutoReview => ApprovalsReviewer::AutoReview,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[ts(rename_all = "kebab-case", export_to = "v2/")]
|
||||
pub enum SandboxMode {
|
||||
ReadOnly,
|
||||
WorkspaceWrite,
|
||||
DangerFullAccess,
|
||||
}
|
||||
|
||||
impl SandboxMode {
|
||||
pub fn to_core(self) -> CoreSandboxMode {
|
||||
match self {
|
||||
SandboxMode::ReadOnly => CoreSandboxMode::ReadOnly,
|
||||
SandboxMode::WorkspaceWrite => CoreSandboxMode::WorkspaceWrite,
|
||||
SandboxMode::DangerFullAccess => CoreSandboxMode::DangerFullAccess,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreSandboxMode> for SandboxMode {
|
||||
fn from(value: CoreSandboxMode) -> Self {
|
||||
match value {
|
||||
CoreSandboxMode::ReadOnly => SandboxMode::ReadOnly,
|
||||
CoreSandboxMode::WorkspaceWrite => SandboxMode::WorkspaceWrite,
|
||||
CoreSandboxMode::DangerFullAccess => SandboxMode::DangerFullAccess,
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user