codex-app-server-sdk 0.3.2__tar.gz → 0.4.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.
Files changed (69) hide show
  1. codex_app_server_sdk-0.4.1/.github/workflows/ci.yml +100 -0
  2. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/.github/workflows/docs.yml +15 -11
  3. codex_app_server_sdk-0.4.1/.github/workflows/publish.yml +110 -0
  4. codex_app_server_sdk-0.4.1/CHANGELOG.md +104 -0
  5. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/PKG-INFO +65 -8
  6. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/README.md +61 -5
  7. codex_app_server_sdk-0.4.1/RELEASE.md +9 -0
  8. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/approvals-and-sandbox.md +43 -11
  9. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/behavior-guarantees.md +16 -2
  10. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/conversation.md +10 -0
  11. codex_app_server_sdk-0.4.1/docs/human-in-the-loop.md +161 -0
  12. codex_app_server_sdk-0.4.1/docs/index.md +102 -0
  13. codex_app_server_sdk-0.4.1/docs/migration-0.4.0.md +222 -0
  14. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/recipes/index.md +1 -0
  15. codex_app_server_sdk-0.4.1/docs/releasing.md +206 -0
  16. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/timeouts-continuation-cancel.md +27 -1
  17. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/mkdocs.yml +3 -0
  18. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/pyproject.toml +24 -5
  19. codex_app_server_sdk-0.4.1/scripts/__init__.py +1 -0
  20. codex_app_server_sdk-0.4.1/scripts/check_quality.py +86 -0
  21. codex_app_server_sdk-0.4.1/scripts/check_release.py +264 -0
  22. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/src/codex_app_server_sdk/__init__.py +18 -0
  23. codex_app_server_sdk-0.4.1/src/codex_app_server_sdk/_version.py +7 -0
  24. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/src/codex_app_server_sdk/client.py +679 -231
  25. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/src/codex_app_server_sdk/models.py +76 -4
  26. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/src/codex_app_server_sdk/protocol.py +1 -0
  27. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/tests/test_chat_continuation.py +17 -3
  28. codex_app_server_sdk-0.4.1/tests/test_client_correctness.py +412 -0
  29. codex_app_server_sdk-0.4.1/tests/test_collaboration_mode.py +129 -0
  30. codex_app_server_sdk-0.4.1/tests/test_live_app_server.py +83 -0
  31. codex_app_server_sdk-0.4.1/tests/test_release_checks.py +292 -0
  32. codex_app_server_sdk-0.4.1/tests/test_user_input_requests.py +202 -0
  33. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/uv.lock +650 -622
  34. codex_app_server_sdk-0.3.2/.github/workflows/publish.yml +0 -52
  35. codex_app_server_sdk-0.3.2/RELEASE.md +0 -56
  36. codex_app_server_sdk-0.3.2/docs/index.md +0 -59
  37. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/.gitignore +0 -0
  38. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/LICENSE +0 -0
  39. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/api/client.md +0 -0
  40. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/api/errors.md +0 -0
  41. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/api/index.md +0 -0
  42. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/api/models.md +0 -0
  43. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/api/package.md +0 -0
  44. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/api/protocol.md +0 -0
  45. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/api/transport.md +0 -0
  46. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/examples.md +0 -0
  47. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/getting-started.md +0 -0
  48. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/protocol-mapping.md +0 -0
  49. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/threads-and-config.md +0 -0
  50. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/docs/transports.md +0 -0
  51. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/examples/chat_session_stdio.py +0 -0
  52. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/examples/chat_session_websocket.py +0 -0
  53. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/examples/chat_steps_rich.py +0 -0
  54. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/examples/thread_concurrent_handles.py +0 -0
  55. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/examples/thread_config_and_fork.py +0 -0
  56. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/examples/thread_ops_showcase.py +0 -0
  57. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/examples/thread_resume_by_id.py +0 -0
  58. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/scripts/check_chat_method_links.py +0 -0
  59. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/src/codex_app_server_sdk/errors.py +0 -0
  60. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/src/codex_app_server_sdk/py.typed +0 -0
  61. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/src/codex_app_server_sdk/transport.py +0 -0
  62. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/tests/test_approval_requests.py +0 -0
  63. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/tests/test_chat_assembly_completed_item.py +0 -0
  64. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/tests/test_chat_steps.py +0 -0
  65. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/tests/test_client_chat_once.py +0 -0
  66. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/tests/test_client_lifecycle.py +0 -0
  67. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/tests/test_protocol.py +0 -0
  68. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/tests/test_thread_handle.py +0 -0
  69. {codex_app_server_sdk-0.3.2 → codex_app_server_sdk-0.4.1}/tests/test_transport.py +0 -0
