python-codex 0.3.3__py3-none-any.whl → 0.4.1__py3-none-any.whl

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 (61) hide show
  1. pycodex/__init__.py +3 -27
  2. pycodex/bootstrap.py +5 -45
  3. pycodex/cli.py +1 -14
  4. pycodex/context.py +1 -1
  5. pycodex/events.py +1 -1
  6. pycodex/model.py +2 -2
  7. pycodex/portable/__init__.py +45 -0
  8. pycodex/{portable.py → portable/client.py} +4 -7
  9. pycodex/{portable_server.py → portable/server.py} +3 -3
  10. pycodex/protocol.py +1 -1
  11. pycodex/runtime.py +2 -2
  12. pycodex/tools/base_tool.py +1 -1
  13. pycodex/tools/close_agent_tool.py +1 -1
  14. pycodex/tools/code_mode_manager.py +1 -1
  15. pycodex/tools/request_permissions_tool.py +1 -1
  16. pycodex/tools/resume_agent_tool.py +1 -1
  17. pycodex/{runtime_services.py → tools/runtime_services.py} +5 -5
  18. pycodex/tools/send_input_tool.py +1 -1
  19. pycodex/tools/spawn_agent_tool.py +1 -1
  20. pycodex/tools/unified_exec_manager.py +1 -1
  21. pycodex/tools/update_plan_tool.py +1 -1
  22. pycodex/tools/view_image_tool.py +5 -0
  23. pycodex/tools/wait_agent_tool.py +1 -1
  24. pycodex/utils/__init__.py +0 -4
  25. pycodex/utils/_aes_gcm/LICENSE +56 -0
  26. pycodex/utils/_aes_gcm/README.md +61 -0
  27. pycodex/utils/_aes_gcm/__init__.py +1 -0
  28. pycodex/utils/_aes_gcm/aes.py +175 -0
  29. pycodex/utils/_aes_gcm/gcm.py +73 -0
  30. pycodex/utils/_aes_gcm/source-sha256.json +4 -0
  31. pycodex/utils/async_bridge.py +3 -4
  32. pycodex/{compat.py → utils/compat.py} +2 -0
  33. pycodex/utils/crypto.py +35 -0
  34. pycodex/utils/debug.py +24 -0
  35. pycodex/{doctor.py → utils/doctor.py} +3 -3
  36. pycodex/utils/image_utils.py +3 -2
  37. pycodex/{model_metadata.py → utils/model_metadata.py} +2 -2
  38. pycodex/utils/session_persist.py +28 -0
  39. {python_codex-0.3.3.dist-info → python_codex-0.4.1.dist-info}/METADATA +124 -42
  40. python_codex-0.4.1.dist-info/RECORD +90 -0
  41. {python_codex-0.3.3.dist-info → python_codex-0.4.1.dist-info}/entry_points.txt +0 -1
  42. responses_server/app.py +28 -15
  43. pycodex/feishu_card.py +0 -793
  44. pycodex/feishu_link.py +0 -440
  45. pycodex/tools/ipython_tool.py +0 -142
  46. python_codex-0.3.3.dist-info/RECORD +0 -98
  47. workspace_server/__init__.py +0 -39
  48. workspace_server/__main__.py +0 -4
  49. workspace_server/app.py +0 -1906
  50. workspace_server/content_views.LICENSE.txt +0 -470
  51. workspace_server/content_views.css +0 -1
  52. workspace_server/content_views.mjs +0 -25
  53. workspace_server/editor.css +0 -1
  54. workspace_server/editor.mjs +0 -1260
  55. workspace_server/owned_process.py +0 -27
  56. workspace_server/workspace.html +0 -2267
  57. workspace_server/workspace_views.py +0 -533
  58. workspace_server/workspaces.html +0 -550
  59. workspace_server/workspaces.py +0 -632
  60. {python_codex-0.3.3.dist-info → python_codex-0.4.1.dist-info}/WHEEL +0 -0
  61. {python_codex-0.3.3.dist-info → python_codex-0.4.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,20 +1,17 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-codex
3
- Version: 0.3.3
3
+ Version: 0.4.1
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
7
7
  Requires-Dist: dataclasses>=0.8; python_version < '3.7'
8
- Requires-Dist: fastapi<0.84,>=0.83.0; python_version < '3.7'
9
- Requires-Dist: fastapi>=0.83.0; python_version >= '3.7'
10
8
  Requires-Dist: importlib-metadata>=4.8.3; python_version < '3.8'
11
9
  Requires-Dist: loguru>=0.7.3
12
- Requires-Dist: pillow>=8.4.0; python_version < '3.7'
13
- Requires-Dist: pillow>=9.0.0; python_version >= '3.7'
14
10
  Requires-Dist: prompt-toolkit>=3.0.36
15
- Requires-Dist: pycryptodomex>=3.20
16
11
  Requires-Dist: pyyaml>=6.0
17
12
  Requires-Dist: requests>=2.27.1
13
+ Requires-Dist: starlette<0.20,>=0.19.1; python_version < '3.7'
14
+ Requires-Dist: starlette>=0.19.1; python_version >= '3.7'
18
15
  Requires-Dist: tomli<2,>=1.2.3; python_version < '3.11'
19
16
  Requires-Dist: typing-extensions>=4.1.1; python_version < '3.8'
20
17
  Requires-Dist: uvicorn<0.17,>=0.16.0; python_version < '3.7'
@@ -25,6 +22,8 @@ Description-Content-Type: text/markdown
25
22
 
26
23
  English README. Chinese version: `README_ZH.md`
27
24
 
25
+ 0.4.0 core/workspace package split and dependency cleanup: [release notes](docs/RELEASE_0.4.0.md).
26
+
28
27
  0.3.3 workspace viewers and reasoning stream fix: [release notes](docs/RELEASE_0.3.3.md).
29
28
 
30
29
  0.3.2 startup fixes: [release notes](docs/RELEASE_0.3.2.md).
@@ -33,15 +32,37 @@ English README. Chinese version: `README_ZH.md`
33
32
 
34
33
  PyPI distributions:
35
34
 
36
- - Primary package: `python-codex`
37
- - Workspace install alias: `pycodex-ws`
35
+ - Core package: `python-codex`
36
+ - Workspace and integrations: `pycodex-ws`
38
37
 
39
38
  The import path remains `pycodex`; the CLI commands are `pycodex` and
40
39
  `pycodex-ws`.
41
40
 
42
- `pycodex-ws` is a thin metapackage that depends on the exact matching
43
- `python-codex` version. The implementation and console script remain owned by
44
- `python-codex`, so the two distributions never install duplicate modules.
41
+ `python-codex` contains the Agent, runtime, CLI, standard tools, Responses
42
+ compatibility server and portable storage support. `pycodex-ws` depends on the
43
+ exact matching core version and contains the browser workspace, viewer assets
44
+ and optional Feishu integration. It owns the
45
+ `workspace_server` and `pycodex_ws` modules and the `pycodex-ws` command.
46
+
47
+ The Feishu SDK is not installed automatically. Install it in the workspace's
48
+ Python environment with `python3 -m pip install lark-oapi` to enable `/link`.
49
+ If `lark_oapi` cannot be imported, `/link` reports that it is unavailable.
50
+
51
+ Core does not require Pillow. Without it, `view_image` sends the original image
52
+ bytes with `detail="original"`, including when `high` is requested. With Pillow
53
+ installed, the default path retains resizing to a maximum dimension of 2048.
54
+ `pycodex-ws` installs Pillow for image preview validation.
55
+
56
+ Portable encryption uses a bundled pure Python AES-GCM subset of pyaes and
57
+ tlslite-ng, under MIT and BSD licenses. Core does not require a crypto package
58
+ or compiler and ships a `py3-none-any` wheel. Existing `PCX1` bundles and call
59
+ tokens remain compatible; large bundles take longer to encrypt and decrypt.
60
+ See the [source notes](pycodex/utils/_aes_gcm/README.md).
61
+
62
+ The Responses compatibility server and workspace HTTP server use Starlette
63
+ and Uvicorn directly. Neither package requires FastAPI, Pydantic or
64
+ `pydantic-core`. Python 3.6 uses Starlette 0.19.x; newer interpreters resolve
65
+ a compatible Starlette release through its Python version metadata.
45
66
 
46
67
  This repository extracts the core Codex agent loop from upstream Codex
47
68
  (`https://github.com/openai/codex`) into a deliberately small Python version,
@@ -61,16 +82,17 @@ Relevant Rust reference points:
61
82
 
62
83
  ## Quick Start
63
84
 
64
- Install the full package or the workspace-oriented alias:
85
+ Install the core CLI, or install the workspace package for the browser frontend:
65
86
 
66
87
  ```bash
67
88
  python3 -m pip install python-codex
68
89
  python3 -m pip install pycodex-ws
69
90
  ```
70
91
 
71
- Use Python 3.6.2 or newer. Both console commands are installed into that
72
- interpreter's scripts directory. On a machine with multiple Python installations,
73
- you can select the same interpreter explicitly for startup:
92
+ The core supports Python 3.6.2 or newer. The workspace package requires Python
93
+ 3.7 or newer. Commands are installed into
94
+ that interpreter's scripts directory. On a machine with multiple Python
95
+ installations, select the same interpreter explicitly for startup:
74
96
 
75
97
  ```bash
76
98
  python3 -m pycodex
@@ -81,10 +103,14 @@ If `pycodex` is missing from `PATH` or resolves to an older installation, use th
81
103
  module entry points. `python3 -m pip --version` shows which Python environment
82
104
  received the installation.
83
105
 
106
+ For an existing Web installation, use `python3 -m pip install --upgrade pycodex-ws`
107
+ to upgrade the workspace and its matching core together. Installing only
108
+ `python-codex` provides the CLI and core API.
109
+
84
110
  For development from this repository, install dependencies first:
85
111
 
86
112
  ```bash
87
- uv sync
113
+ uv sync --dev
88
114
  ```
89
115
 
90
116
  Try the real entry points:
@@ -94,8 +120,22 @@ uv run pycodex "Reply with exactly OK."
94
120
  uv run pycodex
95
121
  ```
96
122
 
97
- A VS Code frontend is available in [`extensions/vscode`](extensions/vscode/README.md).
98
- It reuses an existing `python-codex>=0.3.1` installation. On first use, missing
123
+ Tests are split by package. `uv run --dev pytest` runs both suites;
124
+ `uv run --dev pytest packages/pycodex-ws/tests` runs workspace and integration
125
+ tests. To check core without installing workspace, use a separate
126
+ environment:
127
+
128
+ ```bash
129
+ UV_PROJECT_ENVIRONMENT=.tmp/core-tests uv sync --group test
130
+ UV_PROJECT_ENVIRONMENT=.tmp/core-tests uv run --group test pytest tests
131
+ ```
132
+
133
+ See [test environments and coverage](tests/TESTS.md). Core tests support Python
134
+ 3.6.2+; workspace tests require Python 3.7+.
135
+
136
+ A VS Code frontend is available in [`packages/pycodex-ws/extensions/vscode`](packages/pycodex-ws/extensions/vscode/README.md).
137
+ It belongs to the workspace frontend and is packaged separately as a VSIX.
138
+ It reuses an existing `pycodex-ws>=0.4.0` installation. On first use, missing
99
139
  or older backends are installed/upgraded with pip in the selected Python
100
140
  environment on the workspace host; compatible versions need no network check.
101
141
  It starts a dedicated `pycodex-ws` workspace on the project's host and opens a
@@ -143,19 +183,35 @@ nailing the core tool-augmented reasoning loop first.
143
183
 
144
184
  ## Layout
145
185
 
186
+ The top level of `pycodex/` contains the core components and package entry points.
187
+ Supporting services live in `tools/`, `portable/` and `utils/`.
188
+
189
+ - `pycodex/agent.py`: inner turn loop
190
+ - `pycodex/runtime.py`: session commands, submission queues and frontend event subscriptions
191
+ - `pycodex/model.py`: model client protocol and Responses API adapter
192
+ - `pycodex/context.py`: configuration, prompt assembly and instruction loading
146
193
  - `pycodex/protocol.py`: minimal conversation item / prompt protocol
147
194
  - `pycodex/events.py`: typed events, plain-text views and stateful presentation
148
- - `pycodex/utils/event_helpers.py`: stateless text, color, summary and result-formatting helpers
149
- - `pycodex/utils/image_utils.py`: image loading, resizing and data-URL preparation
150
- - `pycodex/model.py`: model client protocol and Responses API adapter
151
- - `pycodex/cli.py`: single-turn/interactive entry points, terminal I/O executor and input loop
152
195
  - `pycodex/bootstrap.py`: frontend-independent model, tools, Agent and session assembly
196
+ - `pycodex/cli.py`: single-turn/interactive entry points, terminal I/O executor and input loop
153
197
  - `pycodex/tools/base_tool.py`: `BaseTool`, `ToolRegistry`, `ToolContext`
154
- - `pycodex/tools/`: concrete tool implementations
155
- - `pycodex/agent.py`: inner turn loop
156
- - `pycodex/runtime.py`: session commands, submission queues and frontend event subscriptions
157
- - `extensions/vscode/`: VS Code chat frontend using the workspace HTTP API
158
- - `tests/test_agent.py`: core behavior tests
198
+ - `pycodex/tools/runtime_services.py`: plan, sub-agent, user-input and permissions services
199
+ - `pycodex/tools/`: concrete tools and their execution managers
200
+ - `pycodex/portable/`: Codex home storage client and server, both included in core
201
+ - `pycodex/utils/compat.py`: supported-Python compatibility helpers
202
+ - `pycodex/utils/doctor.py`: configuration and connectivity diagnostics
203
+ - `pycodex/utils/model_metadata.py`: vendored model metadata lookup
204
+ - `pycodex/utils/debug.py`: debug paths and the `pycodex.debug()` implementation
205
+ - `pycodex/utils/event_helpers.py`: stateless text, color, summary and result-formatting helpers
206
+ - `pycodex/utils/image_utils.py`: image loading, resizing and data-URL preparation
207
+ - `pycodex/prompts/`: vendored prompts and model metadata
208
+ - `packages/pycodex-ws/workspace_server/`: Web board, API and file/diff viewers
209
+ - `packages/pycodex-ws/pycodex_ws/`: Feishu and workspace assembly
210
+ - `packages/pycodex-ws/extensions/vscode/`: workspace's VS Code frontend, built separately as a VSIX
211
+ - `tests/`: core tests
212
+ - `packages/pycodex-ws/tests/`: workspace and cross-frontend integration tests
213
+
214
+ See [package layout and import paths](docs/RUNTIME.md#package-layout).
159
215
 
160
216
  ## Current Alignment Status
161
217
 
@@ -266,7 +322,7 @@ Current behavior:
266
322
  - with an argv prompt or piped stdin, run a single turn
267
323
  - `pycodex-ws` starts the standalone browser workspace manager and serves each
268
324
  workspace with a board pane and a pycodex session pane
269
- - the left pane is the board, containing a live HTML Canvas tab and closable read-only file/diff tabs that
325
+ - the left pane is the board, containing an optional live HTML Canvas tab and closable read-only file/diff tabs that
270
326
  scroll together in one toolbar; a mouse wheel scrolls overflowing tab strips
271
327
  horizontally.
272
328
  Click Markdown file links such as `[source](src/app.py:42)` or
@@ -285,6 +341,14 @@ Current behavior:
285
341
  hover titles retain the complete paths and revisions. Text,
286
342
  Markdown, HTML, common raster images and text diffs are supported. Monaco
287
343
  provides syntax highlighting, find, folding and character-level diffs.
344
+ Right-click code and choose **Insert into chat**, or select text and use the
345
+ toolbar button, to insert context at the current chat draft's cursor.
346
+ Context appears as a separate block among your words. Click it to edit or
347
+ remove it; Backspace and Delete also remove a block as one element.
348
+ Context identifies the full view label, including both revisions of a diff.
349
+ Selections include only the selected text and range; otherwise it records the
350
+ cursor location. Diff context also identifies the selected side.
351
+ The draft stays editable until you send it.
288
352
  Its code and styles load only when a code or diff view opens, so Canvas,
289
353
  Markdown and HTML previews do not load the editor. Viewer assets use gzip
290
354
  when supported and revalidate cached content with ETags.
@@ -353,28 +417,38 @@ Current behavior:
353
417
  non-persisted follow-up session and submits the file contents as the next
354
418
  user instruction; this is intended for side-effect follow-ups such as
355
419
  Feishu notifications
356
- - `/link <feishu-email|open_id|chat_id>` attaches the current interactive
357
- session to a Feishu card; multiple sessions in the same pycodex process share
420
+ - `/link <feishu-email|open_id|chat_id>` in a workspace session attaches it
421
+ to a Feishu card when the optional `lark-oapi` SDK can be imported;
422
+ multiple sessions in the same workspace process share
358
423
  one Feishu long-connection listener and route card actions by message id
359
424
  - Feishu user OAuth stores its refresh token only in
360
425
  `~/.codex/.feishu_refresh_token` (mode `0600`). Run
361
- `env -u VIRTUAL_ENV uv run python tools/feishu_oauth.py` from this repository
362
- to authorize; app credentials can stay in `~/.codex/.env`. Each refresh reads
426
+ `python3 -m pycodex_ws.feishu_oauth` after installing `pycodex-ws` to authorize.
427
+ From this repository, use `env -u VIRTUAL_ENV uv run --dev python -m pycodex_ws.feishu_oauth`.
428
+ App credentials can stay in `~/.codex/.env`. Each refresh reads
363
429
  the latest token from the dedicated file and saves its replacement there.
364
430
  `FEISHU_REFRESH_TOKEN` in `.env` or the environment is no longer used and
365
431
  can be removed. Refresh is triggered by API calls, with no idle keepalive.
366
432
  - `pycodex-ws --workspace-config workspaces.json` serves workspace boards from
367
433
  one process. The JSON file can be either a list or
368
- `{"workspaces": [...]}`; each entry uses `board` and `work_dir`, with optional
369
- display/URL `id`, and is exposed at `/w/<id>/`. Internally the resolved
370
- `board` path is the workspace identity, so adding the same board path twice is
371
- rejected even with a different name. Relative `board` and `work_dir` paths
434
+ `{"workspaces": [...]}`; each entry uses `state_path` and `work_dir`, with optional
435
+ display/URL `id` and `enable_board` (default `true`), and is exposed at `/w/<id>/`.
436
+ `state_path` is a filename prefix: `/data/demo` uses
437
+ `/data/demo.pycodex-ws.json` for the session index,
438
+ `/data/demo.pycodex-views.json` for file views and `/data/demo.html` for Canvas.
439
+ Suffixes are appended, so prefixes containing dots remain distinct.
440
+ The resolved `state_path` is the workspace identity; duplicates are rejected
441
+ regardless of name or Canvas setting. Relative `state_path` and `work_dir` paths
372
442
  resolve from the config file directory. The root path `/` shows a workspaces
373
- management page with `add_workspace(name=None, dir="./", board=None)` and
374
- `delete(name)` controls; omitted names become `workspace-1`, `workspace-2`,
375
- etc. If `board` is omitted when adding a workspace, pycodex assigns a random
376
- writable `/tmp/pcws-*.html` board path. Add/delete actions and later
377
- session-state saves refresh the JSON file. Board HTML can reference local
443
+ management page with create/delete controls; omitted names become `workspace-1`,
444
+ `workspace-2`, etc. Omitted `state_path` when creating a workspace generates a
445
+ writable `/tmp/pcws-*` prefix. `enable_board: false` hides Canvas and disables its
446
+ routes, polling and context injection; sessions and file views still persist.
447
+ Existing `board: "demo.html"` and `board: false` configurations load with their
448
+ original state paths and are saved in the new format. See the
449
+ [workspace configuration example](packages/pycodex-ws/README.md).
450
+ Add/delete actions and later session-state saves refresh the JSON file.
451
+ Board HTML can reference local
378
452
  images beside the board (including nested paths) with relative URLs; only
379
453
  `image/*` files contained by the board directory are served.
380
454
  Assistant Markdown supports KaTeX formulas with `$...$`, `$$...$$`,
@@ -466,6 +540,13 @@ pycodex doctor --json
466
540
  `Portable Mode` is the quickest way to bring your usual `pycodex` setup into a
467
541
  fresh machine, container, or debug image.
468
542
 
543
+ The storage client and server are both included in `python-codex`. To start a
544
+ local storage service, run this in a separate terminal:
545
+
546
+ ```bash
547
+ python -m pycodex.portable.server --root .tmp/pycodex_storage --host 127.0.0.1 --port 5577
548
+ ```
549
+
469
550
  Use it like this:
470
551
 
471
552
  ```bash
@@ -659,7 +740,8 @@ CLI, Web and Feishu all use `AgentRuntime.submit_input`: not just `/model`
659
740
  and `/resume`, but every session command, steer/queue admission, interactive
660
741
  questions and permissions, state notifications and shutdown. Frontends only
661
742
  adapt input and render events. Web no longer imports or runs the CLI shell.
662
- IPython is the deliberate exception: `ipython_agent()` still returns a bare Agent.
743
+ Workspace assembly uses `pycodex_ws.build_runtime()` to add
744
+ `/link` and `/unlink`; `pycodex.bootstrap.build_runtime()` provides core commands.
663
745
 
664
746
  ```python
665
747
  from pycodex.bootstrap import build_agent, build_model, build_runtime
@@ -0,0 +1,90 @@
1
+ pycodex/__init__.py,sha256=fHEyhylULeRo-5xEnl-UxT5ZpBzbFzRW7vLwdy_7oxU,2660
2
+ pycodex/__main__.py,sha256=MHKZ_ae3fSLGTLUUMOx15fWdeOnJSHhq-zslRP5F5Lc,79
3
+ pycodex/agent.py,sha256=zCIG2DV0oQntLXHFj8FVRkgBp5TCC0YJ7sz0lni9J1s,21177
4
+ pycodex/bootstrap.py,sha256=U1X5kwORpS5JnPk9HhIiOVWPQzDLlk_ro_cY2knwL8I,12421
5
+ pycodex/cli.py,sha256=MLvXpVwrb-HJuVWmPFmNMTR-4cqR3X08ZfAevYlVSQI,12646
6
+ pycodex/context.py,sha256=yfNY2alT3caQQwhay47pSSrGUbgEAcLKhTVaZqtQ4yU,26610
7
+ pycodex/events.py,sha256=wysYXHLiCHzW3k1yaAuoRTw90NRhHPa3jtY0ANGOqH4,29694
8
+ pycodex/model.py,sha256=3mWXTN-oV2Q50SgQYac45WT5Qk2NSmPTxSWyF-w8TRg,44583
9
+ pycodex/protocol.py,sha256=uzUz_06iA4m9vAoqZeCGiJ4SocKZDzOfCJUU4Bpt5dI,12033
10
+ pycodex/runtime.py,sha256=3wHKoNjwzOgE6dXeT6Vbpu6Nf7RWqIfHwrjsmOnk81I,23814
11
+ pycodex/portable/__init__.py,sha256=FmspRPmblYuZIVXMpXaxE1uosCaz2hZDpkpOzxDJQic,1084
12
+ pycodex/portable/client.py,sha256=DOxzZljVfN1ynmhqrChX7NsT1IFSFVKzEn1J3wvV3XQ,16038
13
+ pycodex/portable/server.py,sha256=w4YD71Sxb7MD5q57GPuIgx7AoicTv0R9xzX2kAaibPA,7503
14
+ pycodex/prompts/default_base_instructions.md,sha256=D65mcj6bo4CDvVom-D9cbJRJVNquo0NghKt164_fRsg,20923
15
+ pycodex/prompts/models.json,sha256=u-bS5xtI7ZHbrG_nbzrt-xmp5RtQT6YL8PHbd_4XZB4,397650
16
+ pycodex/prompts/permissions/approval_policy/never.md,sha256=QceTG6wjkaJARjYr0HYV1aPnPcpGcrkRUW-smWRr6MQ,120
17
+ pycodex/prompts/permissions/approval_policy/on_failure.md,sha256=dfJjpXkpO6_ANdCKxbVJ8o4vyLxevrJWfKsGHTqtbkc,289
18
+ pycodex/prompts/permissions/approval_policy/on_request.md,sha256=hVQalzh0FAdkKzw5u-N4H7-LtC9ijVDlYsh3OKsZKzo,3661
19
+ pycodex/prompts/permissions/approval_policy/on_request_rule_request_permission.md,sha256=mOinishp1k-wlPsaEuIOMn5GoVm_dAIsWIuEMmv2r7o,1725
20
+ pycodex/prompts/permissions/approval_policy/unless_trusted.md,sha256=XHpi1Lfx1iIXFbbQ_ho_kGstA3JN-RLho291HM30UNw,247
21
+ pycodex/prompts/permissions/sandbox_mode/danger_full_access.md,sha256=nZ7YHacBd3cAHKRZc9XClOOOnXJPXPh0WFBueh5C2D0,197
22
+ pycodex/prompts/permissions/sandbox_mode/read_only.md,sha256=2rAPEXsBYCcuttI5j3euS-3uv_v97catIsnhxlSQSIM,173
23
+ pycodex/prompts/permissions/sandbox_mode/workspace_write.md,sha256=lVN-LwrBbHqlv5yVjcd_mU8tzZW8jfKpTatJKIZu9HI,277
24
+ pycodex/tools/__init__.py,sha256=UYwmsX_Ckw_YaYQ6TYhUU6w5pxi2qzZoTrq6BAgNErM,1857
25
+ pycodex/tools/agent_tool_schemas.py,sha256=8cL9ml4So0H6IIeK0ZzjAo9bk3VeprDOSYPpIamOqEU,2048
26
+ pycodex/tools/apply_patch_tool.py,sha256=t8XFCGZ7q-s9C1Ty6qkReBRk-QD3ONvcKXLAz9djKRY,13956
27
+ pycodex/tools/base_tool.py,sha256=Oqe-0RgH3mz70YckgBFD-tdvNJ9TQXrb0tuMbdy3bfc,6477
28
+ pycodex/tools/clock_tool.py,sha256=2_RYbBEw4V9_f1L-qZl3hhJ6XNPM_gBDmOlCh1cCAjo,6575
29
+ pycodex/tools/close_agent_tool.py,sha256=uIbCjsQx9MLkjVYheS8ZVf5VVPbC6Iviwox4pneJpmI,2030
30
+ pycodex/tools/code_mode_manager.py,sha256=HUgtXxj3hGj2i4_tsToHLr8mGTV8uIob9vtYAZeLnQc,19166
31
+ pycodex/tools/exec_command_tool.py,sha256=iqRiKaaX-AjG6LjATAMOakHIP0gpCWCj2o8af_8eAiQ,4464
32
+ pycodex/tools/exec_runtime.js,sha256=DR1uocKailTqNWAcJNFJuQgFFMSUzTpT_uQsRaneg2s,3643
33
+ pycodex/tools/exec_tool.py,sha256=tuC21rlhP8CPSYml4XnSDSRV0UPGkQ6aHj0DLIoOOvM,2274
34
+ pycodex/tools/grep_files_tool.py,sha256=Ysw68VKI9OEvUH5haYx8FWuthkHykc1wskbuzjj8gTk,5293
35
+ pycodex/tools/list_dir_tool.py,sha256=_U6ouRcVbGHT5mChVyUsiMgDGrFK7EFMFaspPLAHtH8,5337
36
+ pycodex/tools/read_file_tool.py,sha256=YK__uhIVldBjAQega5S_ZuZU5jgP_kLOwr-YhjAmRo4,9735
37
+ pycodex/tools/request_permissions_tool.py,sha256=nEt3_uw3lmFXyydqcN3PxuKwrEvaRPtfjA_U8nikCtU,3978
38
+ pycodex/tools/request_user_input_tool.py,sha256=_7siHF2p3KiNDFwsTqKKIUw2kPCXMzLaR12PkZ1wdIQ,4050
39
+ pycodex/tools/resume_agent_tool.py,sha256=bZvXEUNdc1RVD2N5Msjv63Rni62FQk4gj9LAXK1Vsy8,1613
40
+ pycodex/tools/runtime_services.py,sha256=vZHIHGAeTA-DoEoHulAKvjcfHLXkuK1t3T0Mob9VJ8A,15044
41
+ pycodex/tools/send_input_tool.py,sha256=w63SKM05_e3oXvdaBtL-hk941TvkWKuTUDEqTSyWEMQ,3761
42
+ pycodex/tools/shell_command_tool.py,sha256=US63I5xiV5zfO1Oox2yHUg7F6XoKzmyxtohfaQIsmrw,4216
43
+ pycodex/tools/shell_tool.py,sha256=lqFH2XosfBg7yQKhpB7i4vLGz9sNQtEZihD0rjsmBCQ,4068
44
+ pycodex/tools/spawn_agent_tool.py,sha256=Jx5jYpxsH_CQ3BLkXYPZuIINW5deO_zY8tyw8kZpreY,6208
45
+ pycodex/tools/unified_exec_manager.py,sha256=XPN6PgBnjZ5WFZATNIqpWKUAuw8HMMD7mlfHJQjJQZM,14544
46
+ pycodex/tools/update_plan_tool.py,sha256=xwrSrerw5qfkbFc9Ltx1OZEmD__CWtryOy3UhL0-Jp4,3198
47
+ pycodex/tools/view_image_tool.py,sha256=SCoiIHaQ51oYjYX69MRxjAK9b1P6_wOCIuZqzsC2rj8,4082
48
+ pycodex/tools/wait_agent_tool.py,sha256=9Os6RzzCxIU5KJI5l6MzdwO6QKLNxLFwFXGeDMfYlP4,3828
49
+ pycodex/tools/wait_tool.py,sha256=0_OO_DvMsBhG3oDKZePTOjZTBq1lmWntXAzqIqvebdA,3206
50
+ pycodex/tools/web_search_tool.py,sha256=3ao1IvJw7MwcP35UKLbqrM-nlm5Z-UUFVdEzkJYOV1o,988
51
+ pycodex/tools/write_stdin_tool.py,sha256=jvBDchLLmoDITd7g-ZVeEVXHRhWKkmnjM5laL-53FOM,3609
52
+ pycodex/utils/__init__.py,sha256=ih_KyZ2_bajR5YlZ1QMTWOHnuEBda-S3gQ7PwnBtLZQ,453
53
+ pycodex/utils/async_bridge.py,sha256=BXsKTUTUvUtPJnItQlulFRdV7opdKKDlsKLdtVTYshs,1732
54
+ pycodex/utils/compactor.py,sha256=0tlszw1n54aMEGH6sL1U1dEgFSU5ioYL2NI5uSvHSiM,6119
55
+ pycodex/utils/compat.py,sha256=QxcI4AQuUD-gE2494qPGezgm0OIX98qSHdAiof1JrlU,3550
56
+ pycodex/utils/crypto.py,sha256=HRCXF26Ft3S8CG2X0YpZwa8GMU9YJ0Loo8Q9PMPMcNw,1249
57
+ pycodex/utils/debug.py,sha256=5XMpWpwFSm6woyx6RGXvN2qL0afRtTQbwlOAv-LotTw,913
58
+ pycodex/utils/doctor.py,sha256=fI66oQqB5zNL7aEpFbiHnzhELyp9XydwMyAGznw5YSE,10616
59
+ pycodex/utils/dotenv.py,sha256=h7ZgvqpEswetqjhtwfiaHyokAHwNKPakizTAHPHz5Ds,1865
60
+ pycodex/utils/event_helpers.py,sha256=pnxL0-nBC7cnOheHPCIfkHqJjMbkJg3C348_EzAVhFA,6342
61
+ pycodex/utils/get_env.py,sha256=L4S8h84tkgxZKvrxY7ezTgePbXepG-yIigUTKeY6uuE,6094
62
+ pycodex/utils/image_utils.py,sha256=OUzUs0Cow4L8Z2np0EBeEUotAqqsCmRmhrV8AxZUXRw,2460
63
+ pycodex/utils/model_metadata.py,sha256=uK3iI4yC7Ge7yN4I1_gQYalQ4MYKddz2qMwsmQb-P80,1337
64
+ pycodex/utils/random_ids.py,sha256=jLTxZZ0MBbRdQOFDFWGVRjWzIo6FKSQ5ADXbQSLPp1s,379
65
+ pycodex/utils/session_persist.py,sha256=_7Lz1jO7D0Qf16UVuZBKU_Si-k_cUVinnLMlsd1jVj4,23600
66
+ pycodex/utils/truncation.py,sha256=5D6vAorT8EgXgjd7ASwtraAyIZdlCR-w5jKZqJxDzho,5446
67
+ pycodex/utils/_aes_gcm/LICENSE,sha256=KvdHagY3sYIK34GldJaRi34sNnGwMVJIIoDhbC9MRu8,2805
68
+ pycodex/utils/_aes_gcm/README.md,sha256=D9XGeewCgU2PVqJCO6WusUs0Mw2FbMnABCqaVktqCnE,3045
69
+ pycodex/utils/_aes_gcm/__init__.py,sha256=p0U1CVy6dQBDAfGvSYG0opn6iP2VGF5rqUUM-mNLJxU,70
70
+ pycodex/utils/_aes_gcm/aes.py,sha256=12p_5O7gX-e-LQ08nNe2CBdP_H4eX3J84LlXaVr9i8A,9269
71
+ pycodex/utils/_aes_gcm/gcm.py,sha256=Z8fYHpnLpqJyTPmjDOZtryqe0xmT_93vscNuJe5ZY-w,2762
72
+ pycodex/utils/_aes_gcm/source-sha256.json,sha256=g9uPWXuA0D9Wq9EGnduyiVanTgi8QWRFW-9T69FG-fc,215
73
+ responses_server/__init__.py,sha256=sx9C88YWqmehASZy24FUMqT14A36doM_rj0MIZtQ9iQ,377
74
+ responses_server/__main__.py,sha256=876xZTqhPeDBD2GKKr8pKX33Af8PhFTosAI8bYQsFgQ,61
75
+ responses_server/app.py,sha256=PE-jWn_hmL5os1xsVL81KwU0kDZHOkZoVdSOK-7x3xQ,8400
76
+ responses_server/config.py,sha256=sCJYGisPHW9Uup26-R9Zv0o9W_kRVt-ETc2MFCVjG90,2795
77
+ responses_server/messages_api.py,sha256=ialAYTMmN0y-uxQB3Y51ukq-kvkSVO84WVLXaqLsKw0,18775
78
+ responses_server/payload_processors.py,sha256=dqPwqHD-FhyiIwjzFEMf2wCtQDxkRyerZzbdqnH1aDE,3561
79
+ responses_server/server.py,sha256=k4DbsOYkaHHcy38uF9u_QXahJC1cplKsTu-MdC3DCIs,2286
80
+ responses_server/session_store.py,sha256=nwGxQL6nUVKnDVeDHz8IzqNQ7dWk8Ybf0URekOHdxTo,1133
81
+ responses_server/stream_router.py,sha256=TQX2-8uOGad3TBJnRu9SOtDaHBHjYwE-WERYz6rcuo8,46274
82
+ responses_server/trajectory_dump.py,sha256=5_Wy6tslszrqx3j1JeP_boyTbzIicKy8No84PzMnmHk,5111
83
+ responses_server/tools/__init__.py,sha256=ivsBSEy0SBUhY-Uea5v1XMLXShkwHdCVl0id-1FwdZg,150
84
+ responses_server/tools/custom_adapter.py,sha256=SnIiNUdomff3APtTriURAC9YCeEdhCDjzGMEYusfUdk,8340
85
+ responses_server/tools/web_search.py,sha256=pnKH9JyTScRehWpZS3HpXRvjWsQvC0QZqxjEOCT4ndg,8936
86
+ python_codex-0.4.1.dist-info/METADATA,sha256=oeFno9KHzkjQBQWXIQILZpJBRydqouzo7BqtpoKh9_g,47510
87
+ python_codex-0.4.1.dist-info/WHEEL,sha256=KGYbc1zXlYddvwxnNty23BeaKzh7YuoSIvIMO4jEhvw,87
88
+ python_codex-0.4.1.dist-info/entry_points.txt,sha256=sNUVakoVuTrzJH505ZgRTQxmtRRPUHV_EH0i6EbYTyM,45
89
+ python_codex-0.4.1.dist-info/licenses/LICENSE,sha256=0X8ifk312hYAORM4hlzg8wVSEXYKNmiPgWlB1YIy2Nw,10926
90
+ python_codex-0.4.1.dist-info/RECORD,,
@@ -1,3 +1,2 @@
1
1
  [console_scripts]
2
2
  pycodex = pycodex.cli:main
3
- pycodex-ws = workspace_server:main
responses_server/app.py CHANGED
@@ -9,8 +9,11 @@ from dataclasses import replace
9
9
  from typing import Iterator
10
10
 
11
11
  import uvicorn
12
- from fastapi import FastAPI, Request
13
- from fastapi.responses import JSONResponse, StreamingResponse
12
+ from starlette.applications import Starlette
13
+ from starlette.exceptions import HTTPException
14
+ from starlette.requests import Request
15
+ from starlette.responses import JSONResponse, StreamingResponse
16
+ from starlette.routing import Route
14
17
 
15
18
  from .config import CompatServerConfig
16
19
  from .server import ResponseServer
@@ -22,6 +25,12 @@ def _run_uvicorn_server(server) -> "None":
22
25
  server.run()
23
26
 
24
27
 
28
+ async def _http_exception_response(request: "Request", exc: "HTTPException"):
29
+ return JSONResponse(
30
+ {"detail": exc.detail}, status_code=exc.status_code, headers=exc.headers
31
+ )
32
+
33
+
25
34
  def _format_sse_event(
26
35
  event_name: "str", payload: "typing.Dict[str, object]"
27
36
  ) -> "bytes":
@@ -113,33 +122,25 @@ class ManagedResponseServer:
113
122
  config: "CompatServerConfig",
114
123
  session_store=None,
115
124
  stream_router=None,
116
- ) -> "FastAPI":
125
+ ) -> "Starlette":
117
126
  response_server = ResponseServer(
118
127
  config,
119
128
  session_store=session_store,
120
129
  stream_router=stream_router,
121
130
  )
