python-codex 0.4.0__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.
- pycodex/runtime.py +1 -1
- pycodex/utils/async_bridge.py +3 -4
- pycodex/utils/session_persist.py +28 -0
- {python_codex-0.4.0.dist-info → python_codex-0.4.1.dist-info}/METADATA +14 -10
- {python_codex-0.4.0.dist-info → python_codex-0.4.1.dist-info}/RECORD +8 -8
- {python_codex-0.4.0.dist-info → python_codex-0.4.1.dist-info}/WHEEL +0 -0
- {python_codex-0.4.0.dist-info → python_codex-0.4.1.dist-info}/entry_points.txt +0 -0
- {python_codex-0.4.0.dist-info → python_codex-0.4.1.dist-info}/licenses/LICENSE +0 -0
pycodex/runtime.py
CHANGED
|
@@ -307,7 +307,7 @@ class AgentRuntime:
|
|
|
307
307
|
if not self.agent.history:
|
|
308
308
|
return {"kind": "compact_empty"}
|
|
309
309
|
result = await self.agent.compact()
|
|
310
|
-
self.publish_state("
|
|
310
|
+
self.publish_state("compacted")
|
|
311
311
|
return {
|
|
312
312
|
"kind": "compacted",
|
|
313
313
|
"original_item_count": result.original_item_count,
|
pycodex/utils/async_bridge.py
CHANGED
|
@@ -5,10 +5,9 @@ import inspect
|
|
|
5
5
|
def run_async(awaitable):
|
|
6
6
|
"""Run an awaitable from synchronous code and return its real result.
|
|
7
7
|
|
|
8
|
-
This helper
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
failure instead of swallowing exceptions.
|
|
8
|
+
This helper lets synchronous callers use async agent APIs without
|
|
9
|
+
managing the event loop themselves. It returns the underlying result
|
|
10
|
+
directly and propagates exceptions.
|
|
12
11
|
"""
|
|
13
12
|
try:
|
|
14
13
|
running_loop = asyncio.get_running_loop()
|
pycodex/utils/session_persist.py
CHANGED
|
@@ -3,6 +3,7 @@ import mmap
|
|
|
3
3
|
import os
|
|
4
4
|
import re
|
|
5
5
|
import typing
|
|
6
|
+
from collections import deque
|
|
6
7
|
from contextlib import closing
|
|
7
8
|
from datetime import datetime
|
|
8
9
|
from pathlib import Path
|
|
@@ -323,6 +324,33 @@ def conversation_history_to_turns(
|
|
|
323
324
|
return tuple(turns)
|
|
324
325
|
|
|
325
326
|
|
|
327
|
+
def load_display_history(
|
|
328
|
+
rollout_path: "typing.Union[str, Path]",
|
|
329
|
+
limit: "int" = 80,
|
|
330
|
+
) -> "typing.Tuple[typing.Union[typing.Tuple[str, str], None], ...]":
|
|
331
|
+
"""Read visible turns across checkpoints; None marks a compaction."""
|
|
332
|
+
path = Path(rollout_path).expanduser().resolve()
|
|
333
|
+
turns = deque(maxlen=limit)
|
|
334
|
+
for entry in _iter_rollout_entries(path):
|
|
335
|
+
item_type = entry.get("type")
|
|
336
|
+
payload = entry.get("payload")
|
|
337
|
+
if not isinstance(payload, dict):
|
|
338
|
+
continue
|
|
339
|
+
if item_type == "compacted":
|
|
340
|
+
turns.append(None)
|
|
341
|
+
elif item_type == "event_msg" and payload.get("type") == "user_message":
|
|
342
|
+
turns.append((str(payload.get("message", "")), ""))
|
|
343
|
+
elif (
|
|
344
|
+
item_type == "response_item"
|
|
345
|
+
and payload.get("type") == "message"
|
|
346
|
+
and payload.get("role") == "assistant"
|
|
347
|
+
):
|
|
348
|
+
if not turns or turns[-1] is None:
|
|
349
|
+
turns.append(("", ""))
|
|
350
|
+
turns[-1] = (turns[-1][0], _extract_response_message_text(payload))
|
|
351
|
+
return tuple(turns)
|
|
352
|
+
|
|
353
|
+
|
|
326
354
|
def _drop_unmatched_tool_calls(
|
|
327
355
|
history: "typing.List[ConversationItem]",
|
|
328
356
|
) -> "typing.List[ConversationItem]":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-codex
|
|
3
|
-
Version: 0.4.
|
|
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
|
|
@@ -40,10 +40,14 @@ The import path remains `pycodex`; the CLI commands are `pycodex` and
|
|
|
40
40
|
|
|
41
41
|
`python-codex` contains the Agent, runtime, CLI, standard tools, Responses
|
|
42
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
|
-
|
|
43
|
+
exact matching core version and contains the browser workspace, viewer assets
|
|
44
|
+
and optional Feishu integration. It owns the
|
|
45
45
|
`workspace_server` and `pycodex_ws` modules and the `pycodex-ws` command.
|
|
46
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
|
+
|
|
47
51
|
Core does not require Pillow. Without it, `view_image` sends the original image
|
|
48
52
|
bytes with `detail="original"`, including when `high` is requested. With Pillow
|
|
49
53
|
installed, the default path retains resizing to a maximum dimension of 2048.
|
|
@@ -78,7 +82,7 @@ Relevant Rust reference points:
|
|
|
78
82
|
|
|
79
83
|
## Quick Start
|
|
80
84
|
|
|
81
|
-
Install the core CLI, or install the workspace package
|
|
85
|
+
Install the core CLI, or install the workspace package for the browser frontend:
|
|
82
86
|
|
|
83
87
|
```bash
|
|
84
88
|
python3 -m pip install python-codex
|
|
@@ -86,7 +90,7 @@ python3 -m pip install pycodex-ws
|
|
|
86
90
|
```
|
|
87
91
|
|
|
88
92
|
The core supports Python 3.6.2 or newer. The workspace package requires Python
|
|
89
|
-
3.7 or newer
|
|
93
|
+
3.7 or newer. Commands are installed into
|
|
90
94
|
that interpreter's scripts directory. On a machine with multiple Python
|
|
91
95
|
installations, select the same interpreter explicitly for startup:
|
|
92
96
|
|
|
@@ -118,7 +122,7 @@ uv run pycodex
|
|
|
118
122
|
|
|
119
123
|
Tests are split by package. `uv run --dev pytest` runs both suites;
|
|
120
124
|
`uv run --dev pytest packages/pycodex-ws/tests` runs workspace and integration
|
|
121
|
-
tests. To check core without installing workspace
|
|
125
|
+
tests. To check core without installing workspace, use a separate
|
|
122
126
|
environment:
|
|
123
127
|
|
|
124
128
|
```bash
|
|
@@ -202,7 +206,7 @@ Supporting services live in `tools/`, `portable/` and `utils/`.
|
|
|
202
206
|
- `pycodex/utils/image_utils.py`: image loading, resizing and data-URL preparation
|
|
203
207
|
- `pycodex/prompts/`: vendored prompts and model metadata
|
|
204
208
|
- `packages/pycodex-ws/workspace_server/`: Web board, API and file/diff viewers
|
|
205
|
-
- `packages/pycodex-ws/pycodex_ws/`: Feishu
|
|
209
|
+
- `packages/pycodex-ws/pycodex_ws/`: Feishu and workspace assembly
|
|
206
210
|
- `packages/pycodex-ws/extensions/vscode/`: workspace's VS Code frontend, built separately as a VSIX
|
|
207
211
|
- `tests/`: core tests
|
|
208
212
|
- `packages/pycodex-ws/tests/`: workspace and cross-frontend integration tests
|
|
@@ -414,7 +418,8 @@ Current behavior:
|
|
|
414
418
|
user instruction; this is intended for side-effect follow-ups such as
|
|
415
419
|
Feishu notifications
|
|
416
420
|
- `/link <feishu-email|open_id|chat_id>` in a workspace session attaches it
|
|
417
|
-
to a Feishu card
|
|
421
|
+
to a Feishu card when the optional `lark-oapi` SDK can be imported;
|
|
422
|
+
multiple sessions in the same workspace process share
|
|
418
423
|
one Feishu long-connection listener and route card actions by message id
|
|
419
424
|
- Feishu user OAuth stores its refresh token only in
|
|
420
425
|
`~/.codex/.feishu_refresh_token` (mode `0600`). Run
|
|
@@ -735,8 +740,7 @@ CLI, Web and Feishu all use `AgentRuntime.submit_input`: not just `/model`
|
|
|
735
740
|
and `/resume`, but every session command, steer/queue admission, interactive
|
|
736
741
|
questions and permissions, state notifications and shutdown. Frontends only
|
|
737
742
|
adapt input and render events. Web no longer imports or runs the CLI shell.
|
|
738
|
-
|
|
739
|
-
a bare Agent. Workspace assembly uses `pycodex_ws.build_runtime()` to add
|
|
743
|
+
Workspace assembly uses `pycodex_ws.build_runtime()` to add
|
|
740
744
|
`/link` and `/unlink`; `pycodex.bootstrap.build_runtime()` provides core commands.
|
|
741
745
|
|
|
742
746
|
```python
|
|
@@ -7,7 +7,7 @@ pycodex/context.py,sha256=yfNY2alT3caQQwhay47pSSrGUbgEAcLKhTVaZqtQ4yU,26610
|
|
|
7
7
|
pycodex/events.py,sha256=wysYXHLiCHzW3k1yaAuoRTw90NRhHPa3jtY0ANGOqH4,29694
|
|
8
8
|
pycodex/model.py,sha256=3mWXTN-oV2Q50SgQYac45WT5Qk2NSmPTxSWyF-w8TRg,44583
|
|
9
9
|
pycodex/protocol.py,sha256=uzUz_06iA4m9vAoqZeCGiJ4SocKZDzOfCJUU4Bpt5dI,12033
|
|
10
|
-
pycodex/runtime.py,sha256=
|
|
10
|
+
pycodex/runtime.py,sha256=3wHKoNjwzOgE6dXeT6Vbpu6Nf7RWqIfHwrjsmOnk81I,23814
|
|
11
11
|
pycodex/portable/__init__.py,sha256=FmspRPmblYuZIVXMpXaxE1uosCaz2hZDpkpOzxDJQic,1084
|
|
12
12
|
pycodex/portable/client.py,sha256=DOxzZljVfN1ynmhqrChX7NsT1IFSFVKzEn1J3wvV3XQ,16038
|
|
13
13
|
pycodex/portable/server.py,sha256=w4YD71Sxb7MD5q57GPuIgx7AoicTv0R9xzX2kAaibPA,7503
|
|
@@ -50,7 +50,7 @@ pycodex/tools/wait_tool.py,sha256=0_OO_DvMsBhG3oDKZePTOjZTBq1lmWntXAzqIqvebdA,32
|
|
|
50
50
|
pycodex/tools/web_search_tool.py,sha256=3ao1IvJw7MwcP35UKLbqrM-nlm5Z-UUFVdEzkJYOV1o,988
|
|
51
51
|
pycodex/tools/write_stdin_tool.py,sha256=jvBDchLLmoDITd7g-ZVeEVXHRhWKkmnjM5laL-53FOM,3609
|
|
52
52
|
pycodex/utils/__init__.py,sha256=ih_KyZ2_bajR5YlZ1QMTWOHnuEBda-S3gQ7PwnBtLZQ,453
|
|
53
|
-
pycodex/utils/async_bridge.py,sha256=
|
|
53
|
+
pycodex/utils/async_bridge.py,sha256=BXsKTUTUvUtPJnItQlulFRdV7opdKKDlsKLdtVTYshs,1732
|
|
54
54
|
pycodex/utils/compactor.py,sha256=0tlszw1n54aMEGH6sL1U1dEgFSU5ioYL2NI5uSvHSiM,6119
|
|
55
55
|
pycodex/utils/compat.py,sha256=QxcI4AQuUD-gE2494qPGezgm0OIX98qSHdAiof1JrlU,3550
|
|
56
56
|
pycodex/utils/crypto.py,sha256=HRCXF26Ft3S8CG2X0YpZwa8GMU9YJ0Loo8Q9PMPMcNw,1249
|
|
@@ -62,7 +62,7 @@ pycodex/utils/get_env.py,sha256=L4S8h84tkgxZKvrxY7ezTgePbXepG-yIigUTKeY6uuE,6094
|
|
|
62
62
|
pycodex/utils/image_utils.py,sha256=OUzUs0Cow4L8Z2np0EBeEUotAqqsCmRmhrV8AxZUXRw,2460
|
|
63
63
|
pycodex/utils/model_metadata.py,sha256=uK3iI4yC7Ge7yN4I1_gQYalQ4MYKddz2qMwsmQb-P80,1337
|
|
64
64
|
pycodex/utils/random_ids.py,sha256=jLTxZZ0MBbRdQOFDFWGVRjWzIo6FKSQ5ADXbQSLPp1s,379
|
|
65
|
-
pycodex/utils/session_persist.py,sha256=
|
|
65
|
+
pycodex/utils/session_persist.py,sha256=_7Lz1jO7D0Qf16UVuZBKU_Si-k_cUVinnLMlsd1jVj4,23600
|
|
66
66
|
pycodex/utils/truncation.py,sha256=5D6vAorT8EgXgjd7ASwtraAyIZdlCR-w5jKZqJxDzho,5446
|
|
67
67
|
pycodex/utils/_aes_gcm/LICENSE,sha256=KvdHagY3sYIK34GldJaRi34sNnGwMVJIIoDhbC9MRu8,2805
|
|
68
68
|
pycodex/utils/_aes_gcm/README.md,sha256=D9XGeewCgU2PVqJCO6WusUs0Mw2FbMnABCqaVktqCnE,3045
|
|
@@ -83,8 +83,8 @@ responses_server/trajectory_dump.py,sha256=5_Wy6tslszrqx3j1JeP_boyTbzIicKy8No84P
|
|
|
83
83
|
responses_server/tools/__init__.py,sha256=ivsBSEy0SBUhY-Uea5v1XMLXShkwHdCVl0id-1FwdZg,150
|
|
84
84
|
responses_server/tools/custom_adapter.py,sha256=SnIiNUdomff3APtTriURAC9YCeEdhCDjzGMEYusfUdk,8340
|
|
85
85
|
responses_server/tools/web_search.py,sha256=pnKH9JyTScRehWpZS3HpXRvjWsQvC0QZqxjEOCT4ndg,8936
|
|
86
|
-
python_codex-0.4.
|
|
87
|
-
python_codex-0.4.
|
|
88
|
-
python_codex-0.4.
|
|
89
|
-
python_codex-0.4.
|
|
90
|
-
python_codex-0.4.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|