python-codex 0.3.2__tar.gz → 0.4.0__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.
- {python_codex-0.3.2 → python_codex-0.4.0}/PKG-INFO +165 -42
- {python_codex-0.3.2 → python_codex-0.4.0}/README.md +162 -36
- {python_codex-0.3.2 → python_codex-0.4.0}/README_ZH.md +130 -22
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/__init__.py +3 -27
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/bootstrap.py +5 -45
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/cli.py +1 -14
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/context.py +1 -1
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/events.py +1 -1
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/model.py +2 -2
- python_codex-0.4.0/pycodex/portable/__init__.py +45 -0
- python_codex-0.3.2/pycodex/portable.py → python_codex-0.4.0/pycodex/portable/client.py +4 -7
- python_codex-0.3.2/pycodex/portable_server.py → python_codex-0.4.0/pycodex/portable/server.py +3 -3
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/protocol.py +1 -1
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/runtime.py +1 -1
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/base_tool.py +1 -1
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/close_agent_tool.py +1 -1
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/code_mode_manager.py +1 -1
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/request_permissions_tool.py +1 -1
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/resume_agent_tool.py +1 -1
- {python_codex-0.3.2/pycodex → python_codex-0.4.0/pycodex/tools}/runtime_services.py +5 -5
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/send_input_tool.py +1 -1
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/spawn_agent_tool.py +1 -1
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/unified_exec_manager.py +1 -1
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/update_plan_tool.py +1 -1
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/view_image_tool.py +5 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/wait_agent_tool.py +1 -1
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/utils/__init__.py +0 -4
- python_codex-0.4.0/pycodex/utils/_aes_gcm/LICENSE +56 -0
- python_codex-0.4.0/pycodex/utils/_aes_gcm/README.md +61 -0
- python_codex-0.4.0/pycodex/utils/_aes_gcm/__init__.py +1 -0
- python_codex-0.4.0/pycodex/utils/_aes_gcm/aes.py +175 -0
- python_codex-0.4.0/pycodex/utils/_aes_gcm/gcm.py +73 -0
- python_codex-0.4.0/pycodex/utils/_aes_gcm/source-sha256.json +4 -0
- {python_codex-0.3.2/pycodex → python_codex-0.4.0/pycodex/utils}/compat.py +2 -0
- python_codex-0.4.0/pycodex/utils/crypto.py +35 -0
- python_codex-0.4.0/pycodex/utils/debug.py +36 -0
- {python_codex-0.3.2/pycodex → python_codex-0.4.0/pycodex/utils}/doctor.py +3 -3
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/utils/image_utils.py +3 -2
- {python_codex-0.3.2/pycodex → python_codex-0.4.0/pycodex/utils}/model_metadata.py +2 -2
- {python_codex-0.3.2 → python_codex-0.4.0}/pyproject.toml +23 -17
- {python_codex-0.3.2 → python_codex-0.4.0}/responses_server/app.py +28 -15
- {python_codex-0.3.2 → python_codex-0.4.0}/responses_server/stream_router.py +17 -13
- python_codex-0.3.2/.github/workflows/publish.yml +0 -201
- python_codex-0.3.2/.github/workflows/test.yml +0 -87
- python_codex-0.3.2/AGENTS.md +0 -82
- python_codex-0.3.2/docs/ALIGNMENT.md +0 -777
- python_codex-0.3.2/docs/CONTEXT.md +0 -187
- python_codex-0.3.2/docs/RELEASE_0.3.0.md +0 -74
- python_codex-0.3.2/docs/RELEASE_0.3.2.md +0 -36
- python_codex-0.3.2/docs/RUNTIME.md +0 -712
- python_codex-0.3.2/docs/responses_server/README.md +0 -163
- python_codex-0.3.2/packages/pycodex-ws/README.md +0 -21
- python_codex-0.3.2/packages/pycodex-ws/pycodex_ws_meta/__init__.py +0 -1
- python_codex-0.3.2/packages/pycodex-ws/pyproject.toml +0 -16
- python_codex-0.3.2/pycodex/feishu_card.py +0 -793
- python_codex-0.3.2/pycodex/feishu_link.py +0 -440
- python_codex-0.3.2/pycodex/tools/ipython_tool.py +0 -142
- python_codex-0.3.2/pycodex/utils/debug.py +0 -12
- python_codex-0.3.2/tests/TESTS.md +0 -367
- python_codex-0.3.2/tests/__init__.py +0 -2
- python_codex-0.3.2/tests/compare_context_requests.py +0 -485
- python_codex-0.3.2/tests/compare_steer_request_bodies.py +0 -689
- python_codex-0.3.2/tests/compare_tool_schemas.py +0 -499
- python_codex-0.3.2/tests/conftest.py +0 -6
- python_codex-0.3.2/tests/fake_responses_server.py +0 -402
- python_codex-0.3.2/tests/fakes.py +0 -56
- python_codex-0.3.2/tests/responses_server/fake_chat_completions_server.py +0 -499
- python_codex-0.3.2/tests/responses_server/test_server.py +0 -2782
- python_codex-0.3.2/tests/responses_server/test_trajectory_dump.py +0 -127
- python_codex-0.3.2/tests/test_agent.py +0 -1776
- python_codex-0.3.2/tests/test_agent_state.py +0 -1718
- python_codex-0.3.2/tests/test_async_bridge.py +0 -142
- python_codex-0.3.2/tests/test_builtin_tools.py +0 -1613
- python_codex-0.3.2/tests/test_cli.py +0 -744
- python_codex-0.3.2/tests/test_compactor.py +0 -111
- python_codex-0.3.2/tests/test_context.py +0 -491
- python_codex-0.3.2/tests/test_doctor.py +0 -166
- python_codex-0.3.2/tests/test_events.py +0 -792
- python_codex-0.3.2/tests/test_fake_responses_server.py +0 -187
- python_codex-0.3.2/tests/test_feishu_card.py +0 -732
- python_codex-0.3.2/tests/test_feishu_link.py +0 -332
- python_codex-0.3.2/tests/test_feishu_oauth.py +0 -61
- python_codex-0.3.2/tests/test_ipython_tool.py +0 -100
- python_codex-0.3.2/tests/test_model.py +0 -2281
- python_codex-0.3.2/tests/test_owned_workspace_server.py +0 -145
- python_codex-0.3.2/tests/test_packaging.py +0 -71
- python_codex-0.3.2/tests/test_portable.py +0 -194
- python_codex-0.3.2/tests/test_py36_syntax.py +0 -31
- python_codex-0.3.2/tests/test_runtime_state.py +0 -860
- python_codex-0.3.2/tests/test_session_backend.py +0 -726
- python_codex-0.3.2/tests/test_workspace_server.py +0 -1307
- python_codex-0.3.2/tools/feishu_oauth.py +0 -185
- python_codex-0.3.2/tools/sync_model_prompts.py +0 -39
- python_codex-0.3.2/workspace_server/__init__.py +0 -39
- python_codex-0.3.2/workspace_server/__main__.py +0 -4
- python_codex-0.3.2/workspace_server/app.py +0 -1713
- python_codex-0.3.2/workspace_server/owned_process.py +0 -27
- python_codex-0.3.2/workspace_server/workspace.html +0 -2211
- python_codex-0.3.2/workspace_server/workspaces.html +0 -550
- python_codex-0.3.2/workspace_server/workspaces.py +0 -628
- {python_codex-0.3.2 → python_codex-0.4.0}/.gitignore +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/LICENSE +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/__main__.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/agent.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/prompts/default_base_instructions.md +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/prompts/models.json +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/prompts/permissions/approval_policy/never.md +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/prompts/permissions/approval_policy/on_failure.md +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/prompts/permissions/approval_policy/on_request.md +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/prompts/permissions/approval_policy/on_request_rule_request_permission.md +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/prompts/permissions/approval_policy/unless_trusted.md +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/prompts/permissions/sandbox_mode/danger_full_access.md +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/prompts/permissions/sandbox_mode/read_only.md +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/prompts/permissions/sandbox_mode/workspace_write.md +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/__init__.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/agent_tool_schemas.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/apply_patch_tool.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/clock_tool.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/exec_command_tool.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/exec_runtime.js +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/exec_tool.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/grep_files_tool.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/list_dir_tool.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/read_file_tool.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/request_user_input_tool.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/shell_command_tool.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/shell_tool.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/wait_tool.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/web_search_tool.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/tools/write_stdin_tool.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/utils/async_bridge.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/utils/compactor.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/utils/dotenv.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/utils/event_helpers.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/utils/get_env.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/utils/random_ids.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/utils/session_persist.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/pycodex/utils/truncation.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/responses_server/__init__.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/responses_server/__main__.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/responses_server/config.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/responses_server/messages_api.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/responses_server/payload_processors.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/responses_server/server.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/responses_server/session_store.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/responses_server/tools/__init__.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/responses_server/tools/custom_adapter.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/responses_server/tools/web_search.py +0 -0
- {python_codex-0.3.2 → python_codex-0.4.0}/responses_server/trajectory_dump.py +0 -0
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-codex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
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,21 +22,43 @@ 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
|
+
|
|
27
|
+
0.3.3 workspace viewers and reasoning stream fix: [release notes](docs/RELEASE_0.3.3.md).
|
|
28
|
+
|
|
28
29
|
0.3.2 startup fixes: [release notes](docs/RELEASE_0.3.2.md).
|
|
29
30
|
|
|
30
31
|
0.3.0 release preparation and Python API migration: `docs/RELEASE_0.3.0.md`.
|
|
31
32
|
|
|
32
33
|
PyPI distributions:
|
|
33
34
|
|
|
34
|
-
-
|
|
35
|
-
- Workspace
|
|
35
|
+
- Core package: `python-codex`
|
|
36
|
+
- Workspace and integrations: `pycodex-ws`
|
|
36
37
|
|
|
37
38
|
The import path remains `pycodex`; the CLI commands are `pycodex` and
|
|
38
39
|
`pycodex-ws`.
|
|
39
40
|
|
|
40
|
-
`
|
|
41
|
-
|
|
42
|
-
|
|
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
|
+
Feishu and IPython integrations, including their dependencies. It owns the
|
|
45
|
+
`workspace_server` and `pycodex_ws` modules and the `pycodex-ws` command.
|
|
46
|
+
|
|
47
|
+
Core does not require Pillow. Without it, `view_image` sends the original image
|
|
48
|
+
bytes with `detail="original"`, including when `high` is requested. With Pillow
|
|
49
|
+
installed, the default path retains resizing to a maximum dimension of 2048.
|
|
50
|
+
`pycodex-ws` installs Pillow for image preview validation.
|
|
51
|
+
|
|
52
|
+
Portable encryption uses a bundled pure Python AES-GCM subset of pyaes and
|
|
53
|
+
tlslite-ng, under MIT and BSD licenses. Core does not require a crypto package
|
|
54
|
+
or compiler and ships a `py3-none-any` wheel. Existing `PCX1` bundles and call
|
|
55
|
+
tokens remain compatible; large bundles take longer to encrypt and decrypt.
|
|
56
|
+
See the [source notes](pycodex/utils/_aes_gcm/README.md).
|
|
57
|
+
|
|
58
|
+
The Responses compatibility server and workspace HTTP server use Starlette
|
|
59
|
+
and Uvicorn directly. Neither package requires FastAPI, Pydantic or
|
|
60
|
+
`pydantic-core`. Python 3.6 uses Starlette 0.19.x; newer interpreters resolve
|
|
61
|
+
a compatible Starlette release through its Python version metadata.
|
|
43
62
|
|
|
44
63
|
This repository extracts the core Codex agent loop from upstream Codex
|
|
45
64
|
(`https://github.com/openai/codex`) into a deliberately small Python version,
|
|
@@ -59,16 +78,17 @@ Relevant Rust reference points:
|
|
|
59
78
|
|
|
60
79
|
## Quick Start
|
|
61
80
|
|
|
62
|
-
Install the
|
|
81
|
+
Install the core CLI, or install the workspace package to include all integrations:
|
|
63
82
|
|
|
64
83
|
```bash
|
|
65
84
|
python3 -m pip install python-codex
|
|
66
85
|
python3 -m pip install pycodex-ws
|
|
67
86
|
```
|
|
68
87
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
88
|
+
The core supports Python 3.6.2 or newer. The workspace package requires Python
|
|
89
|
+
3.7 or newer because of its Feishu SDK dependency. Commands are installed into
|
|
90
|
+
that interpreter's scripts directory. On a machine with multiple Python
|
|
91
|
+
installations, select the same interpreter explicitly for startup:
|
|
72
92
|
|
|
73
93
|
```bash
|
|
74
94
|
python3 -m pycodex
|
|
@@ -79,10 +99,14 @@ If `pycodex` is missing from `PATH` or resolves to an older installation, use th
|
|
|
79
99
|
module entry points. `python3 -m pip --version` shows which Python environment
|
|
80
100
|
received the installation.
|
|
81
101
|
|
|
102
|
+
For an existing Web installation, use `python3 -m pip install --upgrade pycodex-ws`
|
|
103
|
+
to upgrade the workspace and its matching core together. Installing only
|
|
104
|
+
`python-codex` provides the CLI and core API.
|
|
105
|
+
|
|
82
106
|
For development from this repository, install dependencies first:
|
|
83
107
|
|
|
84
108
|
```bash
|
|
85
|
-
uv sync
|
|
109
|
+
uv sync --dev
|
|
86
110
|
```
|
|
87
111
|
|
|
88
112
|
Try the real entry points:
|
|
@@ -92,8 +116,22 @@ uv run pycodex "Reply with exactly OK."
|
|
|
92
116
|
uv run pycodex
|
|
93
117
|
```
|
|
94
118
|
|
|
95
|
-
|
|
96
|
-
|
|
119
|
+
Tests are split by package. `uv run --dev pytest` runs both suites;
|
|
120
|
+
`uv run --dev pytest packages/pycodex-ws/tests` runs workspace and integration
|
|
121
|
+
tests. To check core without installing workspace or its SDKs, use a separate
|
|
122
|
+
environment:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
UV_PROJECT_ENVIRONMENT=.tmp/core-tests uv sync --group test
|
|
126
|
+
UV_PROJECT_ENVIRONMENT=.tmp/core-tests uv run --group test pytest tests
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
See [test environments and coverage](tests/TESTS.md). Core tests support Python
|
|
130
|
+
3.6.2+; workspace tests require Python 3.7+.
|
|
131
|
+
|
|
132
|
+
A VS Code frontend is available in [`packages/pycodex-ws/extensions/vscode`](packages/pycodex-ws/extensions/vscode/README.md).
|
|
133
|
+
It belongs to the workspace frontend and is packaged separately as a VSIX.
|
|
134
|
+
It reuses an existing `pycodex-ws>=0.4.0` installation. On first use, missing
|
|
97
135
|
or older backends are installed/upgraded with pip in the selected Python
|
|
98
136
|
environment on the workspace host; compatible versions need no network check.
|
|
99
137
|
It starts a dedicated `pycodex-ws` workspace on the project's host and opens a
|
|
@@ -141,19 +179,35 @@ nailing the core tool-augmented reasoning loop first.
|
|
|
141
179
|
|
|
142
180
|
## Layout
|
|
143
181
|
|
|
182
|
+
The top level of `pycodex/` contains the core components and package entry points.
|
|
183
|
+
Supporting services live in `tools/`, `portable/` and `utils/`.
|
|
184
|
+
|
|
185
|
+
- `pycodex/agent.py`: inner turn loop
|
|
186
|
+
- `pycodex/runtime.py`: session commands, submission queues and frontend event subscriptions
|
|
187
|
+
- `pycodex/model.py`: model client protocol and Responses API adapter
|
|
188
|
+
- `pycodex/context.py`: configuration, prompt assembly and instruction loading
|
|
144
189
|
- `pycodex/protocol.py`: minimal conversation item / prompt protocol
|
|
145
190
|
- `pycodex/events.py`: typed events, plain-text views and stateful presentation
|
|
146
|
-
- `pycodex/utils/event_helpers.py`: stateless text, color, summary and result-formatting helpers
|
|
147
|
-
- `pycodex/utils/image_utils.py`: image loading, resizing and data-URL preparation
|
|
148
|
-
- `pycodex/model.py`: model client protocol and Responses API adapter
|
|
149
|
-
- `pycodex/cli.py`: single-turn/interactive entry points, terminal I/O executor and input loop
|
|
150
191
|
- `pycodex/bootstrap.py`: frontend-independent model, tools, Agent and session assembly
|
|
192
|
+
- `pycodex/cli.py`: single-turn/interactive entry points, terminal I/O executor and input loop
|
|
151
193
|
- `pycodex/tools/base_tool.py`: `BaseTool`, `ToolRegistry`, `ToolContext`
|
|
152
|
-
- `pycodex/tools
|
|
153
|
-
- `pycodex/
|
|
154
|
-
- `pycodex/
|
|
155
|
-
- `
|
|
156
|
-
- `
|
|
194
|
+
- `pycodex/tools/runtime_services.py`: plan, sub-agent, user-input and permissions services
|
|
195
|
+
- `pycodex/tools/`: concrete tools and their execution managers
|
|
196
|
+
- `pycodex/portable/`: Codex home storage client and server, both included in core
|
|
197
|
+
- `pycodex/utils/compat.py`: supported-Python compatibility helpers
|
|
198
|
+
- `pycodex/utils/doctor.py`: configuration and connectivity diagnostics
|
|
199
|
+
- `pycodex/utils/model_metadata.py`: vendored model metadata lookup
|
|
200
|
+
- `pycodex/utils/debug.py`: debug paths and the `pycodex.debug()` implementation
|
|
201
|
+
- `pycodex/utils/event_helpers.py`: stateless text, color, summary and result-formatting helpers
|
|
202
|
+
- `pycodex/utils/image_utils.py`: image loading, resizing and data-URL preparation
|
|
203
|
+
- `pycodex/prompts/`: vendored prompts and model metadata
|
|
204
|
+
- `packages/pycodex-ws/workspace_server/`: Web board, API and file/diff viewers
|
|
205
|
+
- `packages/pycodex-ws/pycodex_ws/`: Feishu, IPython and workspace assembly
|
|
206
|
+
- `packages/pycodex-ws/extensions/vscode/`: workspace's VS Code frontend, built separately as a VSIX
|
|
207
|
+
- `tests/`: core tests
|
|
208
|
+
- `packages/pycodex-ws/tests/`: workspace and cross-frontend integration tests
|
|
209
|
+
|
|
210
|
+
See [package layout and import paths](docs/RUNTIME.md#package-layout).
|
|
157
211
|
|
|
158
212
|
## Current Alignment Status
|
|
159
213
|
|
|
@@ -264,6 +318,53 @@ Current behavior:
|
|
|
264
318
|
- with an argv prompt or piped stdin, run a single turn
|
|
265
319
|
- `pycodex-ws` starts the standalone browser workspace manager and serves each
|
|
266
320
|
workspace with a board pane and a pycodex session pane
|
|
321
|
+
- the left pane is the board, containing an optional live HTML Canvas tab and closable read-only file/diff tabs that
|
|
322
|
+
scroll together in one toolbar; a mouse wheel scrolls overflowing tab strips
|
|
323
|
+
horizontally.
|
|
324
|
+
Click Markdown file links such as `[source](src/app.py:42)` or
|
|
325
|
+
`[source](/data/project/app.py#L42)` to open a view. Git-style diff links use
|
|
326
|
+
`[changes](diff:HEAD:src/app.py)` for working changes,
|
|
327
|
+
`[versions](diff:HEAD~1..HEAD:src/app.py)` for two revisions, and
|
|
328
|
+
`[files](diff:old.py..new.py)` for two local files. Append `#L42` or `#R42`
|
|
329
|
+
to a diff link to select a 1-based line on the left or right.
|
|
330
|
+
Views open when the user clicks; model replies alone do not create tabs.
|
|
331
|
+
Reopening the same file or comparison selects its existing tab in that
|
|
332
|
+
browser, including when the line changes. Other pages keep their selection.
|
|
333
|
+
Tabs show filenames first, adding a short directory suffix
|
|
334
|
+
for duplicate names. Git versions use short commit IDs in a secondary label.
|
|
335
|
+
Long labels use the same width limit as session tabs, shortening the secondary
|
|
336
|
+
information before the filename;
|
|
337
|
+
hover titles retain the complete paths and revisions. Text,
|
|
338
|
+
Markdown, HTML, common raster images and text diffs are supported. Monaco
|
|
339
|
+
provides syntax highlighting, find, folding and character-level diffs.
|
|
340
|
+
Right-click code and choose **Insert into chat**, or select text and use the
|
|
341
|
+
toolbar button, to insert context at the current chat draft's cursor.
|
|
342
|
+
Context appears as a separate block among your words. Click it to edit or
|
|
343
|
+
remove it; Backspace and Delete also remove a block as one element.
|
|
344
|
+
Context identifies the full view label, including both revisions of a diff.
|
|
345
|
+
Selections include only the selected text and range; otherwise it records the
|
|
346
|
+
cursor location. Diff context also identifies the selected side.
|
|
347
|
+
The draft stays editable until you send it.
|
|
348
|
+
Its code and styles load only when a code or diff view opens, so Canvas,
|
|
349
|
+
Markdown and HTML previews do not load the editor. Viewer assets use gzip
|
|
350
|
+
when supported and revalidate cached content with ETags.
|
|
351
|
+
Narrow content panes automatically use a unified diff; targeting the left
|
|
352
|
+
side keeps both sides visible. Markdown and HTML links default to previews;
|
|
353
|
+
line targets open their source. Clicking a link without a line returns that
|
|
354
|
+
same tab to preview. Manual tab switches preserve the chosen mode and reading state.
|
|
355
|
+
All views remain
|
|
356
|
+
read-only, with text selection and copying available. Local files update
|
|
357
|
+
automatically, including both sides of file diffs and the working side of
|
|
358
|
+
Git diffs; Git revisions stay fixed. Updates keep the active editor and
|
|
359
|
+
reading state without replaying an earlier line request.
|
|
360
|
+
Canvas is for explanations and custom visuals; source and diffs use links.
|
|
361
|
+
`[Canvas](workspace://canvas)` returns to the live page; an HTML file link opens
|
|
362
|
+
a preview tab, and `page.html:1` opens its source. File links work even with an empty `--toolset`.
|
|
363
|
+
Canvas and HTML previews share the same origin and script permissions;
|
|
364
|
+
the browser loads their resources with the workspace login cookie.
|
|
365
|
+
Open views survive reloads and server restarts. See
|
|
366
|
+
[workspace content views](docs/RUNTIME.md#workspace-content-views) for the
|
|
367
|
+
complete syntax and limits.
|
|
267
368
|
- interactive mode exits through `/exit`, `/quit`, Ctrl+D on an empty prompt,
|
|
268
369
|
or a single Ctrl+C; accepted work finishes before cleanup and normal exit.
|
|
269
370
|
A `[closing]` message explains the wait. Press Ctrl+C again while closing
|
|
@@ -312,28 +413,37 @@ Current behavior:
|
|
|
312
413
|
non-persisted follow-up session and submits the file contents as the next
|
|
313
414
|
user instruction; this is intended for side-effect follow-ups such as
|
|
314
415
|
Feishu notifications
|
|
315
|
-
- `/link <feishu-email|open_id|chat_id>`
|
|
316
|
-
|
|
416
|
+
- `/link <feishu-email|open_id|chat_id>` in a workspace session attaches it
|
|
417
|
+
to a Feishu card; multiple sessions in the same workspace process share
|
|
317
418
|
one Feishu long-connection listener and route card actions by message id
|
|
318
419
|
- Feishu user OAuth stores its refresh token only in
|
|
319
420
|
`~/.codex/.feishu_refresh_token` (mode `0600`). Run
|
|
320
|
-
`
|
|
321
|
-
|
|
421
|
+
`python3 -m pycodex_ws.feishu_oauth` after installing `pycodex-ws` to authorize.
|
|
422
|
+
From this repository, use `env -u VIRTUAL_ENV uv run --dev python -m pycodex_ws.feishu_oauth`.
|
|
423
|
+
App credentials can stay in `~/.codex/.env`. Each refresh reads
|
|
322
424
|
the latest token from the dedicated file and saves its replacement there.
|
|
323
425
|
`FEISHU_REFRESH_TOKEN` in `.env` or the environment is no longer used and
|
|
324
426
|
can be removed. Refresh is triggered by API calls, with no idle keepalive.
|
|
325
427
|
- `pycodex-ws --workspace-config workspaces.json` serves workspace boards from
|
|
326
428
|
one process. The JSON file can be either a list or
|
|
327
|
-
`{"workspaces": [...]}`; each entry uses `
|
|
328
|
-
display/URL `id
|
|
329
|
-
`
|
|
330
|
-
|
|
429
|
+
`{"workspaces": [...]}`; each entry uses `state_path` and `work_dir`, with optional
|
|
430
|
+
display/URL `id` and `enable_board` (default `true`), and is exposed at `/w/<id>/`.
|
|
431
|
+
`state_path` is a filename prefix: `/data/demo` uses
|
|
432
|
+
`/data/demo.pycodex-ws.json` for the session index,
|
|
433
|
+
`/data/demo.pycodex-views.json` for file views and `/data/demo.html` for Canvas.
|
|
434
|
+
Suffixes are appended, so prefixes containing dots remain distinct.
|
|
435
|
+
The resolved `state_path` is the workspace identity; duplicates are rejected
|
|
436
|
+
regardless of name or Canvas setting. Relative `state_path` and `work_dir` paths
|
|
331
437
|
resolve from the config file directory. The root path `/` shows a workspaces
|
|
332
|
-
management page with
|
|
333
|
-
`
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
438
|
+
management page with create/delete controls; omitted names become `workspace-1`,
|
|
439
|
+
`workspace-2`, etc. Omitted `state_path` when creating a workspace generates a
|
|
440
|
+
writable `/tmp/pcws-*` prefix. `enable_board: false` hides Canvas and disables its
|
|
441
|
+
routes, polling and context injection; sessions and file views still persist.
|
|
442
|
+
Existing `board: "demo.html"` and `board: false` configurations load with their
|
|
443
|
+
original state paths and are saved in the new format. See the
|
|
444
|
+
[workspace configuration example](packages/pycodex-ws/README.md).
|
|
445
|
+
Add/delete actions and later session-state saves refresh the JSON file.
|
|
446
|
+
Board HTML can reference local
|
|
337
447
|
images beside the board (including nested paths) with relative URLs; only
|
|
338
448
|
`image/*` files contained by the board directory are served.
|
|
339
449
|
Assistant Markdown supports KaTeX formulas with `$...$`, `$$...$$`,
|
|
@@ -366,7 +476,7 @@ Current behavior:
|
|
|
366
476
|
time when it expires.
|
|
367
477
|
- while a background command or clock is pending, the idle status is
|
|
368
478
|
`idle: sleeping`
|
|
369
|
-
- only the active workspace tab shows its close button; closing it restores
|
|
479
|
+
- only the active workspace session tab shows its close button; closing it restores
|
|
370
480
|
the selected tab's conversation, draft, and scroll position immediately
|
|
371
481
|
after its snapshot loads
|
|
372
482
|
- `--vllm-endpoint http://host:port` automatically launches a local
|
|
@@ -387,6 +497,10 @@ Current behavior:
|
|
|
387
497
|
reasoning, retries the same downstream request once, and only then emits
|
|
388
498
|
`response.failed` with `type = "model_output_invalid"` if the retry is still
|
|
389
499
|
reasoning-only
|
|
500
|
+
- compat reasoning fragments are forwarded immediately as
|
|
501
|
+
`response.reasoning_text.delta`, including thinking from `/v1/messages`.
|
|
502
|
+
Continuous reasoning keeps the client's read idle timeout from expiring
|
|
503
|
+
while it waits for assistant text; only finalized reasoning items enter history
|
|
390
504
|
- malformed JSON in ordinary downstream function-call arguments is detected by
|
|
391
505
|
`responses_server` and returned as `response.failed` with `type = "server_error"`;
|
|
392
506
|
the client's existing `stream_max_retries` policy retries the current request
|
|
@@ -421,6 +535,13 @@ pycodex doctor --json
|
|
|
421
535
|
`Portable Mode` is the quickest way to bring your usual `pycodex` setup into a
|
|
422
536
|
fresh machine, container, or debug image.
|
|
423
537
|
|
|
538
|
+
The storage client and server are both included in `python-codex`. To start a
|
|
539
|
+
local storage service, run this in a separate terminal:
|
|
540
|
+
|
|
541
|
+
```bash
|
|
542
|
+
python -m pycodex.portable.server --root .tmp/pycodex_storage --host 127.0.0.1 --port 5577
|
|
543
|
+
```
|
|
544
|
+
|
|
424
545
|
Use it like this:
|
|
425
546
|
|
|
426
547
|
```bash
|
|
@@ -614,7 +735,9 @@ CLI, Web and Feishu all use `AgentRuntime.submit_input`: not just `/model`
|
|
|
614
735
|
and `/resume`, but every session command, steer/queue admission, interactive
|
|
615
736
|
questions and permissions, state notifications and shutdown. Frontends only
|
|
616
737
|
adapt input and render events. Web no longer imports or runs the CLI shell.
|
|
617
|
-
IPython is the deliberate exception: `ipython_agent()`
|
|
738
|
+
IPython is the deliberate exception: `pycodex_ws.ipython.ipython_agent()` returns
|
|
739
|
+
a bare Agent. Workspace assembly uses `pycodex_ws.build_runtime()` to add
|
|
740
|
+
`/link` and `/unlink`; `pycodex.bootstrap.build_runtime()` provides core commands.
|
|
618
741
|
|
|
619
742
|
```python
|
|
620
743
|
from pycodex.bootstrap import build_agent, build_model, build_runtime
|
|
@@ -2,21 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
English README. Chinese version: `README_ZH.md`
|
|
4
4
|
|
|
5
|
+
0.4.0 core/workspace package split and dependency cleanup: [release notes](docs/RELEASE_0.4.0.md).
|
|
6
|
+
|
|
7
|
+
0.3.3 workspace viewers and reasoning stream fix: [release notes](docs/RELEASE_0.3.3.md).
|
|
8
|
+
|
|
5
9
|
0.3.2 startup fixes: [release notes](docs/RELEASE_0.3.2.md).
|
|
6
10
|
|
|
7
11
|
0.3.0 release preparation and Python API migration: `docs/RELEASE_0.3.0.md`.
|
|
8
12
|
|
|
9
13
|
PyPI distributions:
|
|
10
14
|
|
|
11
|
-
-
|
|
12
|
-
- Workspace
|
|
15
|
+
- Core package: `python-codex`
|
|
16
|
+
- Workspace and integrations: `pycodex-ws`
|
|
13
17
|
|
|
14
18
|
The import path remains `pycodex`; the CLI commands are `pycodex` and
|
|
15
19
|
`pycodex-ws`.
|
|
16
20
|
|
|
17
|
-
`
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
`python-codex` contains the Agent, runtime, CLI, standard tools, Responses
|
|
22
|
+
compatibility server and portable storage support. `pycodex-ws` depends on the
|
|
23
|
+
exact matching core version and contains the browser workspace, viewer assets,
|
|
24
|
+
Feishu and IPython integrations, including their dependencies. It owns the
|
|
25
|
+
`workspace_server` and `pycodex_ws` modules and the `pycodex-ws` command.
|
|
26
|
+
|
|
27
|
+
Core does not require Pillow. Without it, `view_image` sends the original image
|
|
28
|
+
bytes with `detail="original"`, including when `high` is requested. With Pillow
|
|
29
|
+
installed, the default path retains resizing to a maximum dimension of 2048.
|
|
30
|
+
`pycodex-ws` installs Pillow for image preview validation.
|
|
31
|
+
|
|
32
|
+
Portable encryption uses a bundled pure Python AES-GCM subset of pyaes and
|
|
33
|
+
tlslite-ng, under MIT and BSD licenses. Core does not require a crypto package
|
|
34
|
+
or compiler and ships a `py3-none-any` wheel. Existing `PCX1` bundles and call
|
|
35
|
+
tokens remain compatible; large bundles take longer to encrypt and decrypt.
|
|
36
|
+
See the [source notes](pycodex/utils/_aes_gcm/README.md).
|
|
37
|
+
|
|
38
|
+
The Responses compatibility server and workspace HTTP server use Starlette
|
|
39
|
+
and Uvicorn directly. Neither package requires FastAPI, Pydantic or
|
|
40
|
+
`pydantic-core`. Python 3.6 uses Starlette 0.19.x; newer interpreters resolve
|
|
41
|
+
a compatible Starlette release through its Python version metadata.
|
|
20
42
|
|
|
21
43
|
This repository extracts the core Codex agent loop from upstream Codex
|
|
22
44
|
(`https://github.com/openai/codex`) into a deliberately small Python version,
|
|
@@ -36,16 +58,17 @@ Relevant Rust reference points:
|
|
|
36
58
|
|
|
37
59
|
## Quick Start
|
|
38
60
|
|
|
39
|
-
Install the
|
|
61
|
+
Install the core CLI, or install the workspace package to include all integrations:
|
|
40
62
|
|
|
41
63
|
```bash
|
|
42
64
|
python3 -m pip install python-codex
|
|
43
65
|
python3 -m pip install pycodex-ws
|
|
44
66
|
```
|
|
45
67
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
68
|
+
The core supports Python 3.6.2 or newer. The workspace package requires Python
|
|
69
|
+
3.7 or newer because of its Feishu SDK dependency. Commands are installed into
|
|
70
|
+
that interpreter's scripts directory. On a machine with multiple Python
|
|
71
|
+
installations, select the same interpreter explicitly for startup:
|
|
49
72
|
|
|
50
73
|
```bash
|
|
51
74
|
python3 -m pycodex
|
|
@@ -56,10 +79,14 @@ If `pycodex` is missing from `PATH` or resolves to an older installation, use th
|
|
|
56
79
|
module entry points. `python3 -m pip --version` shows which Python environment
|
|
57
80
|
received the installation.
|
|
58
81
|
|
|
82
|
+
For an existing Web installation, use `python3 -m pip install --upgrade pycodex-ws`
|
|
83
|
+
to upgrade the workspace and its matching core together. Installing only
|
|
84
|
+
`python-codex` provides the CLI and core API.
|
|
85
|
+
|
|
59
86
|
For development from this repository, install dependencies first:
|
|
60
87
|
|
|
61
88
|
```bash
|
|
62
|
-
uv sync
|
|
89
|
+
uv sync --dev
|
|
63
90
|
```
|
|
64
91
|
|
|
65
92
|
Try the real entry points:
|
|
@@ -69,8 +96,22 @@ uv run pycodex "Reply with exactly OK."
|
|
|
69
96
|
uv run pycodex
|
|
70
97
|
```
|
|
71
98
|
|
|
72
|
-
|
|
73
|
-
|
|
99
|
+
Tests are split by package. `uv run --dev pytest` runs both suites;
|
|
100
|
+
`uv run --dev pytest packages/pycodex-ws/tests` runs workspace and integration
|
|
101
|
+
tests. To check core without installing workspace or its SDKs, use a separate
|
|
102
|
+
environment:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
UV_PROJECT_ENVIRONMENT=.tmp/core-tests uv sync --group test
|
|
106
|
+
UV_PROJECT_ENVIRONMENT=.tmp/core-tests uv run --group test pytest tests
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
See [test environments and coverage](tests/TESTS.md). Core tests support Python
|
|
110
|
+
3.6.2+; workspace tests require Python 3.7+.
|
|
111
|
+
|
|
112
|
+
A VS Code frontend is available in [`packages/pycodex-ws/extensions/vscode`](packages/pycodex-ws/extensions/vscode/README.md).
|
|
113
|
+
It belongs to the workspace frontend and is packaged separately as a VSIX.
|
|
114
|
+
It reuses an existing `pycodex-ws>=0.4.0` installation. On first use, missing
|
|
74
115
|
or older backends are installed/upgraded with pip in the selected Python
|
|
75
116
|
environment on the workspace host; compatible versions need no network check.
|
|
76
117
|
It starts a dedicated `pycodex-ws` workspace on the project's host and opens a
|
|
@@ -118,19 +159,35 @@ nailing the core tool-augmented reasoning loop first.
|
|
|
118
159
|
|
|
119
160
|
## Layout
|
|
120
161
|
|
|
162
|
+
The top level of `pycodex/` contains the core components and package entry points.
|
|
163
|
+
Supporting services live in `tools/`, `portable/` and `utils/`.
|
|
164
|
+
|
|
165
|
+
- `pycodex/agent.py`: inner turn loop
|
|
166
|
+
- `pycodex/runtime.py`: session commands, submission queues and frontend event subscriptions
|
|
167
|
+
- `pycodex/model.py`: model client protocol and Responses API adapter
|
|
168
|
+
- `pycodex/context.py`: configuration, prompt assembly and instruction loading
|
|
121
169
|
- `pycodex/protocol.py`: minimal conversation item / prompt protocol
|
|
122
170
|
- `pycodex/events.py`: typed events, plain-text views and stateful presentation
|
|
123
|
-
- `pycodex/utils/event_helpers.py`: stateless text, color, summary and result-formatting helpers
|
|
124
|
-
- `pycodex/utils/image_utils.py`: image loading, resizing and data-URL preparation
|
|
125
|
-
- `pycodex/model.py`: model client protocol and Responses API adapter
|
|
126
|
-
- `pycodex/cli.py`: single-turn/interactive entry points, terminal I/O executor and input loop
|
|
127
171
|
- `pycodex/bootstrap.py`: frontend-independent model, tools, Agent and session assembly
|
|
172
|
+
- `pycodex/cli.py`: single-turn/interactive entry points, terminal I/O executor and input loop
|
|
128
173
|
- `pycodex/tools/base_tool.py`: `BaseTool`, `ToolRegistry`, `ToolContext`
|
|
129
|
-
- `pycodex/tools
|
|
130
|
-
- `pycodex/
|
|
131
|
-
- `pycodex/
|
|
132
|
-
- `
|
|
133
|
-
- `
|
|
174
|
+
- `pycodex/tools/runtime_services.py`: plan, sub-agent, user-input and permissions services
|
|
175
|
+
- `pycodex/tools/`: concrete tools and their execution managers
|
|
176
|
+
- `pycodex/portable/`: Codex home storage client and server, both included in core
|
|
177
|
+
- `pycodex/utils/compat.py`: supported-Python compatibility helpers
|
|
178
|
+
- `pycodex/utils/doctor.py`: configuration and connectivity diagnostics
|
|
179
|
+
- `pycodex/utils/model_metadata.py`: vendored model metadata lookup
|
|
180
|
+
- `pycodex/utils/debug.py`: debug paths and the `pycodex.debug()` implementation
|
|
181
|
+
- `pycodex/utils/event_helpers.py`: stateless text, color, summary and result-formatting helpers
|
|
182
|
+
- `pycodex/utils/image_utils.py`: image loading, resizing and data-URL preparation
|
|
183
|
+
- `pycodex/prompts/`: vendored prompts and model metadata
|
|
184
|
+
- `packages/pycodex-ws/workspace_server/`: Web board, API and file/diff viewers
|
|
185
|
+
- `packages/pycodex-ws/pycodex_ws/`: Feishu, IPython and workspace assembly
|
|
186
|
+
- `packages/pycodex-ws/extensions/vscode/`: workspace's VS Code frontend, built separately as a VSIX
|
|
187
|
+
- `tests/`: core tests
|
|
188
|
+
- `packages/pycodex-ws/tests/`: workspace and cross-frontend integration tests
|
|
189
|
+
|
|
190
|
+
See [package layout and import paths](docs/RUNTIME.md#package-layout).
|
|
134
191
|
|
|
135
192
|
## Current Alignment Status
|
|
136
193
|
|
|
@@ -241,6 +298,53 @@ Current behavior:
|
|
|
241
298
|
- with an argv prompt or piped stdin, run a single turn
|
|
242
299
|
- `pycodex-ws` starts the standalone browser workspace manager and serves each
|
|
243
300
|
workspace with a board pane and a pycodex session pane
|
|
301
|
+
- the left pane is the board, containing an optional live HTML Canvas tab and closable read-only file/diff tabs that
|
|
302
|
+
scroll together in one toolbar; a mouse wheel scrolls overflowing tab strips
|
|
303
|
+
horizontally.
|
|
304
|
+
Click Markdown file links such as `[source](src/app.py:42)` or
|
|
305
|
+
`[source](/data/project/app.py#L42)` to open a view. Git-style diff links use
|
|
306
|
+
`[changes](diff:HEAD:src/app.py)` for working changes,
|
|
307
|
+
`[versions](diff:HEAD~1..HEAD:src/app.py)` for two revisions, and
|
|
308
|
+
`[files](diff:old.py..new.py)` for two local files. Append `#L42` or `#R42`
|
|
309
|
+
to a diff link to select a 1-based line on the left or right.
|
|
310
|
+
Views open when the user clicks; model replies alone do not create tabs.
|
|
311
|
+
Reopening the same file or comparison selects its existing tab in that
|
|
312
|
+
browser, including when the line changes. Other pages keep their selection.
|
|
313
|
+
Tabs show filenames first, adding a short directory suffix
|
|
314
|
+
for duplicate names. Git versions use short commit IDs in a secondary label.
|
|
315
|
+
Long labels use the same width limit as session tabs, shortening the secondary
|
|
316
|
+
information before the filename;
|
|
317
|
+
hover titles retain the complete paths and revisions. Text,
|
|
318
|
+
Markdown, HTML, common raster images and text diffs are supported. Monaco
|
|
319
|
+
provides syntax highlighting, find, folding and character-level diffs.
|
|
320
|
+
Right-click code and choose **Insert into chat**, or select text and use the
|
|
321
|
+
toolbar button, to insert context at the current chat draft's cursor.
|
|
322
|
+
Context appears as a separate block among your words. Click it to edit or
|
|
323
|
+
remove it; Backspace and Delete also remove a block as one element.
|
|
324
|
+
Context identifies the full view label, including both revisions of a diff.
|
|
325
|
+
Selections include only the selected text and range; otherwise it records the
|
|
326
|
+
cursor location. Diff context also identifies the selected side.
|
|
327
|
+
The draft stays editable until you send it.
|
|
328
|
+
Its code and styles load only when a code or diff view opens, so Canvas,
|
|
329
|
+
Markdown and HTML previews do not load the editor. Viewer assets use gzip
|
|
330
|
+
when supported and revalidate cached content with ETags.
|
|
331
|
+
Narrow content panes automatically use a unified diff; targeting the left
|
|
332
|
+
side keeps both sides visible. Markdown and HTML links default to previews;
|
|
333
|
+
line targets open their source. Clicking a link without a line returns that
|
|
334
|
+
same tab to preview. Manual tab switches preserve the chosen mode and reading state.
|
|
335
|
+
All views remain
|
|
336
|
+
read-only, with text selection and copying available. Local files update
|
|
337
|
+
automatically, including both sides of file diffs and the working side of
|
|
338
|
+
Git diffs; Git revisions stay fixed. Updates keep the active editor and
|
|
339
|
+
reading state without replaying an earlier line request.
|
|
340
|
+
Canvas is for explanations and custom visuals; source and diffs use links.
|
|
341
|
+
`[Canvas](workspace://canvas)` returns to the live page; an HTML file link opens
|
|
342
|
+
a preview tab, and `page.html:1` opens its source. File links work even with an empty `--toolset`.
|
|
343
|
+
Canvas and HTML previews share the same origin and script permissions;
|
|
344
|
+
the browser loads their resources with the workspace login cookie.
|
|
345
|
+
Open views survive reloads and server restarts. See
|
|
346
|
+
[workspace content views](docs/RUNTIME.md#workspace-content-views) for the
|
|
347
|
+
complete syntax and limits.
|
|
244
348
|
- interactive mode exits through `/exit`, `/quit`, Ctrl+D on an empty prompt,
|
|
245
349
|
or a single Ctrl+C; accepted work finishes before cleanup and normal exit.
|
|
246
350
|
A `[closing]` message explains the wait. Press Ctrl+C again while closing
|
|
@@ -289,28 +393,37 @@ Current behavior:
|
|
|
289
393
|
non-persisted follow-up session and submits the file contents as the next
|
|
290
394
|
user instruction; this is intended for side-effect follow-ups such as
|
|
291
395
|
Feishu notifications
|
|
292
|
-
- `/link <feishu-email|open_id|chat_id>`
|
|
293
|
-
|
|
396
|
+
- `/link <feishu-email|open_id|chat_id>` in a workspace session attaches it
|
|
397
|
+
to a Feishu card; multiple sessions in the same workspace process share
|
|
294
398
|
one Feishu long-connection listener and route card actions by message id
|
|
295
399
|
- Feishu user OAuth stores its refresh token only in
|
|
296
400
|
`~/.codex/.feishu_refresh_token` (mode `0600`). Run
|
|
297
|
-
`
|
|
298
|
-
|
|
401
|
+
`python3 -m pycodex_ws.feishu_oauth` after installing `pycodex-ws` to authorize.
|
|
402
|
+
From this repository, use `env -u VIRTUAL_ENV uv run --dev python -m pycodex_ws.feishu_oauth`.
|
|
403
|
+
App credentials can stay in `~/.codex/.env`. Each refresh reads
|
|
299
404
|
the latest token from the dedicated file and saves its replacement there.
|
|
300
405
|
`FEISHU_REFRESH_TOKEN` in `.env` or the environment is no longer used and
|
|
301
406
|
can be removed. Refresh is triggered by API calls, with no idle keepalive.
|
|
302
407
|
- `pycodex-ws --workspace-config workspaces.json` serves workspace boards from
|
|
303
408
|
one process. The JSON file can be either a list or
|
|
304
|
-
`{"workspaces": [...]}`; each entry uses `
|
|
305
|
-
display/URL `id
|
|
306
|
-
`
|
|
307
|
-
|
|
409
|
+
`{"workspaces": [...]}`; each entry uses `state_path` and `work_dir`, with optional
|
|
410
|
+
display/URL `id` and `enable_board` (default `true`), and is exposed at `/w/<id>/`.
|
|
411
|
+
`state_path` is a filename prefix: `/data/demo` uses
|
|
412
|
+
`/data/demo.pycodex-ws.json` for the session index,
|
|
413
|
+
`/data/demo.pycodex-views.json` for file views and `/data/demo.html` for Canvas.
|
|
414
|
+
Suffixes are appended, so prefixes containing dots remain distinct.
|
|
415
|
+
The resolved `state_path` is the workspace identity; duplicates are rejected
|
|
416
|
+
regardless of name or Canvas setting. Relative `state_path` and `work_dir` paths
|
|
308
417
|
resolve from the config file directory. The root path `/` shows a workspaces
|
|
309
|
-
management page with
|
|
310
|
-
`
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
418
|
+
management page with create/delete controls; omitted names become `workspace-1`,
|
|
419
|
+
`workspace-2`, etc. Omitted `state_path` when creating a workspace generates a
|
|
420
|
+
writable `/tmp/pcws-*` prefix. `enable_board: false` hides Canvas and disables its
|
|
421
|
+
routes, polling and context injection; sessions and file views still persist.
|
|
422
|
+
Existing `board: "demo.html"` and `board: false` configurations load with their
|
|
423
|
+
original state paths and are saved in the new format. See the
|
|
424
|
+
[workspace configuration example](packages/pycodex-ws/README.md).
|
|
425
|
+
Add/delete actions and later session-state saves refresh the JSON file.
|
|
426
|
+
Board HTML can reference local
|
|
314
427
|
images beside the board (including nested paths) with relative URLs; only
|
|
315
428
|
`image/*` files contained by the board directory are served.
|
|
316
429
|
Assistant Markdown supports KaTeX formulas with `$...$`, `$$...$$`,
|
|
@@ -343,7 +456,7 @@ Current behavior:
|
|
|
343
456
|
time when it expires.
|
|
344
457
|
- while a background command or clock is pending, the idle status is
|
|
345
458
|
`idle: sleeping`
|
|
346
|
-
- only the active workspace tab shows its close button; closing it restores
|
|
459
|
+
- only the active workspace session tab shows its close button; closing it restores
|
|
347
460
|
the selected tab's conversation, draft, and scroll position immediately
|
|
348
461
|
after its snapshot loads
|
|
349
462
|
- `--vllm-endpoint http://host:port` automatically launches a local
|
|
@@ -364,6 +477,10 @@ Current behavior:
|
|
|
364
477
|
reasoning, retries the same downstream request once, and only then emits
|
|
365
478
|
`response.failed` with `type = "model_output_invalid"` if the retry is still
|
|
366
479
|
reasoning-only
|
|
480
|
+
- compat reasoning fragments are forwarded immediately as
|
|
481
|
+
`response.reasoning_text.delta`, including thinking from `/v1/messages`.
|
|
482
|
+
Continuous reasoning keeps the client's read idle timeout from expiring
|
|
483
|
+
while it waits for assistant text; only finalized reasoning items enter history
|
|
367
484
|
- malformed JSON in ordinary downstream function-call arguments is detected by
|
|
368
485
|
`responses_server` and returned as `response.failed` with `type = "server_error"`;
|
|
369
486
|
the client's existing `stream_max_retries` policy retries the current request
|
|
@@ -398,6 +515,13 @@ pycodex doctor --json
|
|
|
398
515
|
`Portable Mode` is the quickest way to bring your usual `pycodex` setup into a
|
|
399
516
|
fresh machine, container, or debug image.
|
|
400
517
|
|
|
518
|
+
The storage client and server are both included in `python-codex`. To start a
|
|
519
|
+
local storage service, run this in a separate terminal:
|
|
520
|
+
|
|
521
|
+
```bash
|
|
522
|
+
python -m pycodex.portable.server --root .tmp/pycodex_storage --host 127.0.0.1 --port 5577
|
|
523
|
+
```
|
|
524
|
+
|
|
401
525
|
Use it like this:
|
|
402
526
|
|
|
403
527
|
```bash
|
|
@@ -591,7 +715,9 @@ CLI, Web and Feishu all use `AgentRuntime.submit_input`: not just `/model`
|
|
|
591
715
|
and `/resume`, but every session command, steer/queue admission, interactive
|
|
592
716
|
questions and permissions, state notifications and shutdown. Frontends only
|
|
593
717
|
adapt input and render events. Web no longer imports or runs the CLI shell.
|
|
594
|
-
IPython is the deliberate exception: `ipython_agent()`
|
|
718
|
+
IPython is the deliberate exception: `pycodex_ws.ipython.ipython_agent()` returns
|
|
719
|
+
a bare Agent. Workspace assembly uses `pycodex_ws.build_runtime()` to add
|
|
720
|
+
`/link` and `/unlink`; `pycodex.bootstrap.build_runtime()` provides core commands.
|
|
595
721
|
|
|
596
722
|
```python
|
|
597
723
|
from pycodex.bootstrap import build_agent, build_model, build_runtime
|