122
- app = FastAPI(title="ResponsesCompat", version="0.1.0")
123
- app.state.response_server = response_server
124
131
 
125
- @app.get("/health")
126
- @app.get("/healthz")
127
- async def health() -> "typing.Dict[str, bool]":
128
- return {"ok": True}
132
+ async def health(request: "Request"):
133
+ return JSONResponse({"ok": True})
129
134
 
130
- @app.get("/models")
131
- @app.get("/v1/models")
132
- async def list_models():
135
+ async def list_models(request: "Request"):
133
136
  try:
134
- return response_server.list_models()
137
+ return JSONResponse(response_server.list_models())
135
138
  except OutcommingChatError as exc:
136
139
  return JSONResponse(
137
140
  {"error": {"message": str(exc)}},
138
141
  status_code=502,
139
142
  )
140
143
 
141
- @app.post("/responses")
142
- @app.post("/v1/responses")
143
144
  async def responses(request: "Request"):
144
145
  try:
145
146
  request_body = await request.json()
@@ -174,6 +175,18 @@ class ManagedResponseServer:
174
175
  },
175
176
  )
176
177
 
178
+ app = Starlette(
179
+ routes=[
180
+ Route("/health", health, methods=["GET"]),
181
+ Route("/healthz", health, methods=["GET"]),
182
+ Route("/models", list_models, methods=["GET"]),
183
+ Route("/v1/models", list_models, methods=["GET"]),
184
+ Route("/responses", responses, methods=["POST"]),
185
+ Route("/v1/responses", responses, methods=["POST"]),
186
+ ],
187
+ exception_handlers={HTTPException: _http_exception_response},
188
+ )
189
+ app.state.response_server = response_server
177
190
  return app
178
191
 
179
192
  def __init__(self, config: "CompatServerConfig") -> "None":