inspect-codex-app-server 2026.10.29.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- inspect_codex_app_server-2026.10.29.1/.github/workflows/ci.yml +196 -0
- inspect_codex_app_server-2026.10.29.1/.gitignore +6 -0
- inspect_codex_app_server-2026.10.29.1/AGENTS.md +5 -0
- inspect_codex_app_server-2026.10.29.1/LICENSE +21 -0
- inspect_codex_app_server-2026.10.29.1/PKG-INFO +189 -0
- inspect_codex_app_server-2026.10.29.1/README.md +174 -0
- inspect_codex_app_server-2026.10.29.1/TEST_POLICY.md +47 -0
- inspect_codex_app_server-2026.10.29.1/docs/releases.md +51 -0
- inspect_codex_app_server-2026.10.29.1/docs/technical-notes.md +106 -0
- inspect_codex_app_server-2026.10.29.1/examples/arithmetic.py +19 -0
- inspect_codex_app_server-2026.10.29.1/examples/compose.yaml +6 -0
- inspect_codex_app_server-2026.10.29.1/pyproject.toml +37 -0
- inspect_codex_app_server-2026.10.29.1/scripts/generate_protocol.py +158 -0
- inspect_codex_app_server-2026.10.29.1/scripts/update_dependencies.py +175 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/__init__.py +8 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/_generated_protocol.py +1628 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/_generated_rpc.py +135 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/agent.py +266 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/auth.py +30 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/client.py +1049 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/compat.py +226 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/container.py +353 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/evidence.py +201 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/mapping.py +1630 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/policy.py +101 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/py.typed +0 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/runtime/__init__.py +1 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/runtime/budget.py +59 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/runtime/limits.py +100 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/runtime/modelapi.py +24 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/runtime/process.py +62 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/session.py +1769 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/solver.py +254 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/subagent.py +67 -0
- inspect_codex_app_server-2026.10.29.1/src/inspect_codex_app_server/tools.py +90 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/__init__.py +1 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/conftest.py +97 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/support.py +275 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_accounting.py +429 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_agent.py +982 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_client.py +419 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_container.py +302 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_evaluation.py +406 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_mapping.py +508 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_native_configuration.py +201 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_native_inputs.py +178 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_native_models.py +171 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_native_resume.py +149 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_native_subagents.py +299 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_native_tools.py +378 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_provisioning.py +326 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_session.py +172 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_shutdown.py +367 -0
- inspect_codex_app_server-2026.10.29.1/tests/app_server_tests/test_transport.py +192 -0
- inspect_codex_app_server-2026.10.29.1/tests/conftest.py +17 -0
- inspect_codex_app_server-2026.10.29.1/uv.lock +3225 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
name: Compatibility and releases
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
schedule:
|
|
7
|
+
- cron: '17 * * * *'
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
inputs:
|
|
10
|
+
release:
|
|
11
|
+
description: Publish a release even if dependency versions are unchanged
|
|
12
|
+
type: boolean
|
|
13
|
+
default: false
|
|
14
|
+
repository_dispatch:
|
|
15
|
+
types: [upstream-release]
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
concurrency:
|
|
21
|
+
group: compatibility-${{ github.ref }}
|
|
22
|
+
cancel-in-progress: false
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
check:
|
|
26
|
+
name: Check pinned or candidate dependencies
|
|
27
|
+
runs-on: ubuntu-24.04
|
|
28
|
+
timeout-minutes: 20
|
|
29
|
+
outputs:
|
|
30
|
+
changed: ${{ steps.candidate.outputs.changed }}
|
|
31
|
+
version: ${{ steps.candidate.outputs.version }}
|
|
32
|
+
tag: ${{ steps.candidate.outputs.tag }}
|
|
33
|
+
prerelease: ${{ steps.candidate.outputs.prerelease }}
|
|
34
|
+
base_sha: ${{ github.sha }}
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
37
|
+
with:
|
|
38
|
+
persist-credentials: false
|
|
39
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
40
|
+
with:
|
|
41
|
+
python-version: '3.13'
|
|
42
|
+
- name: Install locked development dependencies
|
|
43
|
+
run: uv sync --locked --group dev
|
|
44
|
+
- name: Prepare dependency updates or a requested release
|
|
45
|
+
id: candidate
|
|
46
|
+
if: >-
|
|
47
|
+
github.ref_name == github.event.repository.default_branch &&
|
|
48
|
+
(github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' ||
|
|
49
|
+
github.event_name == 'repository_dispatch')
|
|
50
|
+
env:
|
|
51
|
+
GH_TOKEN: ${{ github.token }}
|
|
52
|
+
RELEASE_REQUESTED: ${{ github.event_name == 'workflow_dispatch' && inputs.release }}
|
|
53
|
+
run: |
|
|
54
|
+
release_args=()
|
|
55
|
+
if test "$RELEASE_REQUESTED" = true; then
|
|
56
|
+
release_args+=(--release)
|
|
57
|
+
fi
|
|
58
|
+
uv run --no-sync python scripts/update_dependencies.py --output-dir "$RUNNER_TEMP/release" "${release_args[@]}"
|
|
59
|
+
- name: Lock candidate dependencies and regenerate the native protocol
|
|
60
|
+
if: steps.candidate.outputs.changed == 'true'
|
|
61
|
+
run: |
|
|
62
|
+
uv lock
|
|
63
|
+
uv sync --locked --group dev
|
|
64
|
+
uv run --no-sync python scripts/generate_protocol.py
|
|
65
|
+
- name: Check protocol, lint, and types
|
|
66
|
+
if: steps.candidate.outputs.changed == 'true' || steps.candidate.outcome == 'skipped'
|
|
67
|
+
run: |
|
|
68
|
+
uv run --no-sync python scripts/generate_protocol.py --check
|
|
69
|
+
uv run --no-sync ruff check .
|
|
70
|
+
uv run --no-sync ty check
|
|
71
|
+
- name: Default tests, including the real pinned Codex executable
|
|
72
|
+
if: steps.candidate.outputs.changed == 'true' || steps.candidate.outcome == 'skipped'
|
|
73
|
+
run: uv run --no-sync pytest -q --keep-failed-artifacts="$RUNNER_TEMP/failures" --junitxml="$RUNNER_TEMP/default.xml"
|
|
74
|
+
- name: Prepare Docker acceptance
|
|
75
|
+
if: steps.candidate.outputs.changed == 'true' || steps.candidate.outcome == 'skipped'
|
|
76
|
+
run: docker pull python:3.13-slim
|
|
77
|
+
- name: Docker acceptance
|
|
78
|
+
if: steps.candidate.outputs.changed == 'true' || steps.candidate.outcome == 'skipped'
|
|
79
|
+
run: uv run --no-sync pytest -q -m containers --keep-failed-artifacts="$RUNNER_TEMP/failures" --junitxml="$RUNNER_TEMP/containers.xml"
|
|
80
|
+
- name: Build wheel and source archive
|
|
81
|
+
if: steps.candidate.outputs.changed == 'true' || steps.candidate.outcome == 'skipped'
|
|
82
|
+
run: uv build --no-sources --out-dir "$RUNNER_TEMP/release/dist"
|
|
83
|
+
- name: Save candidate source changes for review or publication
|
|
84
|
+
if: always() && steps.candidate.outputs.changed == 'true'
|
|
85
|
+
run: git diff --binary > "$RUNNER_TEMP/release/candidate.patch"
|
|
86
|
+
- name: Retain passing release candidate
|
|
87
|
+
if: steps.candidate.outputs.changed == 'true'
|
|
88
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
89
|
+
with:
|
|
90
|
+
name: release-candidate
|
|
91
|
+
path: ${{ runner.temp }}/release
|
|
92
|
+
if-no-files-found: error
|
|
93
|
+
retention-days: 14
|
|
94
|
+
- name: Retain failure diagnostics and candidate changes
|
|
95
|
+
if: failure()
|
|
96
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
97
|
+
with:
|
|
98
|
+
name: compatibility-failure
|
|
99
|
+
include-hidden-files: true
|
|
100
|
+
path: |
|
|
101
|
+
${{ runner.temp }}/failures
|
|
102
|
+
${{ runner.temp }}/*.xml
|
|
103
|
+
${{ runner.temp }}/release
|
|
104
|
+
if-no-files-found: ignore
|
|
105
|
+
retention-days: 7
|
|
106
|
+
|
|
107
|
+
record:
|
|
108
|
+
name: Record tested pins and draft the GitHub release
|
|
109
|
+
needs: check
|
|
110
|
+
if: needs.check.outputs.changed == 'true'
|
|
111
|
+
runs-on: ubuntu-24.04
|
|
112
|
+
timeout-minutes: 5
|
|
113
|
+
permissions:
|
|
114
|
+
contents: write
|
|
115
|
+
steps:
|
|
116
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
117
|
+
with:
|
|
118
|
+
ref: ${{ needs.check.outputs.base_sha }}
|
|
119
|
+
fetch-depth: 0
|
|
120
|
+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
|
|
121
|
+
with:
|
|
122
|
+
name: release-candidate
|
|
123
|
+
path: ${{ runner.temp }}/release
|
|
124
|
+
- name: Commit and tag exactly the tested source
|
|
125
|
+
env:
|
|
126
|
+
RELEASE_VERSION: ${{ needs.check.outputs.version }}
|
|
127
|
+
RELEASE_TAG: ${{ needs.check.outputs.tag }}
|
|
128
|
+
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
|
|
129
|
+
run: |
|
|
130
|
+
git apply --check "$RUNNER_TEMP/release/candidate.patch"
|
|
131
|
+
git apply "$RUNNER_TEMP/release/candidate.patch"
|
|
132
|
+
git add pyproject.toml uv.lock README.md src/inspect_codex_app_server/container.py src/inspect_codex_app_server/_generated_protocol.py src/inspect_codex_app_server/_generated_rpc.py
|
|
133
|
+
expected_tree=$(git write-tree)
|
|
134
|
+
if git show-ref --verify --quiet "refs/tags/$RELEASE_TAG"; then
|
|
135
|
+
# A rerun after a partial publication must reuse the tested tree.
|
|
136
|
+
test "$(git rev-parse "$RELEASE_TAG^{tree}")" = "$expected_tree"
|
|
137
|
+
else
|
|
138
|
+
git config user.name 'github-actions[bot]'
|
|
139
|
+
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
|
140
|
+
git commit -m "Release inspect-codex-app-server $RELEASE_VERSION"
|
|
141
|
+
git tag -a "$RELEASE_TAG" -m "Compatibility release $RELEASE_VERSION"
|
|
142
|
+
# A concurrent default-branch change rejects the entire push.
|
|
143
|
+
git push --atomic origin "HEAD:refs/heads/$DEFAULT_BRANCH" "refs/tags/$RELEASE_TAG"
|
|
144
|
+
fi
|
|
145
|
+
- name: Attach the tested distributions to a draft release
|
|
146
|
+
env:
|
|
147
|
+
GH_TOKEN: ${{ github.token }}
|
|
148
|
+
GH_REPO: ${{ github.repository }}
|
|
149
|
+
RELEASE_VERSION: ${{ needs.check.outputs.version }}
|
|
150
|
+
RELEASE_TAG: ${{ needs.check.outputs.tag }}
|
|
151
|
+
PRERELEASE: ${{ needs.check.outputs.prerelease }}
|
|
152
|
+
run: |
|
|
153
|
+
if gh release view "$RELEASE_TAG" --json isDraft > "$RUNNER_TEMP/existing-release.json"; then
|
|
154
|
+
if jq -e '.isDraft' "$RUNNER_TEMP/existing-release.json"; then
|
|
155
|
+
gh release upload "$RELEASE_TAG" "$RUNNER_TEMP"/release/dist/* --clobber
|
|
156
|
+
fi
|
|
157
|
+
else
|
|
158
|
+
options=(--verify-tag --draft --title "inspect-codex-app-server $RELEASE_VERSION" --notes-file "$RUNNER_TEMP/release/notes.md")
|
|
159
|
+
if test "$PRERELEASE" = true; then
|
|
160
|
+
options+=(--prerelease)
|
|
161
|
+
fi
|
|
162
|
+
gh release create "$RELEASE_TAG" "${options[@]}" "$RUNNER_TEMP"/release/dist/*
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
publish:
|
|
166
|
+
name: Publish the tested distributions to PyPI
|
|
167
|
+
needs: record
|
|
168
|
+
runs-on: ubuntu-24.04
|
|
169
|
+
timeout-minutes: 10
|
|
170
|
+
environment: pypi
|
|
171
|
+
permissions:
|
|
172
|
+
id-token: write
|
|
173
|
+
steps:
|
|
174
|
+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
|
|
175
|
+
with:
|
|
176
|
+
name: release-candidate
|
|
177
|
+
path: candidate
|
|
178
|
+
- uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # release/v1
|
|
179
|
+
with:
|
|
180
|
+
packages-dir: candidate/dist
|
|
181
|
+
skip-existing: true
|
|
182
|
+
|
|
183
|
+
release:
|
|
184
|
+
name: Publish the GitHub release after PyPI succeeds
|
|
185
|
+
needs: [check, publish]
|
|
186
|
+
runs-on: ubuntu-24.04
|
|
187
|
+
timeout-minutes: 5
|
|
188
|
+
permissions:
|
|
189
|
+
contents: write
|
|
190
|
+
steps:
|
|
191
|
+
- name: Publish the draft
|
|
192
|
+
env:
|
|
193
|
+
GH_TOKEN: ${{ github.token }}
|
|
194
|
+
GH_REPO: ${{ github.repository }}
|
|
195
|
+
RELEASE_TAG: ${{ needs.check.outputs.tag }}
|
|
196
|
+
run: gh release edit "$RELEASE_TAG" --draft=false
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ihor Makhynia
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: inspect-codex-app-server
|
|
3
|
+
Version: 2026.10.29.1
|
|
4
|
+
Summary: Run native Codex app-server sessions in Inspect AI
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Requires-Dist: aiohttp>=3.9
|
|
9
|
+
Requires-Dist: anyio>=4
|
|
10
|
+
Requires-Dist: inspect-ai==0.3.286
|
|
11
|
+
Requires-Dist: pydantic>=2
|
|
12
|
+
Requires-Dist: shortuuid>=1
|
|
13
|
+
Requires-Dist: typing-extensions>=4.12
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# inspect-codex-app-server
|
|
17
|
+
|
|
18
|
+
An [Inspect AI](https://inspect.aisi.org.uk/) solver and agent that run native Codex sessions inside Docker sandboxes via the Codex App Server JSON-RPC protocol.
|
|
19
|
+
|
|
20
|
+
Codex manages inference, tool execution, and subagent orchestration, while Inspect AI manages evaluation, scoring, tool governance, and token, message, and time limits. Cost and model-generation turn limits are unsupported.
|
|
21
|
+
|
|
22
|
+
## Key Features
|
|
23
|
+
|
|
24
|
+
- **Use Your ChatGPT Subscription**: Run evaluations directly against your ChatGPT subscription plan (or API key) using native Codex authentication.
|
|
25
|
+
- **Docker Sandbox Execution**: Runs Codex as root with full access inside Docker sandboxes, including filesystem tools, bash commands, and subagents.
|
|
26
|
+
- **Inspect Agent**: `codex_agent()` composes with `as_solver()`, `as_tool()`, `handoff()` and `run()`, with react-style `submit`, `attempts`, `on_continue` and `retry_refusals`.
|
|
27
|
+
- **Inspect Tool Bridging**: Exposes Inspect tools (`use_tools`, MCP tool sources) directly to Codex as dynamic tools with validation, approval and review handling.
|
|
28
|
+
- **Inspect Approvals**: Routes Codex's native command and file-change approval requests to the active Inspect approver.
|
|
29
|
+
- **Native Skills, Web Search and Roles**: Installs Inspect skills as Codex skills, sets the native web search mode, and declares agent roles for Codex's child agents.
|
|
30
|
+
- **Operator Interruption and Checkpoints**: Responds to operator interrupts and messages through Inspect's agent channel, and resumes from Inspect checkpoints.
|
|
31
|
+
- **Session & Quota Management**: Handles rate limits, quota pauses (`quota_hold_sec`), transient turn-start retries with backoff, and token budgeting.
|
|
32
|
+
- **Transcript & Usage Tracking**: Reconstructs model activity, tool events, and subagent spans into Inspect transcripts with live metrics.
|
|
33
|
+
- **Evidence & Artifact Capture**: Retains protocol transcripts, session databases, and execution manifests for debugging and auditability.
|
|
34
|
+
|
|
35
|
+
## Prerequisites & Installation
|
|
36
|
+
|
|
37
|
+
- Python 3.11+
|
|
38
|
+
- Docker (with Inspect Docker sandbox support)
|
|
39
|
+
- Node.js and npm when a compatible pinned Codex bundle is unavailable.
|
|
40
|
+
|
|
41
|
+
For an npm-equipped container image, preinstall with
|
|
42
|
+
`RUN npm install -g --prefix /opt/codex @openai/codex@0.165.0` and add
|
|
43
|
+
`/opt/codex/bin` to `PATH`. See [provisioning constraints](docs/technical-notes.md#provisioning-and-authentication).
|
|
44
|
+
|
|
45
|
+
Install the package:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install -e .
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Authentication
|
|
52
|
+
|
|
53
|
+
Run `codex login` on your host and provide its `~/.codex/auth.json`, or select
|
|
54
|
+
another file with `CODEX_AUTH_PATH` / `auth_path`.
|
|
55
|
+
|
|
56
|
+
Supported authentication modes:
|
|
57
|
+
- `"chatgpt"`: Uses ChatGPT subscription credentials.
|
|
58
|
+
- `"api_key"`: Uses an OpenAI API key.
|
|
59
|
+
- `"existing"`: Uses the container configuration and available credentials without enforcing an authentication mode.
|
|
60
|
+
|
|
61
|
+
Credentials are copied into `/root/.cache/codex-inspect/auth.json` inside the
|
|
62
|
+
container. See [configuration, credential storage, and logging details](docs/technical-notes.md#provisioning-and-authentication).
|
|
63
|
+
|
|
64
|
+
## Quickstart
|
|
65
|
+
|
|
66
|
+
Define a task using `codex_app_server`:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from pathlib import Path
|
|
70
|
+
from inspect_ai import Task, task
|
|
71
|
+
from inspect_ai.dataset import Sample
|
|
72
|
+
from inspect_ai.scorer import match
|
|
73
|
+
from inspect_codex_app_server import codex_app_server
|
|
74
|
+
|
|
75
|
+
@task
|
|
76
|
+
def arithmetic():
|
|
77
|
+
return Task(
|
|
78
|
+
dataset=[Sample(input="What is 19 + 23? Reply with the number only.", target="42")],
|
|
79
|
+
solver=codex_app_server(
|
|
80
|
+
authentication="chatgpt",
|
|
81
|
+
timeout_sec=600,
|
|
82
|
+
max_child_agents=1,
|
|
83
|
+
),
|
|
84
|
+
scorer=match(),
|
|
85
|
+
sandbox=("docker", str(Path(__file__).with_name("compose.yaml"))),
|
|
86
|
+
)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Run evaluation:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
inspect eval examples/arithmetic.py --model codex/default
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Inspect Agent
|
|
96
|
+
|
|
97
|
+
`codex_agent()` runs the same native session as an Inspect agent, so it composes like `react()`:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from inspect_ai.agent import as_solver, as_tool
|
|
101
|
+
from inspect_codex_app_server import CodexSubagent, codex_agent
|
|
102
|
+
|
|
103
|
+
coder = codex_agent(
|
|
104
|
+
name="coder",
|
|
105
|
+
description="Solves programming tasks in the sandbox.",
|
|
106
|
+
prompt="Work carefully and verify your answer.",
|
|
107
|
+
submit=True, # accept answers from the root submit tool
|
|
108
|
+
attempts=3, # score each submission; steer onward when incorrect
|
|
109
|
+
subagents=[CodexSubagent(name="reviewer", description="Reviews changes.", token_limit=200_000)],
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
solver = as_solver(coder) # or as_tool(coder), handoff(coder), run(coder, ...)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
See the [Inspect feature mapping](docs/technical-notes.md#inspect-feature-mapping)
|
|
116
|
+
and [model settings and input formats](docs/technical-notes.md#model-settings-and-conversation-input)
|
|
117
|
+
for compatibility details.
|
|
118
|
+
|
|
119
|
+
### Interruption and checkpoints
|
|
120
|
+
|
|
121
|
+
Operator interrupts stop native work and wait for follow-up input. Inspect
|
|
122
|
+
checkpoints can resume the root thread; scoring-only resume starts no Codex
|
|
123
|
+
process. See [interruption and resume notes](docs/technical-notes.md#operator-interruption-and-checkpoint-resume).
|
|
124
|
+
|
|
125
|
+
## Solver Options
|
|
126
|
+
|
|
127
|
+
The `codex_app_server` solver accepts the following configuration parameters:
|
|
128
|
+
|
|
129
|
+
| Parameter | Type | Default | Description |
|
|
130
|
+
|---|---|---|---|
|
|
131
|
+
| `authentication` | `"existing"` \| `"chatgpt"` \| `"api_key"` | `"existing"` | Required authentication mode. |
|
|
132
|
+
| `timeout_sec` | `float` | `600.0` | Run budget including setup; teardown runs separately. |
|
|
133
|
+
| `max_child_agents` | `int` | `4` | Maximum concurrent subagents per sample. |
|
|
134
|
+
| `developer_instructions` | `str \| None` | `None` | Thread developer instructions. |
|
|
135
|
+
| `base_instructions` | `str \| None` | `None` | Replacement for Codex's base instructions. |
|
|
136
|
+
| `reasoning_effort` | `str \| None` | `None` | Model reasoning effort (defaults to the evaluation's `GenerateConfig`). |
|
|
137
|
+
| `reasoning_summary` | `str \| None` | `None` | Reasoning summary detail (defaults to the evaluation's `GenerateConfig`). |
|
|
138
|
+
| `retry_refusals` | `int \| None` | `None` | Policy-blocked turns to continue before finishing with `content_filter`. |
|
|
139
|
+
| `skills` | `list[str \| Path \| Skill] \| None` | `None` | Inspect skills installed as Codex skills. |
|
|
140
|
+
| `web_search` | `"disabled"` \| `"cached"` \| `"indexed"` \| `"live"` \| `None` | `None` | Native web search mode. |
|
|
141
|
+
| `subagents` | `list[CodexSubagent] \| None` | `None` | Native agent roles for Codex's child agents. |
|
|
142
|
+
| `service_tier` | `str \| None` | `None` | Service tier requested on root turns (e.g. `"priority"`, `"flex"`). |
|
|
143
|
+
| `cwd` | `str` | `"/app"` | Working directory inside the container. |
|
|
144
|
+
| `transport` | `"stdio"` \| `"websocket"` | `"stdio"` | Transport protocol to communicate with the app server. |
|
|
145
|
+
| `policy` | `RunPolicy \| None` | `None` | Custom execution lifecycle and completion policy. |
|
|
146
|
+
| `codex_path` | `str \| None` | `None` | Host binary override (`CODEX_PATH` also works), taking precedence over image reuse. |
|
|
147
|
+
| `auth_path` | `str \| None` | `None` | Explicit path to the host `auth.json`. |
|
|
148
|
+
|
|
149
|
+
## Custom Lifecycle Policies (`RunPolicy`)
|
|
150
|
+
|
|
151
|
+
`RunPolicy` configures completion rules, quota waits, setup hooks, and timed
|
|
152
|
+
steering reminders. See the [lifecycle example and limits](docs/technical-notes.md#limits-and-lifecycle-policies).
|
|
153
|
+
|
|
154
|
+
## Development & Testing
|
|
155
|
+
|
|
156
|
+
The default suite includes real pinned Codex tests using local scripted model
|
|
157
|
+
responses, without credentials or paid inference. Docker acceptance additionally
|
|
158
|
+
requires a running Docker daemon and `docker pull python:3.13-slim`.
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Install development dependencies
|
|
162
|
+
uv sync --group dev
|
|
163
|
+
|
|
164
|
+
# Run the default suite, including native tests; excludes Docker acceptance
|
|
165
|
+
uv run pytest -q
|
|
166
|
+
|
|
167
|
+
# Run only tests that launch the real pinned Codex executable
|
|
168
|
+
uv run pytest -q -m native
|
|
169
|
+
|
|
170
|
+
# Run Docker acceptance separately
|
|
171
|
+
uv run pytest -q -m containers
|
|
172
|
+
|
|
173
|
+
# Run linter and type checker
|
|
174
|
+
uv run ruff check .
|
|
175
|
+
uv run ty check
|
|
176
|
+
|
|
177
|
+
# Validate generated JSON-RPC protocol schemas
|
|
178
|
+
uv run python scripts/generate_protocol.py --check
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Automated compatibility releases
|
|
182
|
+
|
|
183
|
+
The [workflow](.github/workflows/ci.yml) checks pushes and pull requests, and can
|
|
184
|
+
check upstream releases hourly and publish passing candidates to GitHub and
|
|
185
|
+
PyPI. See [release setup, publication, and retry notes](docs/releases.md).
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# inspect-codex-app-server
|
|
2
|
+
|
|
3
|
+
An [Inspect AI](https://inspect.aisi.org.uk/) solver and agent that run native Codex sessions inside Docker sandboxes via the Codex App Server JSON-RPC protocol.
|
|
4
|
+
|
|
5
|
+
Codex manages inference, tool execution, and subagent orchestration, while Inspect AI manages evaluation, scoring, tool governance, and token, message, and time limits. Cost and model-generation turn limits are unsupported.
|
|
6
|
+
|
|
7
|
+
## Key Features
|
|
8
|
+
|
|
9
|
+
- **Use Your ChatGPT Subscription**: Run evaluations directly against your ChatGPT subscription plan (or API key) using native Codex authentication.
|
|
10
|
+
- **Docker Sandbox Execution**: Runs Codex as root with full access inside Docker sandboxes, including filesystem tools, bash commands, and subagents.
|
|
11
|
+
- **Inspect Agent**: `codex_agent()` composes with `as_solver()`, `as_tool()`, `handoff()` and `run()`, with react-style `submit`, `attempts`, `on_continue` and `retry_refusals`.
|
|
12
|
+
- **Inspect Tool Bridging**: Exposes Inspect tools (`use_tools`, MCP tool sources) directly to Codex as dynamic tools with validation, approval and review handling.
|
|
13
|
+
- **Inspect Approvals**: Routes Codex's native command and file-change approval requests to the active Inspect approver.
|
|
14
|
+
- **Native Skills, Web Search and Roles**: Installs Inspect skills as Codex skills, sets the native web search mode, and declares agent roles for Codex's child agents.
|
|
15
|
+
- **Operator Interruption and Checkpoints**: Responds to operator interrupts and messages through Inspect's agent channel, and resumes from Inspect checkpoints.
|
|
16
|
+
- **Session & Quota Management**: Handles rate limits, quota pauses (`quota_hold_sec`), transient turn-start retries with backoff, and token budgeting.
|
|
17
|
+
- **Transcript & Usage Tracking**: Reconstructs model activity, tool events, and subagent spans into Inspect transcripts with live metrics.
|
|
18
|
+
- **Evidence & Artifact Capture**: Retains protocol transcripts, session databases, and execution manifests for debugging and auditability.
|
|
19
|
+
|
|
20
|
+
## Prerequisites & Installation
|
|
21
|
+
|
|
22
|
+
- Python 3.11+
|
|
23
|
+
- Docker (with Inspect Docker sandbox support)
|
|
24
|
+
- Node.js and npm when a compatible pinned Codex bundle is unavailable.
|
|
25
|
+
|
|
26
|
+
For an npm-equipped container image, preinstall with
|
|
27
|
+
`RUN npm install -g --prefix /opt/codex @openai/codex@0.165.0` and add
|
|
28
|
+
`/opt/codex/bin` to `PATH`. See [provisioning constraints](docs/technical-notes.md#provisioning-and-authentication).
|
|
29
|
+
|
|
30
|
+
Install the package:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install -e .
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Authentication
|
|
37
|
+
|
|
38
|
+
Run `codex login` on your host and provide its `~/.codex/auth.json`, or select
|
|
39
|
+
another file with `CODEX_AUTH_PATH` / `auth_path`.
|
|
40
|
+
|
|
41
|
+
Supported authentication modes:
|
|
42
|
+
- `"chatgpt"`: Uses ChatGPT subscription credentials.
|
|
43
|
+
- `"api_key"`: Uses an OpenAI API key.
|
|
44
|
+
- `"existing"`: Uses the container configuration and available credentials without enforcing an authentication mode.
|
|
45
|
+
|
|
46
|
+
Credentials are copied into `/root/.cache/codex-inspect/auth.json` inside the
|
|
47
|
+
container. See [configuration, credential storage, and logging details](docs/technical-notes.md#provisioning-and-authentication).
|
|
48
|
+
|
|
49
|
+
## Quickstart
|
|
50
|
+
|
|
51
|
+
Define a task using `codex_app_server`:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from pathlib import Path
|
|
55
|
+
from inspect_ai import Task, task
|
|
56
|
+
from inspect_ai.dataset import Sample
|
|
57
|
+
from inspect_ai.scorer import match
|
|
58
|
+
from inspect_codex_app_server import codex_app_server
|
|
59
|
+
|
|
60
|
+
@task
|
|
61
|
+
def arithmetic():
|
|
62
|
+
return Task(
|
|
63
|
+
dataset=[Sample(input="What is 19 + 23? Reply with the number only.", target="42")],
|
|
64
|
+
solver=codex_app_server(
|
|
65
|
+
authentication="chatgpt",
|
|
66
|
+
timeout_sec=600,
|
|
67
|
+
max_child_agents=1,
|
|
68
|
+
),
|
|
69
|
+
scorer=match(),
|
|
70
|
+
sandbox=("docker", str(Path(__file__).with_name("compose.yaml"))),
|
|
71
|
+
)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Run evaluation:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
inspect eval examples/arithmetic.py --model codex/default
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Inspect Agent
|
|
81
|
+
|
|
82
|
+
`codex_agent()` runs the same native session as an Inspect agent, so it composes like `react()`:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from inspect_ai.agent import as_solver, as_tool
|
|
86
|
+
from inspect_codex_app_server import CodexSubagent, codex_agent
|
|
87
|
+
|
|
88
|
+
coder = codex_agent(
|
|
89
|
+
name="coder",
|
|
90
|
+
description="Solves programming tasks in the sandbox.",
|
|
91
|
+
prompt="Work carefully and verify your answer.",
|
|
92
|
+
submit=True, # accept answers from the root submit tool
|
|
93
|
+
attempts=3, # score each submission; steer onward when incorrect
|
|
94
|
+
subagents=[CodexSubagent(name="reviewer", description="Reviews changes.", token_limit=200_000)],
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
solver = as_solver(coder) # or as_tool(coder), handoff(coder), run(coder, ...)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
See the [Inspect feature mapping](docs/technical-notes.md#inspect-feature-mapping)
|
|
101
|
+
and [model settings and input formats](docs/technical-notes.md#model-settings-and-conversation-input)
|
|
102
|
+
for compatibility details.
|
|
103
|
+
|
|
104
|
+
### Interruption and checkpoints
|
|
105
|
+
|
|
106
|
+
Operator interrupts stop native work and wait for follow-up input. Inspect
|
|
107
|
+
checkpoints can resume the root thread; scoring-only resume starts no Codex
|
|
108
|
+
process. See [interruption and resume notes](docs/technical-notes.md#operator-interruption-and-checkpoint-resume).
|
|
109
|
+
|
|
110
|
+
## Solver Options
|
|
111
|
+
|
|
112
|
+
The `codex_app_server` solver accepts the following configuration parameters:
|
|
113
|
+
|
|
114
|
+
| Parameter | Type | Default | Description |
|
|
115
|
+
|---|---|---|---|
|
|
116
|
+
| `authentication` | `"existing"` \| `"chatgpt"` \| `"api_key"` | `"existing"` | Required authentication mode. |
|
|
117
|
+
| `timeout_sec` | `float` | `600.0` | Run budget including setup; teardown runs separately. |
|
|
118
|
+
| `max_child_agents` | `int` | `4` | Maximum concurrent subagents per sample. |
|
|
119
|
+
| `developer_instructions` | `str \| None` | `None` | Thread developer instructions. |
|
|
120
|
+
| `base_instructions` | `str \| None` | `None` | Replacement for Codex's base instructions. |
|
|
121
|
+
| `reasoning_effort` | `str \| None` | `None` | Model reasoning effort (defaults to the evaluation's `GenerateConfig`). |
|
|
122
|
+
| `reasoning_summary` | `str \| None` | `None` | Reasoning summary detail (defaults to the evaluation's `GenerateConfig`). |
|
|
123
|
+
| `retry_refusals` | `int \| None` | `None` | Policy-blocked turns to continue before finishing with `content_filter`. |
|
|
124
|
+
| `skills` | `list[str \| Path \| Skill] \| None` | `None` | Inspect skills installed as Codex skills. |
|
|
125
|
+
| `web_search` | `"disabled"` \| `"cached"` \| `"indexed"` \| `"live"` \| `None` | `None` | Native web search mode. |
|
|
126
|
+
| `subagents` | `list[CodexSubagent] \| None` | `None` | Native agent roles for Codex's child agents. |
|
|
127
|
+
| `service_tier` | `str \| None` | `None` | Service tier requested on root turns (e.g. `"priority"`, `"flex"`). |
|
|
128
|
+
| `cwd` | `str` | `"/app"` | Working directory inside the container. |
|
|
129
|
+
| `transport` | `"stdio"` \| `"websocket"` | `"stdio"` | Transport protocol to communicate with the app server. |
|
|
130
|
+
| `policy` | `RunPolicy \| None` | `None` | Custom execution lifecycle and completion policy. |
|
|
131
|
+
| `codex_path` | `str \| None` | `None` | Host binary override (`CODEX_PATH` also works), taking precedence over image reuse. |
|
|
132
|
+
| `auth_path` | `str \| None` | `None` | Explicit path to the host `auth.json`. |
|
|
133
|
+
|
|
134
|
+
## Custom Lifecycle Policies (`RunPolicy`)
|
|
135
|
+
|
|
136
|
+
`RunPolicy` configures completion rules, quota waits, setup hooks, and timed
|
|
137
|
+
steering reminders. See the [lifecycle example and limits](docs/technical-notes.md#limits-and-lifecycle-policies).
|
|
138
|
+
|
|
139
|
+
## Development & Testing
|
|
140
|
+
|
|
141
|
+
The default suite includes real pinned Codex tests using local scripted model
|
|
142
|
+
responses, without credentials or paid inference. Docker acceptance additionally
|
|
143
|
+
requires a running Docker daemon and `docker pull python:3.13-slim`.
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# Install development dependencies
|
|
147
|
+
uv sync --group dev
|
|
148
|
+
|
|
149
|
+
# Run the default suite, including native tests; excludes Docker acceptance
|
|
150
|
+
uv run pytest -q
|
|
151
|
+
|
|
152
|
+
# Run only tests that launch the real pinned Codex executable
|
|
153
|
+
uv run pytest -q -m native
|
|
154
|
+
|
|
155
|
+
# Run Docker acceptance separately
|
|
156
|
+
uv run pytest -q -m containers
|
|
157
|
+
|
|
158
|
+
# Run linter and type checker
|
|
159
|
+
uv run ruff check .
|
|
160
|
+
uv run ty check
|
|
161
|
+
|
|
162
|
+
# Validate generated JSON-RPC protocol schemas
|
|
163
|
+
uv run python scripts/generate_protocol.py --check
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Automated compatibility releases
|
|
167
|
+
|
|
168
|
+
The [workflow](.github/workflows/ci.yml) checks pushes and pull requests, and can
|
|
169
|
+
check upstream releases hourly and publish passing candidates to GitHub and
|
|
170
|
+
PyPI. See [release setup, publication, and retry notes](docs/releases.md).
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Package test gates
|
|
2
|
+
|
|
3
|
+
## Admission
|
|
4
|
+
|
|
5
|
+
Extend an existing scenario first. Add a case only when it catches a named defect
|
|
6
|
+
existing tests miss, with an independently derived expected result. For regressions,
|
|
7
|
+
verify failure against the broken behavior when practical; report if unverified.
|
|
8
|
+
|
|
9
|
+
## Required assertions by change
|
|
10
|
+
|
|
11
|
+
| Changed behavior | Gate |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| Accounting / evidence | Duplicate wire and rollout records count once; unrelated threads contribute zero. Resume after 25 tokens, consume 5: recorded total 30, newly charged tokens 5. |
|
|
14
|
+
| Completion / errors | Child answers cannot replace the root answer. Provider/transport failures persist as execution errors; refusals and limits retain distinct outcomes. |
|
|
15
|
+
| Interruption | Interrupt active native and bridged work: tools stop before redirect. Operator wait exceeds remaining deadline: redirect still resumes. |
|
|
16
|
+
| Shutdown | Stall a real process, close within a bounded timeout, verify its PID disappears and the final protocol record survives. |
|
|
17
|
+
| Checkpoints | Fresh native home resumes the same thread with history, tools, and accurate usage. Scoring-only resume starts no Codex process. |
|
|
18
|
+
| Native options / RPC | Installed pinned binary demonstrates the new assumption, with valid and invalid controls where applicable. A scripted app-server peer alone is insufficient. |
|
|
19
|
+
|
|
20
|
+
Preserve or extend the affected row's evidence. Different ordering, ownership,
|
|
21
|
+
or failure mechanisms justify separate cases; different numbers or model labels
|
|
22
|
+
on the same path do not.
|
|
23
|
+
|
|
24
|
+
## Checks before merge
|
|
25
|
+
|
|
26
|
+
Run from this package directory:
|
|
27
|
+
|
|
28
|
+
| Change | Required commands |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| Code / tests | `uv run pytest -q`; `uv run ruff check .`; `uv run ty check` |
|
|
31
|
+
| Provisioning, transport, lifecycle, checkpoints; every release | Also `uv run pytest -q -m containers` |
|
|
32
|
+
| Codex/Inspect pin, RPC schema, generator | All above plus `uv run python scripts/generate_protocol.py --check`; regenerate bindings |
|
|
33
|
+
| Documentation only | Check changed links and commands |
|
|
34
|
+
|
|
35
|
+
Default pytest includes native tests and excludes containers. Missing pinned-binary
|
|
36
|
+
or Docker prerequisites must fail visibly. Report required checks left unrun.
|
|
37
|
+
|
|
38
|
+
## Reject / prune
|
|
39
|
+
|
|
40
|
+
Remove duplicate helper, forwarding, call-count, source-layout, and presentation
|
|
41
|
+
checks unless they protect a distinct external contract. Keep behavior-preserving
|
|
42
|
+
refactors assertion-neutral. No coverage quotas or mandatory tests per edit.
|
|
43
|
+
|
|
44
|
+
Peers reject unexpected RPCs and never reproduce adapter accounting/recovery.
|
|
45
|
+
Use real processes/files for lifecycle claims; own temporary homes, logs, tasks,
|
|
46
|
+
and containers. Synchronize on events; bound teardown. No flaky-test retries,
|
|
47
|
+
user-artifact cleanup, live credentials, or paid inference in correctness gates.
|