@@ -0,0 +1,100 @@
1
+ name: ci
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main, master]
6
+ push:
7
+ branches: [main, master]
8
+ workflow_call:
9
+ inputs:
10
+ base_ref:
11
+ description: Previous release tag for changed-file quality checks
12
+ required: true
13
+ type: string
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ env:
19
+ CODEX_SDK_LIVE_TESTS: "0"
20
+
21
+ jobs:
22
+ test:
23
+ runs-on: ubuntu-latest
24
+ strategy:
25
+ fail-fast: false
26
+ matrix:
27
+ python: ["3.12", "3.13", "3.14"]
28
+ steps:
29
+ - uses: actions/checkout@v7.0.1
30
+ - uses: actions/setup-python@v7.0.0
31
+ with:
32
+ python-version: ${{ matrix.python }}
33
+ - uses: astral-sh/setup-uv@v10.2.0
34
+ with:
35
+ version: "0.11.18"
36
+ - run: uv sync --locked --group dev
37
+ - run: uv run --locked python -m pytest -q
38
+
39
+ quality:
40
+ runs-on: ubuntu-latest
41
+ steps:
42
+ - uses: actions/checkout@v7.0.1
43
+ with:
44
+ fetch-depth: 0
45
+ - uses: actions/setup-python@v7.0.0
46
+ with:
47
+ python-version: "3.12"
48
+ - uses: astral-sh/setup-uv@v10.2.0
49
+ with:
50
+ version: "0.11.18"
51
+ - run: uv sync --locked --group dev
52
+ - name: Check changed Python files in parallel
53
+ env:
54
+ BASE_REF: ${{ inputs.base_ref || github.event.pull_request.base.sha || github.event.before }}
55
+ run: uv run --locked python scripts/check_quality.py --base "$BASE_REF"
56
+
57
+ package:
58
+ needs: [test, quality]
59
+ runs-on: ubuntu-latest
60
+ steps:
61
+ - uses: actions/checkout@v7.0.1
62
+ - uses: actions/setup-python@v7.0.0
63
+ with:
64
+ python-version: "3.12"
65
+ - uses: astral-sh/setup-uv@v10.2.0
66
+ with:
67
+ version: "0.11.18"
68
+ - run: uv sync --locked --group dev
69
+ - name: Check documentation
70
+ run: |
71
+ uv run --locked python scripts/check_chat_method_links.py
72
+ uv run --locked zensical build
73
+ - name: Build and validate distributions
74
+ run: |
75
+ uv build --no-sources
76
+ uv run --locked twine check --strict dist/*
77
+ uv run --locked python scripts/check_release.py --dist-dir dist
78
+ - name: Smoke test the installed wheel outside the source environment
79
+ run: |
80
+ export EXPECTED_VERSION
81
+ EXPECTED_VERSION=$(uv version --short)
82
+ wheels=(dist/*.whl)
83
+ uv run --isolated --no-project --with "${wheels[0]}" python -I - <<'PY'
84
+ import os
85
+ from importlib.metadata import version
86
+ from importlib.resources import files
87
+ from codex_app_server_sdk import CodexClient, __version__
88
+
89
+ assert __version__ == version("codex-app-server-sdk") == os.environ["EXPECTED_VERSION"]
90
+ assert files("codex_app_server_sdk").joinpath("py.typed").is_file()
91
+ assert callable(CodexClient.connect_stdio)
92
+ PY
93
+ - name: Reject conflicting artifacts already on PyPI
94
+ if: startsWith(github.ref, 'refs/tags/')
95
+ run: uv run --locked python scripts/check_release.py --dist-dir dist --check-pypi
96
+ - uses: actions/upload-artifact@v7.0.1
97
+ with:
98
+ name: dist
99
+ path: dist/*
100
+ if-no-files-found: error
@@ -12,24 +12,26 @@ jobs:
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
14
  - name: Checkout
15
- uses: actions/checkout@v4
15
+ uses: actions/checkout@v7.0.1
16
16
 
17
17
  - name: Setup Python
18
- uses: actions/setup-python@v5
18
+ uses: actions/setup-python@v7.0.0
19
19
  with:
20
20
  python-version: "3.12"
21
21
 
22
22
  - name: Setup uv
23
- uses: astral-sh/setup-uv@v3
23
+ uses: astral-sh/setup-uv@v10.2.0
24
+ with:
25
+ version: "0.11.18"
24
26
 
25
27
  - name: Install dependencies
26
- run: uv sync --group dev
28
+ run: uv sync --locked --group dev
27
29
 
28
30
  - name: Check method links
29
- run: uv run python scripts/check_chat_method_links.py
31
+ run: uv run --locked python scripts/check_chat_method_links.py
30
32
 
31
33
  - name: Build docs
32
- run: uv run zensical build
34
+ run: uv run --locked zensical build
33
35
 
34
36
  - name: Link check
35
37
  uses: lycheeverse/lychee-action@v2
@@ -58,21 +60,23 @@ jobs:
58
60
  url: ${{ steps.deployment.outputs.page_url }}
59
61
  steps:
60
62
  - name: Checkout
61
- uses: actions/checkout@v4
63
+ uses: actions/checkout@v7.0.1
62
64
 
63
65
  - name: Setup Python
64
- uses: actions/setup-python@v5
66
+ uses: actions/setup-python@v7.0.0
65
67
  with:
66
68
  python-version: "3.12"
67
69
 
68
70
  - name: Setup uv
69
- uses: astral-sh/setup-uv@v3
71
+ uses: astral-sh/setup-uv@v10.2.0
72
+ with:
73
+ version: "0.11.18"
70
74
 
71
75
  - name: Install dependencies
72
- run: uv sync --group dev
76
+ run: uv sync --locked --group dev
73
77
 
74
78
  - name: Build docs
75
- run: uv run zensical build
79
+ run: uv run --locked zensical build
76
80
 
77
81
  - name: Configure Pages
78
82
  uses: actions/configure-pages@v5
@@ -0,0 +1,110 @@
1
+ name: publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: publish-${{ github.ref }}
14
+ cancel-in-progress: false
15
+
16
+ jobs:
17
+ validate:
18
+ runs-on: ubuntu-latest
19
+ outputs:
20
+ version: ${{ steps.release.outputs.version }}
21
+ base_ref: ${{ steps.release.outputs.base_ref }}
22
+ prerelease: ${{ steps.release.outputs.prerelease }}
23
+ steps:
24
+ - name: Require a tag, including for manual runs
25
+ env:
26
+ REF_TYPE: ${{ github.ref_type }}
27
+ run: test "$REF_TYPE" = tag
28
+ - uses: actions/checkout@v7.0.1
29
+ with:
30
+ fetch-depth: 0
31
+ - uses: actions/setup-python@v7.0.0
32
+ with:
33
+ python-version: "3.12"
34
+ - uses: astral-sh/setup-uv@v10.2.0
35
+ with:
36
+ version: "0.11.18"
37
+ - run: uv sync --locked --group dev
38
+ - name: Validate version, tag commit, and release notes
39
+ id: release
40
+ env:
41
+ RELEASE_TAG: ${{ github.ref_name }}
42
+ run: >-
43
+ uv run --locked python scripts/check_release.py
44
+ --tag "$RELEASE_TAG" --require-tag
45
+ --notes-file release-notes.md --github-output "$GITHUB_OUTPUT"
46
+ - uses: actions/upload-artifact@v7.0.1
47
+ with:
48
+ name: release-notes
49
+ path: release-notes.md
50
+ if-no-files-found: error
51
+
52
+ checks:
53
+ needs: validate
54
+ uses: ./.github/workflows/ci.yml
55
+ with:
56
+ base_ref: ${{ needs.validate.outputs.base_ref }}
57
+
58
+ publish:
59
+ needs: checks
60
+ runs-on: ubuntu-latest
61
+ environment:
62
+ name: pypi
63
+ url: https://pypi.org/p/codex-app-server-sdk
64
+ permissions:
65
+ id-token: write
66
+ steps:
67
+ - name: Download distributions
68
+ uses: actions/download-artifact@v8.0.1
69
+ with:
70
+ name: dist
71
+ path: dist
72
+
73
+ - name: Publish to PyPI
74
+ uses: pypa/gh-action-pypi-publish@release/v1
75
+ with:
76
+ # The package job first rejects same-name files with different hashes.
77
+ skip-existing: true
78
+
79
+ github-release:
80
+ needs: [validate, publish]
81
+ runs-on: ubuntu-latest
82
+ permissions:
83
+ contents: write
84
+ env:
85
+ GH_TOKEN: ${{ github.token }}
86
+ GH_REPO: ${{ github.repository }}
87
+ RELEASE_TAG: ${{ github.ref_name }}
88
+ PRERELEASE: ${{ needs.validate.outputs.prerelease }}
89
+ steps:
90
+ - uses: actions/download-artifact@v8.0.1
91
+ with:
92
+ name: dist
93
+ path: dist
94
+ - uses: actions/download-artifact@v8.0.1
95
+ with:
96
+ name: release-notes
97
+ - name: Publish release notes and the exact PyPI artifacts
98
+ run: |
99
+ if draft_status=$(gh release view "$RELEASE_TAG" --json isDraft --jq .isDraft 2>/dev/null); then
100
+ if [ "$draft_status" = false ]; then
101
+ echo "GitHub Release already published: $RELEASE_TAG"
102
+ exit 0
103
+ fi
104
+ else
105
+ gh release create "$RELEASE_TAG" --verify-tag --draft \
106
+ --title "$RELEASE_TAG" --notes-file release-notes.md
107
+ fi
108
+ gh release upload "$RELEASE_TAG" dist/* --clobber
109
+ gh release edit "$RELEASE_TAG" --draft=false \
110
+ --prerelease="$PRERELEASE" --notes-file release-notes.md
@@ -0,0 +1,104 @@
1
+ # Changelog
2
+
3
+ Version headings identify prepared releases. Publication dates and artifacts
4
+ are recorded in GitHub Releases and PyPI.
5
+
6
+ ## 0.4.1
7
+
8
+ ### Fixed
9
+
10
+ - Convert the README's relative changelog and release-procedure links to
11
+ version-tagged GitHub URLs when building the PyPI description. The source
12
+ README keeps its relative links.
13
+
14
+ ### Compatibility
15
+
16
+ - Packaging/documentation patch; the SDK API and behavior are unchanged from 0.4.0.
17
+ The 0.4.0 migration requirements below still apply.
18
+ - Source builds now use `hatch-fancy-pypi-readme` as a build dependency. Isolated
19
+ builds install it automatically; builds without isolation must provide it.
20
+ Wheel runtime dependencies are unchanged.
21
+
22
+ ## 0.4.0
23
+
24
+ ### Compatibility and required migration
25
+
26
+ **This release is not a drop-in behavior-compatible upgrade from 0.3.2.**
27
+ Read the [complete migration guide](https://emsi.github.io/codex-app-server-sdk/migration-0.4.0/)
28
+ before deploying an existing application. Existing public methods and imports
29
+ remain available, but callers may need the following changes:
30
+
31
+ - **Manual approvals:** set `approval_mode="manual"` when responding through
32
+ `approval_requests()` without a callback. Previously, these responses raced
33
+ automatic decline. The default still declines without a handler; a callback
34
+ handles requests in either mode. Consuming the stream does not select manual
35
+ mode. Late, duplicate, server-resolved, or mismatched approval responses now
36
+ fail stricter pending-request checks.
37
+ - **Unsuccessful turns:** both conversation APIs raise `CodexProtocolError`
38
+ for failed/interrupted terminal statuses, even after partial output. A stream
39
+ can yield steps before raising; partial assistant text is not proof of success.
40
+ - **Cancellation errors and ownership:** `cancel()` propagates interrupt RPC,
41
+ request-timeout, and transport failures. Missing terminal confirmation raises
42
+ `CodexTurnInactiveError` with the original continuation and cursor. It rejects
43
+ tokens for turns no longer retained by the same client, including repeated
44
+ cancellation after cleanup. Retain tokens on errors, but do not assume a
45
+ failed transport remains usable.
46
+ - **Cancellation results:** `was_interrupted` requires confirmed interruption;
47
+ `was_completed` means successful completion. Both can be false for a failed
48
+ terminal turn. An interrupt acknowledgement alone is not confirmation.
49
+ - **Low-level interruption:** pass `thread_id` to `interrupt_turn()` for turns
50
+ the SDK does not track. Missing or conflicting thread IDs raise `ValueError`.
51
+ - **Initialization:** the first successful call is cached. Later `initialize()`
52
+ calls return the same result and ignore new parameters/timeouts. Supply custom
53
+ settings before implicit initialization. Custom servers and tests must accept
54
+ the new `initialized` notification and the installed SDK version in default
55
+ `clientInfo.version`, replacing the hardcoded `0.1.0`.
56
+ - **Unanswered user questions:** `item/tool/requestUserInput` now waits up to
57
+ 300 seconds without a callback or manual response, instead of immediately
58
+ returning unsupported-method error `-32601`. The default 180-second turn
59
+ inactivity timeout can fire first. Unattended clients can set
60
+ `user_input_response_timeout=0.0` for a prompt error response (`-32000`, not
61
+ the old code); manual UIs may use `None` with an active response loop.
62
+ - **Events and transports:** routing uses explicit turn/thread identifiers,
63
+ not arbitrary nested content. Ambiguous terminal events no longer complete
64
+ arbitrary turns. Raw event counts/timing can change; all waiting consumers
65
+ now receive connection failures. Custom transports and fixtures may need
66
+ updated envelopes and handshake expectations.
67
+ - **Installation and model shape:** package imports require installed
68
+ distribution metadata; use `uv sync` or an editable/wheel install rather
69
+ than copying source alone. `TurnOverrides` adds a field, affecting fixed
70
+ dataclass snapshots and tuple unpacking. Python and runtime dependency
71
+ requirements are unchanged.
72
+
73
+ ### Added
74
+
75
+ - Collaboration mode configuration (`default` and `plan`) through turn overrides.
76
+ - Human input requests, typed answers, callbacks, and manual response streams.
77
+ - Explicit `approval_mode="manual"` for applications that collect approval
78
+ decisions from a person or UI.
79
+ - Public `__version__`, read from installed package metadata and used in the
80
+ app-server initialization handshake.
81
+ - Release validation shared with PR CI: Python 3.12–3.14 tests, changed-file
82
+ quality checks, package checks, and an isolated wheel import.
83
+ - Automated GitHub Releases with changelog notes and the same artifacts as
84
+ PyPI, with version/tag checks and recovery for interrupted uploads.
85
+
86
+ ### Fixed
87
+
88
+ - Concurrent turns receive their own notifications, including events that
89
+ arrive before the turn-start response. Connection failures wake all waiters.
90
+ - Concurrent first calls initialize the connection once and send `initialized`.
91
+ - Failed and interrupted turns raise `CodexProtocolError` from both conversation
92
+ APIs, including when partial assistant text has already arrived.
93
+ - Interrupt requests include both thread and turn identifiers. Cancellation
94
+ retains continuations on errors or timeouts and cleans up after confirmation.
95
+ - Approval responses reject duplicate or already-resolved requests.
96
+ - Update release tooling to validate current Hatchling's core metadata 2.5.
97
+ - Make basedpyright warnings non-fatal consistently in local and GitHub
98
+ Actions checks; type errors remain a release gate.
99
+
100
+ ### Validation
101
+
102
+ - Added deterministic regression tests and an opt-in live smoke test using
103
+ only `gpt-6-luna`. Concurrent turns and cancellation were tested with Codex
104
+ CLI 0.156.1; this does not imply complete coverage of its protocol.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: codex-app-server-sdk
3
- Version: 0.3.2
3
+ Version: 0.4.1
4
4
  Summary: Async Python client for Codex app-server over stdio and websocket.
5
5
  Project-URL: Documentation, https://emsi.github.io/codex-app-server-sdk/
6
6
  Project-URL: Repository, https://github.com/emsi/codex-app-server-sdk
@@ -674,6 +674,7 @@ Classifier: License :: OSI Approved :: GNU Affero General Public License v3
674
674
  Classifier: Programming Language :: Python :: 3
675
675
  Classifier: Programming Language :: Python :: 3.12
676
676
  Classifier: Programming Language :: Python :: 3.13
677
+ Classifier: Programming Language :: Python :: 3.14
677
678
  Classifier: Typing :: Typed
678
679
  Requires-Python: >=3.12
679
680
  Requires-Dist: pydantic>=2.8.0
@@ -682,7 +683,7 @@ Provides-Extra: dev
682
683
  Requires-Dist: build>=1.2.2; extra == 'dev'
683
684
  Requires-Dist: mkdocstrings-python>=1.18.2; extra == 'dev'
684
685
  Requires-Dist: pytest>=8.2.0; extra == 'dev'
685
- Requires-Dist: twine>=6.0.1; extra == 'dev'
686
+ Requires-Dist: twine>=7.0.0; extra == 'dev'
686
687
  Requires-Dist: zensical>=0.0.23; extra == 'dev'
687
688
  Description-Content-Type: text/markdown
688
689
 
@@ -694,6 +695,13 @@ It gives you a convenient conversation API over `stdio` or `websocket` without h
694
695
 
695
696
  Documentation: https://emsi.github.io/codex-app-server-sdk/
696
697
 
698
+ > **Upgrading to 0.4.0? Behavior changes require review.** Read the
699
+ > [0.3.2 → 0.4.0 migration guide](https://emsi.github.io/codex-app-server-sdk/migration-0.4.0/)
700
+ > before upgrading.
701
+ > Stream-based approval responders must set `approval_mode="manual"`.
702
+ > Failed/interrupted turns now raise; cancellation, initialization, unanswered
703
+ > user questions, and custom transport expectations also change.
704
+
697
705
  ## Highlights
698
706
 
699
707
  - simple one-shot turns with `chat_once(...)`
@@ -702,8 +710,46 @@ Documentation: https://emsi.github.io/codex-app-server-sdk/
702
710
  - thread-scoped config + forking via `ThreadHandle`
703
711
  - inactivity timeout continuation for long-running turns
704
712
  - turn cancellation with unread-step/event drain via `cancel(...)`
713
+ - collaboration mode overrides (`default`/`plan`) via `TurnOverrides`
714
+ - human-in-the-loop user input handling (`item/tool/requestUserInput`)
705
715
  - optional low-level `request(...)` access when needed
706
716
 
717
+ ## Why use this client?
718
+
719
+ Protocol I/O and callbacks run directly on your application's `asyncio` event
720
+ loop, using asynchronous subprocess pipes or WebSockets. Thread handles share
721
+ one connection, and approvals can integrate with an async callback or a manual
722
+ UI response loop.
723
+
724
+ You control the Codex runtime: launch your chosen executable or connect to an
725
+ existing WebSocket server. The conversation API adds completed-step streaming,
726
+ resumable inactivity timeouts, and cancellation with unread-event recovery.
727
+ The `Transport` interface and raw `request(...)` method remain available for
728
+ application-specific integrations.
729
+
730
+ ### Compared with `openai-codex`
731
+
732
+ Both libraries use the Codex app-server protocol. Their integration choices differ:
733
+
734
+ | Area | `codex-app-server-sdk` | `openai-codex` |
735
+ | --- | --- | --- |
736
+ | Execution | Native `asyncio` client; asynchronous protocol I/O on your event loop | Synchronous client with an async wrapper that offloads blocking operations to background threads |
737
+ | Transport | Public, replaceable `Transport`; built-in stdio and WebSocket support | SDK-managed subprocess communicating through line-delimited JSON over stdio |
738
+ | Protocol access | Flexible dictionary-based RPC via `request(...)`, plus high-level conversation models | Extensive generated types, typed responses, and typed notifications |
739
+ | Runtime management | You supply and manage Codex; choose an executable or connect to an existing WebSocket server | Installs an exactly pinned Codex runtime dependency by default |
740
+
741
+ This client fits applications that need native async I/O, custom transports,
742
+ connections to an existing server, or independent control over runtime upgrades.
743
+ The official SDK offers broader generated type coverage and a reproducible
744
+ runtime default. You are responsible for installing and updating Codex when
745
+ using this client.
746
+
747
+ Comparison verified against the published
748
+ [`openai-codex` 0.156.1](https://pypi.org/project/openai-codex/0.156.1/)
749
+ source and package metadata on 2026-09-23. The official SDK also supports a
750
+ [`CodexConfig(codex_bin=...)` override](https://learn.chatgpt.com/docs/codex-sdk)
751
+ for selecting a different local executable.
752
+
707
753
  ## Install
708
754
 
709
755
  Install `uv` (if needed):
@@ -728,6 +774,10 @@ uv pip install codex-app-server-sdk
728
774
 
729
775
  - Docs site: https://emsi.github.io/codex-app-server-sdk/
730
776
  - PyPI: https://pypi.org/project/codex-app-server-sdk/
777
+ - Human-in-the-loop guide: https://emsi.github.io/codex-app-server-sdk/human-in-the-loop/
778
+ - Release procedure: [RELEASE.md](https://github.com/emsi/codex-app-server-sdk/blob/v0.4.1/RELEASE.md)
779
+ - Upgrading from 0.3.2: [0.4.0 migration guide](https://emsi.github.io/codex-app-server-sdk/migration-0.4.0/)
780
+ - Release notes and migration guidance: [CHANGELOG.md](https://github.com/emsi/codex-app-server-sdk/blob/v0.4.1/CHANGELOG.md)
731
781
 
732
782
  ## Quick start
733
783
 
@@ -1083,13 +1133,13 @@ uv run python examples/chat_session_websocket.py
1083
1133
  - `compact_thread(thread_id)`: request context compaction.
1084
1134
  - `chat(...)` (`text=None, thread_id=None, user=None, metadata=None, thread_config=None, turn_overrides=None, inactivity_timeout=None, continuation=None`): async iterator yielding completed non-delta step blocks.
1085
1135
  - `chat_once(...)` (`text=None, thread_id=None, user=None, metadata=None, thread_config=None, turn_overrides=None, inactivity_timeout=None, continuation=None`): send one user message and wait for completed turn.
1086
- - `cancel(continuation, timeout=None)`: interrupt running turn, return unread steps/events, and clean turn state.
1136
+ - `cancel(continuation, timeout=None)`: interrupt a turn and return unread steps/events after terminal confirmation; retain the continuation if cancellation fails or times out.
1087
1137
  - `steer_turn(thread_id=..., expected_turn_id=..., input_items=...)`: steer active turn input.
1088
1138
  - `start_review(thread_id=..., target=..., delivery=None)`: run review mode.
1089
1139
  - `list_models(...)`: discover available models.
1090
1140
  - `exec_command(command, ...)`: run one command via server command API.
1091
1141
  - `read_config(...)`, `read_config_requirements()`, `write_config_value(...)`, `batch_write_config(...)`: config APIs.
1092
- - `interrupt_turn(turn_id, timeout=None)`: low-level turn interruption request.
1142
+ - `interrupt_turn(turn_id, thread_id=None, timeout=None)`: low-level interruption request; infer the thread for tracked turns or pass it explicitly.
1093
1143
  - `close()`: cancel receive loop and close transport.
1094
1144
 
1095
1145
  ### `Transport` and implementations (`src/codex_app_server_sdk/transport.py`)
@@ -1138,7 +1188,9 @@ uv run python examples/chat_session_websocket.py
1138
1188
  - `chat_once(...)` resolves final text from completed `agentMessage` items (`item/completed`), with `thread/read(includeTurns=true)` fallback.
1139
1189
  - `turn_timeout` is intentionally removed to avoid conflicting timeout semantics.
1140
1190
  - Turn waits are controlled by `inactivity_timeout` (or unbounded when `None`).
1141
- - `cancel(...)` interrupts a continuation turn, returns unread buffered data, and cleans internal session state so the same thread can be reused safely.
1191
+ - `cancel(...)` releases turn state only after a terminal event. RPC failures propagate; a confirmation timeout raises `CodexTurnInactiveError` with the original continuation.
1192
+ - Failed or interrupted turns raise `CodexProtocolError` from both chat APIs, even if partial assistant text was received.
1193
+ - Use `approval_mode="manual"` on either connection factory to answer `approval_requests()` yourself. Without a callback, the default `"auto"` mode declines requests.
1142
1194
  - Advanced thread-level config/fork uses protocol v2 methods (`thread/start`, `thread/resume`, `thread/fork`) exposed via `ThreadHandle` and `ThreadConfig`.
1143
1195
  - `metadata` is applied on `turn/start` payloads for message turns; thread-level config uses schema-aligned fields on thread methods.
1144
1196
  - preferred lifecycle is `async with CodexClient.connect_*() as client:`; manual `start()/close()` remains available for advanced control.
@@ -1157,14 +1209,16 @@ uv run python examples/chat_session_websocket.py
1157
1209
 
1158
1210
  ### Default initialize payload
1159
1211
 
1160
- When `params=None`, the client sends:
1212
+ When `params=None`, the client sends the following payload. The version
1213
+ placeholder is replaced with the installed package version, also available as
1214
+ `codex_app_server_sdk.__version__`:
1161
1215
 
1162
1216
  ```json
1163
1217
  {
1164
1218
  "protocolVersion": "1",
1165
1219
  "clientInfo": {
1166
1220
  "name": "codex-app-server-sdk",
1167
- "version": "0.1.0"
1221
+ "version": "<installed SDK version>"
1168
1222
  },
1169
1223
  "capabilities": {
1170
1224
  "optOutNotificationMethods": [
@@ -1206,6 +1260,9 @@ Merge rules:
1206
1260
 
1207
1261
  ### Example: explicit initialize
1208
1262
 
1263
+ The custom `clientInfo.version` below identifies your application, independently
1264
+ of the SDK version.
1265
+
1209
1266
  ```python
1210
1267
  import asyncio
1211
1268
  from codex_app_server_sdk import CodexClient
@@ -6,6 +6,13 @@ It gives you a convenient conversation API over `stdio` or `websocket` without h
6
6
 
7
7
  Documentation: https://emsi.github.io/codex-app-server-sdk/
8
8
 
9
+ > **Upgrading to 0.4.0? Behavior changes require review.** Read the
10
+ > [0.3.2 → 0.4.0 migration guide](https://emsi.github.io/codex-app-server-sdk/migration-0.4.0/)
11
+ > before upgrading.
12
+ > Stream-based approval responders must set `approval_mode="manual"`.
13
+ > Failed/interrupted turns now raise; cancellation, initialization, unanswered
14
+ > user questions, and custom transport expectations also change.
15
+
9
16
  ## Highlights
10
17
 
11
18
  - simple one-shot turns with `chat_once(...)`
@@ -14,8 +21,46 @@ Documentation: https://emsi.github.io/codex-app-server-sdk/
14
21
  - thread-scoped config + forking via `ThreadHandle`
15
22
  - inactivity timeout continuation for long-running turns
16
23
  - turn cancellation with unread-step/event drain via `cancel(...)`
24
+ - collaboration mode overrides (`default`/`plan`) via `TurnOverrides`
25
+ - human-in-the-loop user input handling (`item/tool/requestUserInput`)
17
26
  - optional low-level `request(...)` access when needed
18
27
 
28
+ ## Why use this client?
29
+
30
+ Protocol I/O and callbacks run directly on your application's `asyncio` event
31
+ loop, using asynchronous subprocess pipes or WebSockets. Thread handles share
32
+ one connection, and approvals can integrate with an async callback or a manual
33
+ UI response loop.
34
+
35
+ You control the Codex runtime: launch your chosen executable or connect to an
36
+ existing WebSocket server. The conversation API adds completed-step streaming,
37
+ resumable inactivity timeouts, and cancellation with unread-event recovery.
38
+ The `Transport` interface and raw `request(...)` method remain available for
39
+ application-specific integrations.
40
+
41
+ ### Compared with `openai-codex`
42
+
43
+ Both libraries use the Codex app-server protocol. Their integration choices differ:
44
+
45
+ | Area | `codex-app-server-sdk` | `openai-codex` |
46
+ | --- | --- | --- |
47
+ | Execution | Native `asyncio` client; asynchronous protocol I/O on your event loop | Synchronous client with an async wrapper that offloads blocking operations to background threads |
48
+ | Transport | Public, replaceable `Transport`; built-in stdio and WebSocket support | SDK-managed subprocess communicating through line-delimited JSON over stdio |
49
+ | Protocol access | Flexible dictionary-based RPC via `request(...)`, plus high-level conversation models | Extensive generated types, typed responses, and typed notifications |
50
+ | Runtime management | You supply and manage Codex; choose an executable or connect to an existing WebSocket server | Installs an exactly pinned Codex runtime dependency by default |
51
+
52
+ This client fits applications that need native async I/O, custom transports,
53
+ connections to an existing server, or independent control over runtime upgrades.
54
+ The official SDK offers broader generated type coverage and a reproducible
55
+ runtime default. You are responsible for installing and updating Codex when
56
+ using this client.
57
+
58
+ Comparison verified against the published
59
+ [`openai-codex` 0.156.1](https://pypi.org/project/openai-codex/0.156.1/)
60
+ source and package metadata on 2026-09-23. The official SDK also supports a
61
+ [`CodexConfig(codex_bin=...)` override](https://learn.chatgpt.com/docs/codex-sdk)
62
+ for selecting a different local executable.
63
+
19
64
  ## Install
20
65
 
21
66
  Install `uv` (if needed):
@@ -40,6 +85,10 @@ uv pip install codex-app-server-sdk
40
85
 
41
86
  - Docs site: https://emsi.github.io/codex-app-server-sdk/
42
87
  - PyPI: https://pypi.org/project/codex-app-server-sdk/
88
+ - Human-in-the-loop guide: https://emsi.github.io/codex-app-server-sdk/human-in-the-loop/
89
+ - Release procedure: [RELEASE.md](RELEASE.md)
90
+ - Upgrading from 0.3.2: [0.4.0 migration guide](https://emsi.github.io/codex-app-server-sdk/migration-0.4.0/)
91
+ - Release notes and migration guidance: [CHANGELOG.md](CHANGELOG.md)
43
92
 
44
93
  ## Quick start
45
94
 
@@ -395,13 +444,13 @@ uv run python examples/chat_session_websocket.py
395
444
  - `compact_thread(thread_id)`: request context compaction.
396
445
  - `chat(...)` (`text=None, thread_id=None, user=None, metadata=None, thread_config=None, turn_overrides=None, inactivity_timeout=None, continuation=None`): async iterator yielding completed non-delta step blocks.
397
446
  - `chat_once(...)` (`text=None, thread_id=None, user=None, metadata=None, thread_config=None, turn_overrides=None, inactivity_timeout=None, continuation=None`): send one user message and wait for completed turn.
398
- - `cancel(continuation, timeout=None)`: interrupt running turn, return unread steps/events, and clean turn state.
447
+ - `cancel(continuation, timeout=None)`: interrupt a turn and return unread steps/events after terminal confirmation; retain the continuation if cancellation fails or times out.
399
448
  - `steer_turn(thread_id=..., expected_turn_id=..., input_items=...)`: steer active turn input.
400
449
  - `start_review(thread_id=..., target=..., delivery=None)`: run review mode.
401
450
  - `list_models(...)`: discover available models.
402
451
  - `exec_command(command, ...)`: run one command via server command API.
403
452
  - `read_config(...)`, `read_config_requirements()`, `write_config_value(...)`, `batch_write_config(...)`: config APIs.
404
- - `interrupt_turn(turn_id, timeout=None)`: low-level turn interruption request.
453
+ - `interrupt_turn(turn_id, thread_id=None, timeout=None)`: low-level interruption request; infer the thread for tracked turns or pass it explicitly.
405
454
  - `close()`: cancel receive loop and close transport.
406
455
 
407
456
  ### `Transport` and implementations (`src/codex_app_server_sdk/transport.py`)
@@ -450,7 +499,9 @@ uv run python examples/chat_session_websocket.py
450
499
  - `chat_once(...)` resolves final text from completed `agentMessage` items (`item/completed`), with `thread/read(includeTurns=true)` fallback.
451
500
  - `turn_timeout` is intentionally removed to avoid conflicting timeout semantics.
452
501
  - Turn waits are controlled by `inactivity_timeout` (or unbounded when `None`).
453
- - `cancel(...)` interrupts a continuation turn, returns unread buffered data, and cleans internal session state so the same thread can be reused safely.
502
+ - `cancel(...)` releases turn state only after a terminal event. RPC failures propagate; a confirmation timeout raises `CodexTurnInactiveError` with the original continuation.
503
+ - Failed or interrupted turns raise `CodexProtocolError` from both chat APIs, even if partial assistant text was received.
504
+ - Use `approval_mode="manual"` on either connection factory to answer `approval_requests()` yourself. Without a callback, the default `"auto"` mode declines requests.
454
505
  - Advanced thread-level config/fork uses protocol v2 methods (`thread/start`, `thread/resume`, `thread/fork`) exposed via `ThreadHandle` and `ThreadConfig`.
455
506
  - `metadata` is applied on `turn/start` payloads for message turns; thread-level config uses schema-aligned fields on thread methods.
456
507
  - preferred lifecycle is `async with CodexClient.connect_*() as client:`; manual `start()/close()` remains available for advanced control.
@@ -469,14 +520,16 @@ uv run python examples/chat_session_websocket.py
469
520
 
470
521
  ### Default initialize payload
471
522
 
472
- When `params=None`, the client sends:
523
+ When `params=None`, the client sends the following payload. The version
524
+ placeholder is replaced with the installed package version, also available as
525
+ `codex_app_server_sdk.__version__`:
473
526
 
474
527
  ```json
475
528
  {
476
529
  "protocolVersion": "1",
477
530
  "clientInfo": {
478
531
  "name": "codex-app-server-sdk",
479
- "version": "0.1.0"
532
+ "version": "<installed SDK version>"
480
533
  },
481
534
  "capabilities": {
482
535
  "optOutNotificationMethods": [
@@ -518,6 +571,9 @@ Merge rules:
518
571
 
519
572
  ### Example: explicit initialize
520
573
 
574
+ The custom `clientInfo.version` below identifies your application, independently
575
+ of the SDK version.
576
+
521
577
  ```python
522
578
  import asyncio
523
579
  from codex_app_server_sdk import CodexClient
@@ -0,0 +1,9 @@
1
+ # Releasing codex-app-server-sdk
2
+
3
+ The maintained procedure is in [the release guide](docs/releasing.md), also
4
+ published on the [documentation site](https://emsi.github.io/codex-app-server-sdk/releasing/).
5
+
6
+ Prepare the version and changelog locally, then push the reviewed version tag.
7
+ GitHub Actions validates, builds, publishes to PyPI, and creates a GitHub Release
8
+ with the same distributions. Do not manually upload packages before pushing the
9
+ tag: the tag already triggers publication.