python-codex 0.4.7__tar.gz → 0.5.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.5.0/PKG-INFO +193 -0
- python_codex-0.5.0/README.md +173 -0
- python_codex-0.5.0/README_ZH.md +164 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/agent.py +8 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/bootstrap.py +23 -26
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/context.py +10 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/runtime.py +11 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/apply_patch_tool.py +24 -26
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/base_tool.py +5 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/code_mode_manager.py +4 -9
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/exec_command_tool.py +1 -2
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/grep_files_tool.py +2 -16
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/shell_command_tool.py +1 -17
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/shell_tool.py +1 -17
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/unified_exec_manager.py +2 -14
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/view_image_tool.py +1 -12
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/event_helpers.py +2 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pyproject.toml +2 -2
- python_codex-0.4.7/PKG-INFO +0 -905
- python_codex-0.4.7/README.md +0 -885
- python_codex-0.4.7/README_ZH.md +0 -521
- {python_codex-0.4.7 → python_codex-0.5.0}/.gitignore +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/LICENSE +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/__init__.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/__main__.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/cli.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/events.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/model.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/portable/__init__.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/portable/client.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/portable/server.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/prompts/default_base_instructions.md +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/prompts/models.json +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/prompts/permissions/approval_policy/never.md +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/prompts/permissions/approval_policy/on_failure.md +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/prompts/permissions/approval_policy/on_request.md +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/prompts/permissions/approval_policy/on_request_rule_request_permission.md +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/prompts/permissions/approval_policy/unless_trusted.md +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/prompts/permissions/sandbox_mode/danger_full_access.md +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/prompts/permissions/sandbox_mode/read_only.md +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/prompts/permissions/sandbox_mode/workspace_write.md +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/protocol.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/__init__.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/agent_tool_schemas.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/clock_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/close_agent_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/exec_runtime.js +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/exec_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/list_dir_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/read_file_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/request_permissions_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/request_user_input_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/resume_agent_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/runtime_services.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/send_input_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/spawn_agent_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/update_plan_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/wait_agent_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/wait_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/web_search_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/tools/write_stdin_tool.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/__init__.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/_aes_gcm/LICENSE +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/_aes_gcm/README.md +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/_aes_gcm/__init__.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/_aes_gcm/aes.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/_aes_gcm/gcm.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/_aes_gcm/source-sha256.json +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/async_bridge.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/compactor.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/compat.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/crypto.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/debug.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/doctor.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/dotenv.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/get_env.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/image_utils.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/model_metadata.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/random_ids.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/session_persist.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/pycodex/utils/truncation.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/responses_server/__init__.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/responses_server/__main__.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/responses_server/app.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/responses_server/config.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/responses_server/messages_api.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/responses_server/payload_processors.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/responses_server/server.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/responses_server/session_store.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/responses_server/stream_router.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/responses_server/tools/__init__.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/responses_server/tools/custom_adapter.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/responses_server/tools/web_search.py +0 -0
- {python_codex-0.4.7 → python_codex-0.5.0}/responses_server/trajectory_dump.py +0 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: python-codex
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: A minimal Python extraction of Codex's main agent loop
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Python: >=3.6.2
|
|
7
|
+
Requires-Dist: dataclasses>=0.8; python_version < '3.7'
|
|
8
|
+
Requires-Dist: importlib-metadata>=4.8.3; python_version < '3.8'
|
|
9
|
+
Requires-Dist: loguru>=0.7.3
|
|
10
|
+
Requires-Dist: prompt-toolkit>=3.0.36
|
|
11
|
+
Requires-Dist: pyyaml>=6.0
|
|
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'
|
|
15
|
+
Requires-Dist: tomli<2,>=1.2.3; python_version < '3.11'
|
|
16
|
+
Requires-Dist: typing-extensions>=4.1.1; python_version < '3.8'
|
|
17
|
+
Requires-Dist: uvicorn<0.17,>=0.16.0; python_version < '3.7'
|
|
18
|
+
Requires-Dist: uvicorn>=0.16.0; python_version >= '3.7'
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# pycodex
|
|
22
|
+
|
|
23
|
+
[中文](README_ZH.md)
|
|
24
|
+
|
|
25
|
+
pycodex brings the [Codex](https://github.com/openai/codex) agent loop to Python,
|
|
26
|
+
with a CLI, reusable Agent API and browser workspace. It aims to follow upstream
|
|
27
|
+
behavior; supported features and deliberate differences are documented in
|
|
28
|
+
[Alignment](docs/ALIGNMENT.md).
|
|
29
|
+
|
|
30
|
+
| Package | Provides | Python |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| `python-codex` | Agent, runtime, CLI, tools, Responses compatibility server and portable storage | 3.6.2+ |
|
|
33
|
+
| `pycodex-ws` | Browser workspace, Canvas, file/diff viewers and optional Feishu integration | 3.7+ |
|
|
34
|
+
|
|
35
|
+
The workspace package installs the matching core version. Python imports use
|
|
36
|
+
`pycodex`; the commands are `pycodex` and `pycodex-ws`.
|
|
37
|
+
|
|
38
|
+
## Install and run
|
|
39
|
+
|
|
40
|
+
Install the core CLI:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
python3 -m pip install python-codex
|
|
44
|
+
pycodex
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Or install the browser workspace, which includes core:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
python3 -m pip install pycodex-ws
|
|
51
|
+
pycodex-ws --help
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Use `python3 -m pip install --upgrade pycodex-ws` to upgrade both packages
|
|
55
|
+
together. If a command is missing from `PATH`, use `python3 -m pycodex` or
|
|
56
|
+
`python3 -m workspace_server` with the interpreter used for installation.
|
|
57
|
+
|
|
58
|
+
## Model configuration
|
|
59
|
+
|
|
60
|
+
pycodex reads `~/.codex/config.toml` and the adjacent `.env`. Configure `model`,
|
|
61
|
+
`model_provider`, and the provider's `base_url` and `env_key` as needed.
|
|
62
|
+
The built-in `openai` provider uses `OPENAI_API_KEY`. Authentication uses API
|
|
63
|
+
keys; ChatGPT sign-in credentials from `auth.json` or the OS keychain are not
|
|
64
|
+
loaded.
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pycodex --profile my_profile "Summarize this repository."
|
|
68
|
+
pycodex --config /path/to/config.toml
|
|
69
|
+
pycodex doctor
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Models use the streaming Responses API. For a Chat Completions backend, set
|
|
73
|
+
`use_chat_completion = true` in its provider table. Other backend options include:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pycodex --vllm-endpoint http://127.0.0.1:18000
|
|
77
|
+
pycodex --profile my_profile --use-messages
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
See [context and configuration](docs/CONTEXT.md) and the
|
|
81
|
+
[Responses compatibility server](docs/responses_server/README.md).
|
|
82
|
+
|
|
83
|
+
## CLI
|
|
84
|
+
|
|
85
|
+
Run `pycodex` without a prompt for an interactive session, or supply a prompt
|
|
86
|
+
for a single turn:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pycodex "Summarize this repository in one sentence."
|
|
90
|
+
printf 'Reply with exactly OK.' | pycodex
|
|
91
|
+
pycodex --json "Reply with exactly OK."
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
| Command | Purpose |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| `/model`, `/effort` | Show or change the model and reasoning effort |
|
|
97
|
+
| `/cd <directory>` | Change the session's working directory while idle |
|
|
98
|
+
| `/title`, `/history` | Manage the title and inspect conversation history |
|
|
99
|
+
| `/resume` | List saved sessions; pass an index or session UUID to resume |
|
|
100
|
+
| `/compact` | Summarize history to free context |
|
|
101
|
+
| `/fork` | Continue the current history under a new session ID |
|
|
102
|
+
| `/queue <message>` | Wait for the active turn to finish before submitting |
|
|
103
|
+
|
|
104
|
+
Ordinary input during a turn steers at the next safe sampling boundary.
|
|
105
|
+
Sessions are saved under `CODEX_HOME/sessions`. Set
|
|
106
|
+
`model_auto_compact_token_limit` in the configuration to compact automatically.
|
|
107
|
+
|
|
108
|
+
Ctrl+D or Ctrl+C closes the CLI after accepted work finishes. A second Ctrl+C
|
|
109
|
+
during closing exits immediately. Use `pycodex --help` for startup options.
|
|
110
|
+
|
|
111
|
+
## Browser workspace
|
|
112
|
+
|
|
113
|
+
Create `workspaces.json`:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"workspaces": [
|
|
118
|
+
{"id": "demo", "work_dir": ".", "state_path": "demo", "enable_board": true}
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
pycodex-ws --listen 127.0.0.1:6007 --workspace-config workspaces.json
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Open `http://127.0.0.1:6007`. The workspace combines conversations with a live
|
|
128
|
+
HTML Canvas and read-only file/diff viewers. Click file links in replies to open
|
|
129
|
+
them, and use **Insert into chat** to add selected code to an editable draft.
|
|
130
|
+
Keep the server's stdin open: EOF initiates shutdown.
|
|
131
|
+
The gear button starts an Agent conversation for customizing the interface
|
|
132
|
+
through files in `~/.pycodex/frontend/`.
|
|
133
|
+
|
|
134
|
+
See the [workspace guide](packages/pycodex-ws/README.md) for session controls,
|
|
135
|
+
storage and Feishu setup. The separately distributed
|
|
136
|
+
[VS Code extension](packages/pycodex-ws/extensions/vscode/README.md) uses the same
|
|
137
|
+
workspace backend, including on Remote SSH hosts.
|
|
138
|
+
|
|
139
|
+
## Python API
|
|
140
|
+
|
|
141
|
+
Use the standard model and tool setup from Python:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from pycodex.bootstrap import build_agent, build_model
|
|
145
|
+
|
|
146
|
+
agent = build_agent(build_model())
|
|
147
|
+
try:
|
|
148
|
+
result = agent.ask("Summarize this repository in one sentence.")
|
|
149
|
+
print(result.output_text)
|
|
150
|
+
finally:
|
|
151
|
+
agent.shutdown()
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
For custom integrations, `Agent` accepts a model client, `ToolRegistry` and
|
|
155
|
+
`ContextConfig`. `await agent.run_turn([...])` runs an asynchronous turn;
|
|
156
|
+
`AgentRuntime` adds input queues, commands and frontend subscriptions.
|
|
157
|
+
See [runtime contracts and examples](docs/RUNTIME.md).
|
|
158
|
+
|
|
159
|
+
## Portable configuration
|
|
160
|
+
|
|
161
|
+
Portable mode transfers an encrypted bundle of your configuration, instructions
|
|
162
|
+
and skills to another machine. Start a storage service in a separate terminal:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
python3 -m pycodex.portable.server --root .tmp/pycodex_storage --host 127.0.0.1 --port 5577
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Upload the default Codex home, or specify another directory:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
pycodex --put @127.0.0.1:5577
|
|
172
|
+
pycodex --put /path/to/.codex/@127.0.0.1:5577
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
After verifying a download round trip, the command prints a reusable
|
|
176
|
+
`pycodex --call ...` command. Run it on the target machine using a storage
|
|
177
|
+
address reachable from that machine.
|
|
178
|
+
|
|
179
|
+
## Development and reference
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
uv sync --dev
|
|
183
|
+
uv run pycodex
|
|
184
|
+
uv run --dev pytest
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
- [Test environments and coverage](tests/TESTS.md)
|
|
188
|
+
- [Architecture, package layout and runtime contracts](docs/RUNTIME.md)
|
|
189
|
+
- [Prompts, configuration and context](docs/CONTEXT.md)
|
|
190
|
+
- [Upstream alignment](docs/ALIGNMENT.md)
|
|
191
|
+
- [Responses compatibility server](docs/responses_server/README.md)
|
|
192
|
+
|
|
193
|
+
Release notes and implementation details live in `docs/`.
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# pycodex
|
|
2
|
+
|
|
3
|
+
[中文](README_ZH.md)
|
|
4
|
+
|
|
5
|
+
pycodex brings the [Codex](https://github.com/openai/codex) agent loop to Python,
|
|
6
|
+
with a CLI, reusable Agent API and browser workspace. It aims to follow upstream
|
|
7
|
+
behavior; supported features and deliberate differences are documented in
|
|
8
|
+
[Alignment](docs/ALIGNMENT.md).
|
|
9
|
+
|
|
10
|
+
| Package | Provides | Python |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| `python-codex` | Agent, runtime, CLI, tools, Responses compatibility server and portable storage | 3.6.2+ |
|
|
13
|
+
| `pycodex-ws` | Browser workspace, Canvas, file/diff viewers and optional Feishu integration | 3.7+ |
|
|
14
|
+
|
|
15
|
+
The workspace package installs the matching core version. Python imports use
|
|
16
|
+
`pycodex`; the commands are `pycodex` and `pycodex-ws`.
|
|
17
|
+
|
|
18
|
+
## Install and run
|
|
19
|
+
|
|
20
|
+
Install the core CLI:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
python3 -m pip install python-codex
|
|
24
|
+
pycodex
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Or install the browser workspace, which includes core:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
python3 -m pip install pycodex-ws
|
|
31
|
+
pycodex-ws --help
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Use `python3 -m pip install --upgrade pycodex-ws` to upgrade both packages
|
|
35
|
+
together. If a command is missing from `PATH`, use `python3 -m pycodex` or
|
|
36
|
+
`python3 -m workspace_server` with the interpreter used for installation.
|
|
37
|
+
|
|
38
|
+
## Model configuration
|
|
39
|
+
|
|
40
|
+
pycodex reads `~/.codex/config.toml` and the adjacent `.env`. Configure `model`,
|
|
41
|
+
`model_provider`, and the provider's `base_url` and `env_key` as needed.
|
|
42
|
+
The built-in `openai` provider uses `OPENAI_API_KEY`. Authentication uses API
|
|
43
|
+
keys; ChatGPT sign-in credentials from `auth.json` or the OS keychain are not
|
|
44
|
+
loaded.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pycodex --profile my_profile "Summarize this repository."
|
|
48
|
+
pycodex --config /path/to/config.toml
|
|
49
|
+
pycodex doctor
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Models use the streaming Responses API. For a Chat Completions backend, set
|
|
53
|
+
`use_chat_completion = true` in its provider table. Other backend options include:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pycodex --vllm-endpoint http://127.0.0.1:18000
|
|
57
|
+
pycodex --profile my_profile --use-messages
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
See [context and configuration](docs/CONTEXT.md) and the
|
|
61
|
+
[Responses compatibility server](docs/responses_server/README.md).
|
|
62
|
+
|
|
63
|
+
## CLI
|
|
64
|
+
|
|
65
|
+
Run `pycodex` without a prompt for an interactive session, or supply a prompt
|
|
66
|
+
for a single turn:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pycodex "Summarize this repository in one sentence."
|
|
70
|
+
printf 'Reply with exactly OK.' | pycodex
|
|
71
|
+
pycodex --json "Reply with exactly OK."
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
| Command | Purpose |
|
|
75
|
+
| --- | --- |
|
|
76
|
+
| `/model`, `/effort` | Show or change the model and reasoning effort |
|
|
77
|
+
| `/cd <directory>` | Change the session's working directory while idle |
|
|
78
|
+
| `/title`, `/history` | Manage the title and inspect conversation history |
|
|
79
|
+
| `/resume` | List saved sessions; pass an index or session UUID to resume |
|
|
80
|
+
| `/compact` | Summarize history to free context |
|
|
81
|
+
| `/fork` | Continue the current history under a new session ID |
|
|
82
|
+
| `/queue <message>` | Wait for the active turn to finish before submitting |
|
|
83
|
+
|
|
84
|
+
Ordinary input during a turn steers at the next safe sampling boundary.
|
|
85
|
+
Sessions are saved under `CODEX_HOME/sessions`. Set
|
|
86
|
+
`model_auto_compact_token_limit` in the configuration to compact automatically.
|
|
87
|
+
|
|
88
|
+
Ctrl+D or Ctrl+C closes the CLI after accepted work finishes. A second Ctrl+C
|
|
89
|
+
during closing exits immediately. Use `pycodex --help` for startup options.
|
|
90
|
+
|
|
91
|
+
## Browser workspace
|
|
92
|
+
|
|
93
|
+
Create `workspaces.json`:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"workspaces": [
|
|
98
|
+
{"id": "demo", "work_dir": ".", "state_path": "demo", "enable_board": true}
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
pycodex-ws --listen 127.0.0.1:6007 --workspace-config workspaces.json
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Open `http://127.0.0.1:6007`. The workspace combines conversations with a live
|
|
108
|
+
HTML Canvas and read-only file/diff viewers. Click file links in replies to open
|
|
109
|
+
them, and use **Insert into chat** to add selected code to an editable draft.
|
|
110
|
+
Keep the server's stdin open: EOF initiates shutdown.
|
|
111
|
+
The gear button starts an Agent conversation for customizing the interface
|
|
112
|
+
through files in `~/.pycodex/frontend/`.
|
|
113
|
+
|
|
114
|
+
See the [workspace guide](packages/pycodex-ws/README.md) for session controls,
|
|
115
|
+
storage and Feishu setup. The separately distributed
|
|
116
|
+
[VS Code extension](packages/pycodex-ws/extensions/vscode/README.md) uses the same
|
|
117
|
+
workspace backend, including on Remote SSH hosts.
|
|
118
|
+
|
|
119
|
+
## Python API
|
|
120
|
+
|
|
121
|
+
Use the standard model and tool setup from Python:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from pycodex.bootstrap import build_agent, build_model
|
|
125
|
+
|
|
126
|
+
agent = build_agent(build_model())
|
|
127
|
+
try:
|
|
128
|
+
result = agent.ask("Summarize this repository in one sentence.")
|
|
129
|
+
print(result.output_text)
|
|
130
|
+
finally:
|
|
131
|
+
agent.shutdown()
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
For custom integrations, `Agent` accepts a model client, `ToolRegistry` and
|
|
135
|
+
`ContextConfig`. `await agent.run_turn([...])` runs an asynchronous turn;
|
|
136
|
+
`AgentRuntime` adds input queues, commands and frontend subscriptions.
|
|
137
|
+
See [runtime contracts and examples](docs/RUNTIME.md).
|
|
138
|
+
|
|
139
|
+
## Portable configuration
|
|
140
|
+
|
|
141
|
+
Portable mode transfers an encrypted bundle of your configuration, instructions
|
|
142
|
+
and skills to another machine. Start a storage service in a separate terminal:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
python3 -m pycodex.portable.server --root .tmp/pycodex_storage --host 127.0.0.1 --port 5577
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Upload the default Codex home, or specify another directory:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
pycodex --put @127.0.0.1:5577
|
|
152
|
+
pycodex --put /path/to/.codex/@127.0.0.1:5577
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
After verifying a download round trip, the command prints a reusable
|
|
156
|
+
`pycodex --call ...` command. Run it on the target machine using a storage
|
|
157
|
+
address reachable from that machine.
|
|
158
|
+
|
|
159
|
+
## Development and reference
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
uv sync --dev
|
|
163
|
+
uv run pycodex
|
|
164
|
+
uv run --dev pytest
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
- [Test environments and coverage](tests/TESTS.md)
|
|
168
|
+
- [Architecture, package layout and runtime contracts](docs/RUNTIME.md)
|
|
169
|
+
- [Prompts, configuration and context](docs/CONTEXT.md)
|
|
170
|
+
- [Upstream alignment](docs/ALIGNMENT.md)
|
|
171
|
+
- [Responses compatibility server](docs/responses_server/README.md)
|
|
172
|
+
|
|
173
|
+
Release notes and implementation details live in `docs/`.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# pycodex
|
|
2
|
+
|
|
3
|
+
[English](README.md)
|
|
4
|
+
|
|
5
|
+
pycodex 用 Python 实现 [Codex](https://github.com/openai/codex) 的 Agent 主循环,
|
|
6
|
+
提供 CLI、可复用的 Agent API 和浏览器工作区。项目以对齐上游行为为目标;
|
|
7
|
+
支持范围和刻意保留的差异见[对齐文档](docs/ALIGNMENT.md)。
|
|
8
|
+
|
|
9
|
+
| 包 | 内容 | Python |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| `python-codex` | Agent、Runtime、CLI、工具、Responses 兼容服务和 portable 存储 | 3.6.2+ |
|
|
12
|
+
| `pycodex-ws` | 浏览器工作区、Canvas、文件/diff 查看器和可选飞书集成 | 3.7+ |
|
|
13
|
+
|
|
14
|
+
workspace 包会安装匹配版本的 core。Python 导入路径为 `pycodex`,
|
|
15
|
+
命令为 `pycodex` 和 `pycodex-ws`。
|
|
16
|
+
|
|
17
|
+
## 安装与启动
|
|
18
|
+
|
|
19
|
+
安装核心 CLI:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
python3 -m pip install python-codex
|
|
23
|
+
pycodex
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
也可以安装包含 core 的浏览器工作区:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
python3 -m pip install pycodex-ws
|
|
30
|
+
pycodex-ws --help
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
使用 `python3 -m pip install --upgrade pycodex-ws` 一起升级两个包。
|
|
34
|
+
如果命令不在 `PATH` 中,用安装时的解释器运行 `python3 -m pycodex`
|
|
35
|
+
或 `python3 -m workspace_server`。
|
|
36
|
+
|
|
37
|
+
## 模型配置
|
|
38
|
+
|
|
39
|
+
默认读取 `~/.codex/config.toml` 和同目录的 `.env`。根据需要配置 `model`、
|
|
40
|
+
`model_provider` 及 provider 的 `base_url`、`env_key`。
|
|
41
|
+
内置 `openai` provider 使用 `OPENAI_API_KEY`。认证使用 API key,
|
|
42
|
+
不读取 `auth.json` 或系统钥匙串中的 ChatGPT 登录凭据。
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pycodex --profile my_profile "概括这个仓库。"
|
|
46
|
+
pycodex --config /path/to/config.toml
|
|
47
|
+
pycodex doctor
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
默认使用流式 Responses API。接入 Chat Completions 后端时,在对应 provider
|
|
51
|
+
配置中设置 `use_chat_completion = true`。其他后端入口包括:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pycodex --vllm-endpoint http://127.0.0.1:18000
|
|
55
|
+
pycodex --profile my_profile --use-messages
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
详见[配置与上下文](docs/CONTEXT.md)和
|
|
59
|
+
[Responses 兼容服务](docs/responses_server/README.md)。
|
|
60
|
+
|
|
61
|
+
## CLI
|
|
62
|
+
|
|
63
|
+
不带 prompt 时进入交互会话,也可以直接运行单轮任务:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pycodex "用一句话概括这个仓库。"
|
|
67
|
+
printf 'Reply with exactly OK.' | pycodex
|
|
68
|
+
pycodex --json "Reply with exactly OK."
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
| 命令 | 用途 |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `/model`、`/effort` | 查看或切换模型及推理强度 |
|
|
74
|
+
| `/cd <directory>` | 空闲时切换当前会话的工作目录 |
|
|
75
|
+
| `/title`、`/history` | 管理标题、查看历史 |
|
|
76
|
+
| `/resume` | 列出已保存会话;传入序号或 UUID 恢复 |
|
|
77
|
+
| `/compact` | 压缩历史,释放上下文空间 |
|
|
78
|
+
| `/fork` | 保留当前历史,以新会话 ID 继续 |
|
|
79
|
+
| `/queue <message>` | 等当前 turn 完成后再执行 |
|
|
80
|
+
|
|
81
|
+
运行中提交普通输入,会在下一个安全采样边界插入。会话保存在
|
|
82
|
+
`CODEX_HOME/sessions`;配置 `model_auto_compact_token_limit` 可启用自动压缩。
|
|
83
|
+
|
|
84
|
+
Ctrl+D 或 Ctrl+C 发起退出,等待已接收任务完成;关闭等待期间再次 Ctrl+C
|
|
85
|
+
立即退出。完整启动参数见 `pycodex --help`。
|
|
86
|
+
|
|
87
|
+
## 浏览器工作区
|
|
88
|
+
|
|
89
|
+
创建 `workspaces.json`:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"workspaces": [
|
|
94
|
+
{"id": "demo", "work_dir": ".", "state_path": "demo", "enable_board": true}
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pycodex-ws --listen 127.0.0.1:6007 --workspace-config workspaces.json
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
访问 `http://127.0.0.1:6007`。工作区同时提供对话、实时 HTML Canvas 和只读
|
|
104
|
+
文件/diff 查看器。点击回复中的文件链接打开视图,通过 **Insert into chat**
|
|
105
|
+
把选中的代码插入可编辑草稿。运行期间保持服务器 stdin 打开,EOF 会触发关闭。
|
|
106
|
+
点击齿轮按钮可开启界面定制会话,让 Agent 修改 `~/.pycodex/frontend/` 中的文件。
|
|
107
|
+
|
|
108
|
+
会话操作、存储和飞书配置见[工作区说明](packages/pycodex-ws/README.md)。
|
|
109
|
+
独立分发的 [VS Code 扩展](packages/pycodex-ws/extensions/vscode/README.md)
|
|
110
|
+
复用同一后端,支持 Remote SSH 工作区。
|
|
111
|
+
|
|
112
|
+
## Python API
|
|
113
|
+
|
|
114
|
+
在 Python 中复用标准模型和工具装配:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from pycodex.bootstrap import build_agent, build_model
|
|
118
|
+
|
|
119
|
+
agent = build_agent(build_model())
|
|
120
|
+
try:
|
|
121
|
+
result = agent.ask("用一句话概括这个仓库。")
|
|
122
|
+
print(result.output_text)
|
|
123
|
+
finally:
|
|
124
|
+
agent.shutdown()
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
自定义集成时,`Agent` 接收 model client、`ToolRegistry` 和 `ContextConfig`。
|
|
128
|
+
通过 `await agent.run_turn([...])` 异步运行 turn;`AgentRuntime` 提供输入队列、
|
|
129
|
+
会话命令和前端订阅。详见[运行时契约与示例](docs/RUNTIME.md)。
|
|
130
|
+
|
|
131
|
+
## Portable 配置
|
|
132
|
+
|
|
133
|
+
Portable mode 将配置、指令和 skills 加密打包,供其他机器恢复使用。
|
|
134
|
+
先在单独的终端启动存储服务:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
python3 -m pycodex.portable.server --root .tmp/pycodex_storage --host 127.0.0.1 --port 5577
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
上传默认 Codex home,或指定其他目录:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
pycodex --put @127.0.0.1:5577
|
|
144
|
+
pycodex --put /path/to/.codex/@127.0.0.1:5577
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
上传并验证下载成功后,命令会打印可复用的 `pycodex --call ...` 启动命令。
|
|
148
|
+
在目标机器运行时,使用该机器能够访问的存储服务地址。
|
|
149
|
+
|
|
150
|
+
## 开发与参考
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
uv sync --dev
|
|
154
|
+
uv run pycodex
|
|
155
|
+
uv run --dev pytest
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- [测试环境与覆盖范围](tests/TESTS.md)
|
|
159
|
+
- [架构、包布局与运行时契约](docs/RUNTIME.md)
|
|
160
|
+
- [提示、配置与上下文](docs/CONTEXT.md)
|
|
161
|
+
- [上游对齐](docs/ALIGNMENT.md)
|
|
162
|
+
- [Responses 兼容服务](docs/responses_server/README.md)
|
|
163
|
+
|
|
164
|
+
发布记录和实现细节放在 `docs/`。
|
|
@@ -152,6 +152,13 @@ class Agent:
|
|
|
152
152
|
self.context_manager.set_model(model)
|
|
153
153
|
self._last_total_usage_tokens = None
|
|
154
154
|
|
|
155
|
+
def set_cwd(self, cwd: "typing.Union[str, Path]") -> "None":
|
|
156
|
+
if self.is_running:
|
|
157
|
+
raise RuntimeError("cannot change directory while agent is running")
|
|
158
|
+
if not self.accepts_input:
|
|
159
|
+
raise RuntimeError("cannot change directory while agent is closing or closed")
|
|
160
|
+
self.context_manager.set_cwd(cwd)
|
|
161
|
+
|
|
155
162
|
def resume(
|
|
156
163
|
self, session_file_path: "typing.Union[str, Path, None]" = None
|
|
157
164
|
) -> "typing.Union[typing.Dict[str, object], None]":
|
|
@@ -400,6 +407,7 @@ class Agent:
|
|
|
400
407
|
context = ToolContext(
|
|
401
408
|
turn_id=turn_id,
|
|
402
409
|
history=self.history,
|
|
410
|
+
cwd=self.context_manager.cwd,
|
|
403
411
|
)
|
|
404
412
|
if len(batch) == 1:
|
|
405
413
|
results.append(await self._run_single_tool(turn_id, batch[0], context))
|
|
@@ -86,7 +86,6 @@ def configure_loguru() -> "None":
|
|
|
86
86
|
def get_tools(
|
|
87
87
|
runtime_environment: "typing.Union[AgentRuntimeEnvironment, None]" = None,
|
|
88
88
|
exec_mode: "bool" = False,
|
|
89
|
-
cwd: "typing.Union[str, Path, None]" = None,
|
|
90
89
|
toolset: "typing.Union[typing.Iterable[str], None]" = None,
|
|
91
90
|
):
|
|
92
91
|
from .tools import (
|
|
@@ -119,8 +118,8 @@ def get_tools(
|
|
|
119
118
|
|
|
120
119
|
runtime_environment = runtime_environment or create_agent_runtime_environment()
|
|
121
120
|
registry = Registry(runtime_environment)
|
|
122
|
-
code_mode_manager = CodeModeManager(registry
|
|
123
|
-
unified_exec_manager = UnifiedExecManager(
|
|
121
|
+
code_mode_manager = CodeModeManager(registry)
|
|
122
|
+
unified_exec_manager = UnifiedExecManager()
|
|
124
123
|
clock_manager = ClockManager()
|
|
125
124
|
exec_tool = ExecTool(code_mode_manager)
|
|
126
125
|
wait_tool = WaitTool(code_mode_manager)
|
|
@@ -135,16 +134,16 @@ def get_tools(
|
|
|
135
134
|
resume_agent_tool = ResumeAgentTool(runtime_environment.subagent_manager)
|
|
136
135
|
wait_agent_tool = WaitAgentTool(runtime_environment.subagent_manager)
|
|
137
136
|
close_agent_tool = CloseAgentTool(runtime_environment.subagent_manager)
|
|
138
|
-
apply_patch_tool = ApplyPatchTool(
|
|
139
|
-
shell_tool = ShellTool(
|
|
140
|
-
shell_command_tool = ShellCommandTool(
|
|
137
|
+
apply_patch_tool = ApplyPatchTool()
|
|
138
|
+
shell_tool = ShellTool()
|
|
139
|
+
shell_command_tool = ShellCommandTool()
|
|
141
140
|
exec_command_tool = ExecCommandTool(unified_exec_manager)
|
|
142
141
|
write_stdin_tool = WriteStdinTool(unified_exec_manager)
|
|
143
142
|
clock_tool = ClockTool(clock_manager)
|
|
144
|
-
grep_files_tool = GrepFilesTool(
|
|
143
|
+
grep_files_tool = GrepFilesTool()
|
|
145
144
|
read_file_tool = ReadFileTool()
|
|
146
145
|
list_dir_tool = ListDirTool()
|
|
147
|
-
view_image_tool = ViewImageTool(
|
|
146
|
+
view_image_tool = ViewImageTool()
|
|
148
147
|
tools = (
|
|
149
148
|
shell_tool,
|
|
150
149
|
shell_command_tool,
|
|
@@ -200,7 +199,6 @@ def get_tools(
|
|
|
200
199
|
|
|
201
200
|
def get_subagent_tools(
|
|
202
201
|
runtime_environment: "typing.Union[AgentRuntimeEnvironment, None]" = None,
|
|
203
|
-
cwd: "typing.Union[str, Path, None]" = None,
|
|
204
202
|
):
|
|
205
203
|
from .tools import (
|
|
206
204
|
ApplyPatchTool,
|
|
@@ -215,13 +213,13 @@ def get_subagent_tools(
|
|
|
215
213
|
|
|
216
214
|
runtime_environment = runtime_environment or create_agent_runtime_environment()
|
|
217
215
|
registry = Registry(runtime_environment)
|
|
218
|
-
unified_exec_manager = UnifiedExecManager(
|
|
216
|
+
unified_exec_manager = UnifiedExecManager()
|
|
219
217
|
registry.register(ExecCommandTool(unified_exec_manager))
|
|
220
218
|
registry.register(WriteStdinTool(unified_exec_manager))
|
|
221
219
|
registry.register(UpdatePlanTool(runtime_environment.plan_store))
|
|
222
|
-
registry.register(ApplyPatchTool(
|
|
220
|
+
registry.register(ApplyPatchTool())
|
|
223
221
|
registry.register(WebSearchTool())
|
|
224
|
-
registry.register(ViewImageTool(
|
|
222
|
+
registry.register(ViewImageTool())
|
|
225
223
|
return registry
|
|
226
224
|
|
|
227
225
|
|
|
@@ -244,46 +242,41 @@ def build_agent(
|
|
|
244
242
|
)
|
|
245
243
|
runtime_environment = create_agent_runtime_environment()
|
|
246
244
|
|
|
247
|
-
def make_subagent_runtime_builder(
|
|
245
|
+
def make_subagent_runtime_builder(parent_agent):
|
|
248
246
|
def build_subagent_runtime(
|
|
249
247
|
model_override: "typing.Union[str, None]",
|
|
250
248
|
reasoning_effort_override: "typing.Union[str, None]",
|
|
251
249
|
initial_history=(),
|
|
252
250
|
session_id: "typing.Union[str, None]" = None,
|
|
253
251
|
) -> "AgentRuntime":
|
|
254
|
-
nested_client =
|
|
252
|
+
nested_client = parent_agent.model_client.with_overrides(
|
|
255
253
|
model_override,
|
|
256
254
|
reasoning_effort_override,
|
|
257
255
|
session_id=session_id,
|
|
258
256
|
openai_subagent="collab_spawn",
|
|
259
257
|
)
|
|
260
258
|
subagent_agent_runtime_environment = create_agent_runtime_environment()
|
|
261
|
-
|
|
262
|
-
make_subagent_runtime_builder(nested_client)
|
|
263
|
-
)
|
|
259
|
+
inherited_cwd = parent_agent.context_manager.cwd
|
|
264
260
|
sub_agent = Agent(
|
|
265
261
|
nested_client,
|
|
266
|
-
get_subagent_tools(
|
|
267
|
-
|
|
268
|
-
),
|
|
269
|
-
context_config,
|
|
262
|
+
get_subagent_tools(subagent_agent_runtime_environment),
|
|
263
|
+
replace(context_config, cwd=inherited_cwd),
|
|
270
264
|
initial_history=tuple(initial_history),
|
|
271
265
|
session_id=session_id,
|
|
272
266
|
)
|
|
267
|
+
subagent_agent_runtime_environment.subagent_manager.set_runtime_builder(
|
|
268
|
+
make_subagent_runtime_builder(sub_agent)
|
|
269
|
+
)
|
|
273
270
|
return AgentRuntime(sub_agent)
|
|
274
271
|
|
|
275
272
|
return build_subagent_runtime
|
|
276
273
|
|
|
277
|
-
runtime_environment.subagent_manager.set_runtime_builder(
|
|
278
|
-
make_subagent_runtime_builder(client)
|
|
279
|
-
)
|
|
280
274
|
session_id = uuid7_string()
|
|
281
|
-
|
|
275
|
+
agent = Agent(
|
|
282
276
|
client,
|
|
283
277
|
get_tools(
|
|
284
278
|
runtime_environment,
|
|
285
279
|
exec_mode=True,
|
|
286
|
-
cwd=resolved_cwd,
|
|
287
280
|
toolset=toolset,
|
|
288
281
|
),
|
|
289
282
|
context_config,
|
|
@@ -292,6 +285,10 @@ def build_agent(
|
|
|
292
285
|
),
|
|
293
286
|
session_id=session_id,
|
|
294
287
|
)
|
|
288
|
+
runtime_environment.subagent_manager.set_runtime_builder(
|
|
289
|
+
make_subagent_runtime_builder(agent)
|
|
290
|
+
)
|
|
291
|
+
return agent
|
|
295
292
|
|
|
296
293
|
|
|
297
294
|
def build_model(
|