python-codex 0.3.1__tar.gz → 0.3.2__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 (140) hide show
  1. {python_codex-0.3.1 → python_codex-0.3.2}/.github/workflows/publish.yml +11 -0
  2. {python_codex-0.3.1 → python_codex-0.3.2}/PKG-INFO +31 -4
  3. {python_codex-0.3.1 → python_codex-0.3.2}/README.md +30 -3
  4. {python_codex-0.3.1 → python_codex-0.3.2}/README_ZH.md +26 -3
  5. {python_codex-0.3.1 → python_codex-0.3.2}/docs/ALIGNMENT.md +23 -0
  6. python_codex-0.3.2/docs/RELEASE_0.3.2.md +36 -0
  7. {python_codex-0.3.1 → python_codex-0.3.2}/packages/pycodex-ws/README.md +9 -1
  8. {python_codex-0.3.1 → python_codex-0.3.2}/packages/pycodex-ws/pyproject.toml +2 -2
  9. python_codex-0.3.2/pycodex/__main__.py +4 -0
  10. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/model.py +11 -2
  11. {python_codex-0.3.1 → python_codex-0.3.2}/pyproject.toml +1 -1
  12. {python_codex-0.3.1 → python_codex-0.3.2}/tests/TESTS.md +12 -0
  13. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_doctor.py +16 -4
  14. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_model.py +88 -0
  15. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_packaging.py +28 -0
  16. {python_codex-0.3.1 → python_codex-0.3.2}/.github/workflows/test.yml +0 -0
  17. {python_codex-0.3.1 → python_codex-0.3.2}/.gitignore +0 -0
  18. {python_codex-0.3.1 → python_codex-0.3.2}/AGENTS.md +0 -0
  19. {python_codex-0.3.1 → python_codex-0.3.2}/LICENSE +0 -0
  20. {python_codex-0.3.1 → python_codex-0.3.2}/docs/CONTEXT.md +0 -0
  21. {python_codex-0.3.1 → python_codex-0.3.2}/docs/RELEASE_0.3.0.md +0 -0
  22. {python_codex-0.3.1 → python_codex-0.3.2}/docs/RUNTIME.md +0 -0
  23. {python_codex-0.3.1 → python_codex-0.3.2}/docs/responses_server/README.md +0 -0
  24. {python_codex-0.3.1 → python_codex-0.3.2}/packages/pycodex-ws/pycodex_ws_meta/__init__.py +0 -0
  25. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/__init__.py +0 -0
  26. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/agent.py +0 -0
  27. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/bootstrap.py +0 -0
  28. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/cli.py +0 -0
  29. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/compat.py +0 -0
  30. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/context.py +0 -0
  31. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/doctor.py +0 -0
  32. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/events.py +0 -0
  33. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/feishu_card.py +0 -0
  34. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/feishu_link.py +0 -0
  35. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/model_metadata.py +0 -0
  36. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/portable.py +0 -0
  37. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/portable_server.py +0 -0
  38. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/prompts/default_base_instructions.md +0 -0
  39. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/prompts/models.json +0 -0
  40. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/prompts/permissions/approval_policy/never.md +0 -0
  41. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/prompts/permissions/approval_policy/on_failure.md +0 -0
  42. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/prompts/permissions/approval_policy/on_request.md +0 -0
  43. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/prompts/permissions/approval_policy/on_request_rule_request_permission.md +0 -0
  44. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/prompts/permissions/approval_policy/unless_trusted.md +0 -0
  45. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/prompts/permissions/sandbox_mode/danger_full_access.md +0 -0
  46. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/prompts/permissions/sandbox_mode/read_only.md +0 -0
  47. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/prompts/permissions/sandbox_mode/workspace_write.md +0 -0
  48. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/protocol.py +0 -0
  49. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/runtime.py +0 -0
  50. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/runtime_services.py +0 -0
  51. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/__init__.py +0 -0
  52. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/agent_tool_schemas.py +0 -0
  53. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/apply_patch_tool.py +0 -0
  54. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/base_tool.py +0 -0
  55. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/clock_tool.py +0 -0
  56. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/close_agent_tool.py +0 -0
  57. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/code_mode_manager.py +0 -0
  58. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/exec_command_tool.py +0 -0
  59. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/exec_runtime.js +0 -0
  60. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/exec_tool.py +0 -0
  61. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/grep_files_tool.py +0 -0
  62. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/ipython_tool.py +0 -0
  63. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/list_dir_tool.py +0 -0
  64. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/read_file_tool.py +0 -0
  65. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/request_permissions_tool.py +0 -0
  66. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/request_user_input_tool.py +0 -0
  67. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/resume_agent_tool.py +0 -0
  68. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/send_input_tool.py +0 -0
  69. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/shell_command_tool.py +0 -0
  70. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/shell_tool.py +0 -0
  71. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/spawn_agent_tool.py +0 -0
  72. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/unified_exec_manager.py +0 -0
  73. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/update_plan_tool.py +0 -0
  74. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/view_image_tool.py +0 -0
  75. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/wait_agent_tool.py +0 -0
  76. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/wait_tool.py +0 -0
  77. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/web_search_tool.py +0 -0
  78. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/tools/write_stdin_tool.py +0 -0
  79. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/utils/__init__.py +0 -0
  80. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/utils/async_bridge.py +0 -0
  81. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/utils/compactor.py +0 -0
  82. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/utils/debug.py +0 -0
  83. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/utils/dotenv.py +0 -0
  84. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/utils/event_helpers.py +0 -0
  85. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/utils/get_env.py +0 -0
  86. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/utils/image_utils.py +0 -0
  87. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/utils/random_ids.py +0 -0
  88. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/utils/session_persist.py +0 -0
  89. {python_codex-0.3.1 → python_codex-0.3.2}/pycodex/utils/truncation.py +0 -0
  90. {python_codex-0.3.1 → python_codex-0.3.2}/responses_server/__init__.py +0 -0
  91. {python_codex-0.3.1 → python_codex-0.3.2}/responses_server/__main__.py +0 -0
  92. {python_codex-0.3.1 → python_codex-0.3.2}/responses_server/app.py +0 -0
  93. {python_codex-0.3.1 → python_codex-0.3.2}/responses_server/config.py +0 -0
  94. {python_codex-0.3.1 → python_codex-0.3.2}/responses_server/messages_api.py +0 -0
  95. {python_codex-0.3.1 → python_codex-0.3.2}/responses_server/payload_processors.py +0 -0
  96. {python_codex-0.3.1 → python_codex-0.3.2}/responses_server/server.py +0 -0
  97. {python_codex-0.3.1 → python_codex-0.3.2}/responses_server/session_store.py +0 -0
  98. {python_codex-0.3.1 → python_codex-0.3.2}/responses_server/stream_router.py +0 -0
  99. {python_codex-0.3.1 → python_codex-0.3.2}/responses_server/tools/__init__.py +0 -0
  100. {python_codex-0.3.1 → python_codex-0.3.2}/responses_server/tools/custom_adapter.py +0 -0
  101. {python_codex-0.3.1 → python_codex-0.3.2}/responses_server/tools/web_search.py +0 -0
  102. {python_codex-0.3.1 → python_codex-0.3.2}/responses_server/trajectory_dump.py +0 -0
  103. {python_codex-0.3.1 → python_codex-0.3.2}/tests/__init__.py +0 -0
  104. {python_codex-0.3.1 → python_codex-0.3.2}/tests/compare_context_requests.py +0 -0
  105. {python_codex-0.3.1 → python_codex-0.3.2}/tests/compare_steer_request_bodies.py +0 -0
  106. {python_codex-0.3.1 → python_codex-0.3.2}/tests/compare_tool_schemas.py +0 -0
  107. {python_codex-0.3.1 → python_codex-0.3.2}/tests/conftest.py +0 -0
  108. {python_codex-0.3.1 → python_codex-0.3.2}/tests/fake_responses_server.py +0 -0
  109. {python_codex-0.3.1 → python_codex-0.3.2}/tests/fakes.py +0 -0
  110. {python_codex-0.3.1 → python_codex-0.3.2}/tests/responses_server/fake_chat_completions_server.py +0 -0
  111. {python_codex-0.3.1 → python_codex-0.3.2}/tests/responses_server/test_server.py +0 -0
  112. {python_codex-0.3.1 → python_codex-0.3.2}/tests/responses_server/test_trajectory_dump.py +0 -0
  113. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_agent.py +0 -0
  114. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_agent_state.py +0 -0
  115. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_async_bridge.py +0 -0
  116. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_builtin_tools.py +0 -0
  117. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_cli.py +0 -0
  118. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_compactor.py +0 -0
  119. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_context.py +0 -0
  120. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_events.py +0 -0
  121. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_fake_responses_server.py +0 -0
  122. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_feishu_card.py +0 -0
  123. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_feishu_link.py +0 -0
  124. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_feishu_oauth.py +0 -0
  125. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_ipython_tool.py +0 -0
  126. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_owned_workspace_server.py +0 -0
  127. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_portable.py +0 -0
  128. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_py36_syntax.py +0 -0
  129. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_runtime_state.py +0 -0
  130. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_session_backend.py +0 -0
  131. {python_codex-0.3.1 → python_codex-0.3.2}/tests/test_workspace_server.py +0 -0
  132. {python_codex-0.3.1 → python_codex-0.3.2}/tools/feishu_oauth.py +0 -0
  133. {python_codex-0.3.1 → python_codex-0.3.2}/tools/sync_model_prompts.py +0 -0
  134. {python_codex-0.3.1 → python_codex-0.3.2}/workspace_server/__init__.py +0 -0
  135. {python_codex-0.3.1 → python_codex-0.3.2}/workspace_server/__main__.py +0 -0
  136. {python_codex-0.3.1 → python_codex-0.3.2}/workspace_server/app.py +0 -0
  137. {python_codex-0.3.1 → python_codex-0.3.2}/workspace_server/owned_process.py +0 -0
  138. {python_codex-0.3.1 → python_codex-0.3.2}/workspace_server/workspace.html +0 -0
  139. {python_codex-0.3.1 → python_codex-0.3.2}/workspace_server/workspaces.html +0 -0
  140. {python_codex-0.3.1 → python_codex-0.3.2}/workspace_server/workspaces.py +0 -0
@@ -117,6 +117,17 @@ jobs:
117
117
  python -m build --outdir dist/pycodex-ws packages/pycodex-ws
118
118
  python -m twine check dist/python-codex/* dist/pycodex-ws/*
119
119
 
120
+ - name: Smoke test installed wheels
121
+ run: |
122
+ python -m venv "$RUNNER_TEMP/pycodex-wheel"
123
+ "$RUNNER_TEMP/pycodex-wheel/bin/python" -m pip install \
124
+ dist/python-codex/*.whl dist/pycodex-ws/*.whl
125
+ cd "$RUNNER_TEMP"
126
+ "$RUNNER_TEMP/pycodex-wheel/bin/pycodex" --help
127
+ "$RUNNER_TEMP/pycodex-wheel/bin/pycodex-ws" --help
128
+ "$RUNNER_TEMP/pycodex-wheel/bin/python" -m pycodex --help
129
+ "$RUNNER_TEMP/pycodex-wheel/bin/python" -m workspace_server --help
130
+
120
131
  - name: Upload distributions
121
132
  uses: actions/upload-artifact@v4
122
133
  with:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-codex
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: A minimal Python extraction of Codex's main agent loop
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.6.2
@@ -25,6 +25,8 @@ Description-Content-Type: text/markdown
25
25
 
26
26
  English README. Chinese version: `README_ZH.md`
27
27
 
28
+ 0.3.2 startup fixes: [release notes](docs/RELEASE_0.3.2.md).
29
+
28
30
  0.3.0 release preparation and Python API migration: `docs/RELEASE_0.3.0.md`.
29
31
 
30
32
  PyPI distributions:
@@ -60,11 +62,24 @@ Relevant Rust reference points:
60
62
  Install the full package or the workspace-oriented alias:
61
63
 
62
64
  ```bash
63
- pip install python-codex
64
- pip install pycodex-ws
65
+ python3 -m pip install python-codex
66
+ python3 -m pip install pycodex-ws
65
67
  ```
66
68
 
67
- Install dependencies first:
69
+ Use Python 3.6.2 or newer. Both console commands are installed into that
70
+ interpreter's scripts directory. On a machine with multiple Python installations,
71
+ you can select the same interpreter explicitly for startup:
72
+
73
+ ```bash
74
+ python3 -m pycodex
75
+ python3 -m workspace_server --help
76
+ ```
77
+
78
+ If `pycodex` is missing from `PATH` or resolves to an older installation, use these
79
+ module entry points. `python3 -m pip --version` shows which Python environment
80
+ received the installation.
81
+
82
+ For development from this repository, install dependencies first:
68
83
 
69
84
  ```bash
70
85
  uv sync
@@ -200,6 +215,18 @@ from pycodex import ResponsesModelClient
200
215
  client = ResponsesModelClient.from_codex_config()
201
216
  ```
202
217
 
218
+ `model_provider` is optional and defaults to `openai`. The built-in provider
219
+ does not require a `[model_providers.openai]` table: it uses
220
+ `https://api.openai.com/v1` and reads `OPENAI_API_KEY`. Set `openai_base_url` to
221
+ override this address. Explicit provider tables retain their configured
222
+ `base_url` and optional `env_key`; unknown provider names raise a configuration
223
+ error. The model still comes from `model` in the configuration or selected
224
+ profile.
225
+
226
+ Authentication currently uses API keys from environment variables or `.env`;
227
+ Codex desktop/CLI ChatGPT sign-in credentials in `auth.json` or the OS keychain
228
+ are not loaded.
229
+
203
230
  The current implementation uses the streaming OpenAI-compatible `/responses`
204
231
  endpoint. This path has already been validated against the local
205
232
  `~/.codex/config.toml` setup.
@@ -2,6 +2,8 @@
2
2
 
3
3
  English README. Chinese version: `README_ZH.md`
4
4
 
5
+ 0.3.2 startup fixes: [release notes](docs/RELEASE_0.3.2.md).
6
+
5
7
  0.3.0 release preparation and Python API migration: `docs/RELEASE_0.3.0.md`.
6
8
 
7
9
  PyPI distributions:
@@ -37,11 +39,24 @@ Relevant Rust reference points:
37
39
  Install the full package or the workspace-oriented alias:
38
40
 
39
41
  ```bash
40
- pip install python-codex
41
- pip install pycodex-ws
42
+ python3 -m pip install python-codex
43
+ python3 -m pip install pycodex-ws
42
44
  ```
43
45
 
44
- Install dependencies first:
46
+ Use Python 3.6.2 or newer. Both console commands are installed into that
47
+ interpreter's scripts directory. On a machine with multiple Python installations,
48
+ you can select the same interpreter explicitly for startup:
49
+
50
+ ```bash
51
+ python3 -m pycodex
52
+ python3 -m workspace_server --help
53
+ ```
54
+
55
+ If `pycodex` is missing from `PATH` or resolves to an older installation, use these
56
+ module entry points. `python3 -m pip --version` shows which Python environment
57
+ received the installation.
58
+
59
+ For development from this repository, install dependencies first:
45
60
 
46
61
  ```bash
47
62
  uv sync
@@ -177,6 +192,18 @@ from pycodex import ResponsesModelClient
177
192
  client = ResponsesModelClient.from_codex_config()
178
193
  ```
179
194
 
195
+ `model_provider` is optional and defaults to `openai`. The built-in provider
196
+ does not require a `[model_providers.openai]` table: it uses
197
+ `https://api.openai.com/v1` and reads `OPENAI_API_KEY`. Set `openai_base_url` to
198
+ override this address. Explicit provider tables retain their configured
199
+ `base_url` and optional `env_key`; unknown provider names raise a configuration
200
+ error. The model still comes from `model` in the configuration or selected
201
+ profile.
202
+
203
+ Authentication currently uses API keys from environment variables or `.env`;
204
+ Codex desktop/CLI ChatGPT sign-in credentials in `auth.json` or the OS keychain
205
+ are not loaded.
206
+
180
207
  The current implementation uses the streaming OpenAI-compatible `/responses`
181
208
  endpoint. This path has already been validated against the local
182
209
  `~/.codex/config.toml` setup.
@@ -2,6 +2,8 @@
2
2
 
3
3
  中文 README。English version: `README.md`
4
4
 
5
+ 0.3.2 启动修复:[发布说明](docs/RELEASE_0.3.2.md)。
6
+
5
7
  0.3.0 发版准备与 Python API 迁移说明:`docs/RELEASE_0.3.0.md`。
6
8
 
7
9
  PyPI distributions:
@@ -34,11 +36,22 @@ Import 路径仍保持 `pycodex`;CLI 命令为 `pycodex` 和 `pycodex-ws`。
34
36
  安装完整包或 workspace 安装别名:
35
37
 
36
38
  ```bash
37
- pip install python-codex
38
- pip install pycodex-ws
39
+ python3 -m pip install python-codex
40
+ python3 -m pip install pycodex-ws
41
+ ```
42
+
43
+ 要求 Python 3.6.2 或更新版本。两个命令会安装到该解释器的 scripts 目录。
44
+ 在同时存在 Python 2/3 或多套 Python 的机器上,可以明确使用安装时的解释器启动:
45
+
46
+ ```bash
47
+ python3 -m pycodex
48
+ python3 -m workspace_server --help
39
49
  ```
40
50
 
41
- 先安装开发依赖:
51
+ 如果 `PATH` 中找不到 `pycodex`,或者命中了旧安装,使用以上模块入口即可。
52
+ `python3 -m pip --version` 可确认包安装到了哪个 Python 环境。
53
+
54
+ 从本仓库开发时,先安装依赖:
42
55
 
43
56
  ```bash
44
57
  uv sync
@@ -188,6 +201,16 @@ from pycodex import ResponsesModelClient
188
201
  client = ResponsesModelClient.from_codex_config()
189
202
  ```
190
203
 
204
+ `model_provider` 可省略,默认使用 `openai`。内置 provider 不要求
205
+ `[model_providers.openai]` 表,默认地址为 `https://api.openai.com/v1`,
206
+ 从 `OPENAI_API_KEY` 读取密钥;可用 `openai_base_url` 覆盖地址。
207
+ 显式 provider 表仍使用其配置的 `base_url` 和可选 `env_key`,
208
+ 未知 provider 名称会报明确的配置错误。模型名仍从配置或所选 profile 的
209
+ `model` 字段读取。
210
+
211
+ 当前认证通过环境变量或 `.env` 中的 API key 完成,尚不读取官方 Codex
212
+ 桌面端/CLI 保存在 `auth.json` 或系统钥匙串中的 ChatGPT 登录凭据。
213
+
191
214
  当前实现走 OpenAI-compatible Responses API 的流式 `/responses` 接口。这个点
192
215
  已经用本机 `~/.codex/config.toml` 做过联调验证。
193
216
 
@@ -48,6 +48,29 @@ Tool-specific status uses two inputs:
48
48
  - proxy captures of actual upstream Codex and `pycodex` requests/results
49
49
  - source inspection against the latest upstream tool specifications
50
50
 
51
+ ## Startup and provider defaults (2026-10-10)
52
+
53
+ Provider selection uses `openai` when `model_provider` is omitted, matching
54
+ [`config/mod.rs` at the 0.153.4 source baseline](https://github.com/openai/codex/blob/3d2ee51ca2d5db578f328aa75e20aa22c0197c9a/codex-rs/core/src/config/mod.rs).
55
+ The built-in OpenAI provider needs no user-defined provider table. For pycodex's
56
+ API-key transport, its default address is `https://api.openai.com/v1`, with the
57
+ top-level/profile `openai_base_url` override and `OPENAI_API_KEY` environment
58
+ variable. Custom providers must be selected explicitly; an unknown provider
59
+ raises a descriptive configuration error.
60
+
61
+ Two local boundaries remain: explicit provider tables retain their existing
62
+ pycodex override behavior, and authentication reads environment API keys rather
63
+ than Codex's stored ChatGPT credentials. `model` must still be specified in the
64
+ configuration or selected profile. This change aligns provider selection,
65
+ not the full upstream authentication or model-discovery surface.
66
+
67
+ The package also supports `python3 -m pycodex`, alongside the existing
68
+ `python3 -m workspace_server`, so installation and startup can use the same
69
+ interpreter on hosts with multiple Python installations. Console scripts remain
70
+ owned by `python-codex` and are generated by the installer. The publish workflow
71
+ installs the built wheels into a fresh environment and checks both console and
72
+ module entry points outside the source checkout before uploading artifacts.
73
+
51
74
  ## Context audit (2026-09-23)
52
75
 
53
76
  This audit uses installed `codex-cli 0.153.4` and its matching
@@ -0,0 +1,36 @@
1
+ # 0.3.2 release notes
2
+
3
+ Both `python-codex` and `pycodex-ws` use version **0.3.2**. The workspace
4
+ metapackage depends on exactly `python-codex==0.3.2`; publish the core package
5
+ first.
6
+
7
+ ## Startup fixes
8
+
9
+ - Codex configurations may omit `model_provider`. In that case, use the built-in
10
+ `openai` provider without requiring a `[model_providers.openai]` table.
11
+ Its default API address is `https://api.openai.com/v1`, with
12
+ `openai_base_url` available as an override and `OPENAI_API_KEY` supplying
13
+ authentication. Existing explicit provider tables keep their behavior;
14
+ unknown provider names produce a descriptive configuration error.
15
+ - Add `python3 -m pycodex` so installation and startup can explicitly use the
16
+ same interpreter on hosts with multiple Python installations.
17
+ The browser frontend remains available through
18
+ `python3 -m workspace_server` or the `pycodex-ws` command.
19
+ - Check installed wheel entry points in a fresh environment before publication,
20
+ covering both console scripts and both module entry points outside the source
21
+ checkout. Add provider-selection and module-exit-status regressions.
22
+
23
+ The configuration still needs `model`, either at the top level or in the
24
+ selected profile. Authentication uses environment API keys or `.env`;
25
+ stored ChatGPT sign-in credentials from the official Codex CLI/desktop app
26
+ are not loaded.
27
+
28
+ ## Upgrade
29
+
30
+ ```bash
31
+ python3 -m pip install --upgrade pycodex-ws==0.3.2
32
+ python3 -m pycodex
33
+ python3 -m workspace_server --help
34
+ ```
35
+
36
+ `python3 -m pycodex-ws` is not a module entry point.
@@ -4,10 +4,18 @@
4
4
  [`python-codex`](https://pypi.org/project/python-codex/).
5
5
 
6
6
  ```bash
7
- pip install pycodex-ws
7
+ python3 -m pip install pycodex-ws
8
8
  pycodex-ws --help
9
9
  ```
10
10
 
11
+ Requires Python 3.6.2 or newer. With multiple Python installations, use the
12
+ installing interpreter to launch either frontend directly:
13
+
14
+ ```bash
15
+ python3 -m workspace_server --help
16
+ python3 -m pycodex --help
17
+ ```
18
+
11
19
  This distribution intentionally contains only package metadata. It depends on
12
20
  the exact matching `python-codex` version, which provides the `workspace_server`
13
21
  implementation and the `pycodex-ws` console script.
@@ -4,12 +4,12 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pycodex-ws"
7
- version = "0.3.1"
7
+ version = "0.3.2"
8
8
  description = "Browser workspace install alias for python-codex"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.6.2"
11
11
  dependencies = [
12
- "python-codex==0.3.1",
12
+ "python-codex==0.3.2",
13
13
  ]
14
14
 
15
15
  [tool.hatch.build.targets.wheel]
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ raise SystemExit(main())
@@ -107,8 +107,17 @@ class ResponsesProviderConfig:
107
107
  raise ValueError(f"unknown Codex profile: {profile}")
108
108
  selected.update(overrides)
109
109
 
110
- provider_name = selected["model_provider"]
111
- provider = data["model_providers"][provider_name]
110
+ provider_name = selected.get("model_provider", "openai")
111
+ provider = data.get("model_providers", {}).get(provider_name)
112
+ if provider is None:
113
+ if provider_name != "openai":
114
+ raise ValueError(f"unknown Codex model provider: {provider_name}")
115
+ provider = {
116
+ "base_url": (
117
+ selected.get("openai_base_url") or "https://api.openai.com/v1"
118
+ ),
119
+ "env_key": "OPENAI_API_KEY",
120
+ }
112
121
  wire_api = provider.get("wire_api", "responses")
113
122
  if wire_api != "responses":
114
123
  raise ValueError(f"unsupported wire_api for Python client: {wire_api}")
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "python-codex"
7
- version = "0.3.1"
7
+ version = "0.3.2"
8
8
  description = "A minimal Python extraction of Codex's main agent loop"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.6.2"
@@ -22,9 +22,21 @@
22
22
  - 如果已推送的 tag 在 CI 初始化阶段失败,修复 workflow 后应从包含修复的
23
23
  branch 手动运行 `publish`,并选择正确的 `repository`。直接重跑旧的
24
24
  tag workflow 仍使用旧提交;不要为了 CI 修复强制移动已公开的 tag。
25
+ - `publish.yml` 构建两个 wheel 后,在新 venv 中通过 pip 安装 `pycodex-ws`
26
+ 及同批 `python-codex`,离开源码目录后检查两个 console script 和
27
+ `python -m pycodex` / `python -m workspace_server`,成功后才上传发布产物。
28
+ `test_packaging.py` 另覆盖模块入口的帮助、doctor 分发及参数错误退出码。
25
29
 
26
30
  ## 自动化测试
27
31
 
32
+ ### Provider 配置
33
+
34
+ - `test_model.py` 覆盖省略 `model_provider` / provider 表时默认使用内置
35
+ `openai`、显式选择内置 provider、profile 选择及 `openai_base_url` 覆盖、
36
+ 保留显式 provider 表语义,以及未知 provider 的明确错误。
37
+ - `test_doctor.py` 用本地 Responses fixture 验证省略 provider 的配置可完成
38
+ 配置、API key、连通性和模型请求检查,不访问真实模型服务。
39
+
28
40
  ### VS Code 前端
29
41
 
30
42
  - `extensions/vscode` 使用 Node 22+,运行
@@ -30,9 +30,11 @@ def _write_config(
30
30
 
31
31
 
32
32
  @pytest.mark.asyncio
33
+ @pytest.mark.parametrize("builtin_openai", [False, True])
33
34
  async def test_collect_doctor_report_succeeds_with_live_check(
34
35
  tmp_path,
35
36
  monkeypatch,
37
+ builtin_openai,
36
38
  ) -> "None":
37
39
  capture_store = CaptureStore(tmp_path / "capture")
38
40
  httpd = ThreadingHTTPServer(
@@ -43,8 +45,18 @@ async def test_collect_doctor_report_succeeds_with_live_check(
43
45
  server_thread.start()
44
46
 
45
47
  config_path = tmp_path / "config.toml"
46
- _write_config(config_path, f"http://127.0.0.1:{httpd.server_port}/v1")
47
- monkeypatch.setenv("DOCTOR_KEY", "dummy-key")
48
+ base_url = f"http://127.0.0.1:{httpd.server_port}/v1"
49
+ if builtin_openai:
50
+ config_path.write_text(
51
+ 'model = "gpt-5.4"\n'
52
+ f'openai_base_url = "{base_url}"\n',
53
+ encoding="utf-8",
54
+ )
55
+ env_key = "OPENAI_API_KEY"
56
+ else:
57
+ _write_config(config_path, base_url)
58
+ env_key = "DOCTOR_KEY"
59
+ monkeypatch.setenv(env_key, "dummy-key")
48
60
 
49
61
  try:
50
62
  report = await collect_doctor_report(
@@ -58,8 +70,8 @@ async def test_collect_doctor_report_succeeds_with_live_check(
58
70
  httpd.server_close()
59
71
 
60
72
  assert report.ok is True
61
- assert report.provider_name == "neo"
62
- assert report.api_key_env == "DOCTOR_KEY"
73
+ assert report.provider_name == ("openai" if builtin_openai else "neo")
74
+ assert report.api_key_env == env_key
63
75
  assert report.api_key_loaded is True
64
76
  assert report.live_output_text == "OK"
65
77
  assert {check.name for check in report.checks} == {
@@ -268,6 +268,94 @@ def test_provider_config_reads_codex_style_config_with_profile_override(
268
268
  assert provider.beta_features_header == "guardian_approval"
269
269
 
270
270
 
271
+ @pytest.mark.parametrize("selection", ["", 'model_provider = "openai"\n'])
272
+ def test_provider_config_defaults_to_builtin_openai(
273
+ tmp_path, monkeypatch, selection
274
+ ) -> "None":
275
+ config_path = tmp_path / "config.toml"
276
+ config_path.write_text(
277
+ 'model = "gpt-5.4"\n' + selection,
278
+ encoding="utf-8",
279
+ )
280
+ monkeypatch.setenv("OPENAI_API_KEY", "test-key")
281
+
282
+ provider = ResponsesProviderConfig.from_codex_config(config_path)
283
+ client = ResponsesModelClient(provider)
284
+
285
+ assert provider.model == "gpt-5.4"
286
+ assert provider.provider_name == "openai"
287
+ assert client.responses_url() == "https://api.openai.com/v1/responses"
288
+ assert provider.api_key_env == "OPENAI_API_KEY"
289
+ assert provider.api_key() == "test-key"
290
+
291
+
292
+ def test_provider_config_uses_openai_default_with_unselected_custom_provider(
293
+ tmp_path,
294
+ ) -> "None":
295
+ config_path = tmp_path / "config.toml"
296
+ config_path.write_text(
297
+ 'model = "gpt-5.4"\n'
298
+ "[model_providers.local]\n"
299
+ 'base_url = "http://localhost:8000/v1"\n',
300
+ encoding="utf-8",
301
+ )
302
+
303
+ provider = ResponsesProviderConfig.from_codex_config(config_path)
304
+
305
+ assert provider.provider_name == "openai"
306
+ assert provider.base_url == "https://api.openai.com/v1"
307
+
308
+
309
+ def test_provider_config_profile_selects_builtin_openai(tmp_path) -> "None":
310
+ config_path = tmp_path / "config.toml"
311
+ config_path.write_text(
312
+ 'model = "base-model"\n'
313
+ 'model_provider = "local"\n'
314
+ "[model_providers.local]\n"
315
+ 'base_url = "http://localhost:8000/v1"\n'
316
+ "[profiles.openai]\n"
317
+ 'model = "gpt-5.4"\n'
318
+ 'model_provider = "openai"\n'
319
+ 'openai_base_url = "https://example.invalid/v1"\n',
320
+ encoding="utf-8",
321
+ )
322
+
323
+ provider = ResponsesProviderConfig.from_codex_config(config_path, "openai")
324
+
325
+ assert provider.model == "gpt-5.4"
326
+ assert provider.provider_name == "openai"
327
+ assert provider.base_url == "https://example.invalid/v1"
328
+ assert provider.api_key_env == "OPENAI_API_KEY"
329
+
330
+
331
+ def test_provider_config_preserves_explicit_openai_provider(tmp_path) -> "None":
332
+ config_path = tmp_path / "config.toml"
333
+ config_path.write_text(
334
+ 'model = "local-model"\n'
335
+ 'model_provider = "openai"\n'
336
+ "[model_providers.openai]\n"
337
+ 'base_url = "http://localhost:8000/v1"\n',
338
+ encoding="utf-8",
339
+ )
340
+
341
+ provider = ResponsesProviderConfig.from_codex_config(config_path)
342
+
343
+ assert provider.base_url == "http://localhost:8000/v1"
344
+ assert provider.api_key_env is None
345
+ assert provider.api_key() is None
346
+
347
+
348
+ def test_provider_config_rejects_unknown_provider(tmp_path) -> "None":
349
+ config_path = tmp_path / "config.toml"
350
+ config_path.write_text(
351
+ 'model = "gpt-5.4"\nmodel_provider = "missing"\n',
352
+ encoding="utf-8",
353
+ )
354
+
355
+ with pytest.raises(ValueError, match="unknown Codex model provider: missing"):
356
+ ResponsesProviderConfig.from_codex_config(config_path)
357
+
358
+
271
359
  def test_build_payload_omits_tool_choice_when_no_tools() -> "None":
272
360
  client = ResponsesModelClient(
273
361
  ResponsesProviderConfig(
@@ -1,3 +1,6 @@
1
+ import os
2
+ import subprocess
3
+ import sys
1
4
  from pathlib import Path
2
5
 
3
6
  import pytest
@@ -30,6 +33,31 @@ def test_workspace_distribution_tracks_core_version() -> "None":
30
33
  assert core["project"]["scripts"]["pycodex-ws"] == "workspace_server:main"
31
34
 
32
35
 
36
+ @pytest.mark.parametrize(
37
+ ("arguments", "exit_code", "output"),
38
+ [
39
+ (["--help"], 0, "usage: pycodex "),
40
+ (["doctor", "--help"], 0, "usage: pycodex doctor "),
41
+ (["--unknown-option"], 2, "unrecognized arguments: --unknown-option"),
42
+ ],
43
+ )
44
+ def test_python_module_entrypoint(tmp_path, arguments, exit_code, output):
45
+ environment = dict(os.environ)
46
+ environment["PYTHONPATH"] = str(ROOT)
47
+ result = subprocess.run(
48
+ [sys.executable, "-m", "pycodex"] + arguments,
49
+ cwd=str(tmp_path),
50
+ env=environment,
51
+ stdout=subprocess.PIPE,
52
+ stderr=subprocess.PIPE,
53
+ universal_newlines=True,
54
+ timeout=15,
55
+ )
56
+
57
+ assert result.returncode == exit_code, result.stderr
58
+ assert output in result.stdout + result.stderr
59
+
60
+
33
61
  @pytest.mark.parametrize("filename", ["test.yml", "publish.yml"])
34
62
  def test_python36_workflows_install_yaml_dependency(filename):
35
63
  path = ROOT / ".github" / "workflows" / filename
File without changes
File without changes
File without changes