python-codex 0.1.1__py3-none-any.whl → 0.1.3__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/__init__.py +5 -1
- pycodex/agent.py +39 -41
- pycodex/cli.py +51 -43
- pycodex/collaboration.py +6 -7
- pycodex/compat.py +99 -0
- pycodex/context.py +87 -87
- pycodex/doctor.py +40 -40
- pycodex/model.py +69 -69
- pycodex/portable.py +33 -33
- pycodex/portable_server.py +22 -21
- pycodex/protocol.py +84 -86
- pycodex/runtime.py +36 -35
- pycodex/runtime_services.py +72 -69
- pycodex/tools/agent_tool_schemas.py +0 -2
- pycodex/tools/apply_patch_tool.py +43 -44
- pycodex/tools/base_tool.py +35 -36
- pycodex/tools/close_agent_tool.py +2 -4
- pycodex/tools/code_mode_manager.py +61 -61
- pycodex/tools/exec_command_tool.py +5 -6
- pycodex/tools/exec_runtime.js +3 -3
- pycodex/tools/exec_tool.py +3 -5
- pycodex/tools/grep_files_tool.py +10 -11
- pycodex/tools/list_dir_tool.py +8 -9
- pycodex/tools/read_file_tool.py +13 -14
- pycodex/tools/request_permissions_tool.py +2 -4
- pycodex/tools/request_user_input_tool.py +13 -14
- pycodex/tools/resume_agent_tool.py +2 -4
- pycodex/tools/send_input_tool.py +8 -9
- pycodex/tools/shell_command_tool.py +5 -6
- pycodex/tools/shell_tool.py +5 -6
- pycodex/tools/spawn_agent_tool.py +4 -5
- pycodex/tools/unified_exec_manager.py +79 -61
- pycodex/tools/update_plan_tool.py +4 -5
- pycodex/tools/view_image_tool.py +4 -5
- pycodex/tools/wait_agent_tool.py +2 -4
- pycodex/tools/wait_tool.py +4 -5
- pycodex/tools/web_search_tool.py +1 -3
- pycodex/tools/write_stdin_tool.py +4 -5
- pycodex/utils/dotenv.py +6 -6
- pycodex/utils/get_env.py +57 -34
- pycodex/utils/random_ids.py +1 -2
- pycodex/utils/visualize.py +79 -79
- {python_codex-0.1.1.dist-info → python_codex-0.1.3.dist-info}/METADATA +15 -9
- python_codex-0.1.3.dist-info/RECORD +74 -0
- {python_codex-0.1.1.dist-info → python_codex-0.1.3.dist-info}/WHEEL +1 -1
- responses_server/__init__.py +17 -0
- responses_server/__main__.py +5 -0
- responses_server/app.py +227 -0
- responses_server/config.py +63 -0
- responses_server/payload_processors.py +86 -0
- responses_server/server.py +63 -0
- responses_server/session_store.py +37 -0
- responses_server/stream_router.py +784 -0
- responses_server/tools/__init__.py +4 -0
- responses_server/tools/custom_adapter.py +235 -0
- responses_server/tools/web_search.py +263 -0
- python_codex-0.1.1.dist-info/RECORD +0 -62
- {python_codex-0.1.1.dist-info → python_codex-0.1.3.dist-info}/entry_points.txt +0 -0
- {python_codex-0.1.1.dist-info → python_codex-0.1.3.dist-info}/licenses/LICENSE +0 -0
pycodex/utils/get_env.py
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import importlib.metadata
|
|
4
1
|
import os
|
|
5
2
|
import platform
|
|
6
3
|
import re
|
|
7
4
|
from datetime import datetime
|
|
8
5
|
from pathlib import Path
|
|
9
6
|
import subprocess
|
|
7
|
+
import typing
|
|
8
|
+
|
|
9
|
+
from ..compat import importlib_metadata
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def get_shell_name() -> str:
|
|
12
|
+
def get_shell_name() -> 'str':
|
|
13
13
|
shell_path = os.environ.get("SHELL")
|
|
14
14
|
if shell_path:
|
|
15
15
|
return Path(shell_path).name or shell_path
|
|
16
16
|
return "bash"
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def get_timezone_name() -> str:
|
|
19
|
+
def get_timezone_name() -> 'str':
|
|
20
20
|
timezone_env = os.environ.get("TZ")
|
|
21
21
|
if timezone_env:
|
|
22
22
|
return timezone_env
|
|
@@ -33,7 +33,7 @@ def get_timezone_name() -> str:
|
|
|
33
33
|
return "Etc/UTC"
|
|
34
34
|
name = str(timezone)
|
|
35
35
|
return name or "Etc/UTC"
|
|
36
|
-
def get_sandbox_tag(sandbox_mode: str
|
|
36
|
+
def get_sandbox_tag(sandbox_mode: 'typing.Union[str, None]') -> 'str':
|
|
37
37
|
if sandbox_mode == "danger-full-access":
|
|
38
38
|
return "none"
|
|
39
39
|
if sandbox_mode == "read-only":
|
|
@@ -43,7 +43,7 @@ def get_sandbox_tag(sandbox_mode: str | None) -> str:
|
|
|
43
43
|
return "none"
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
def get_workspace_turn_metadata(cwd: str
|
|
46
|
+
def get_workspace_turn_metadata(cwd: 'typing.Union[str, Path]') -> 'typing.Union[typing.Dict[str, object], None]':
|
|
47
47
|
resolved_cwd = Path(cwd).resolve()
|
|
48
48
|
repo_root = _git_output(
|
|
49
49
|
resolved_cwd,
|
|
@@ -52,7 +52,7 @@ def get_workspace_turn_metadata(cwd: str | Path) -> dict[str, object] | None:
|
|
|
52
52
|
if repo_root is None:
|
|
53
53
|
return None
|
|
54
54
|
|
|
55
|
-
workspace:
|
|
55
|
+
workspace: 'typing.Dict[str, object]' = {}
|
|
56
56
|
head = _git_output(resolved_cwd, ["rev-parse", "HEAD"])
|
|
57
57
|
if head is not None:
|
|
58
58
|
workspace["latest_git_commit_hash"] = head
|
|
@@ -70,7 +70,7 @@ def get_workspace_turn_metadata(cwd: str | Path) -> dict[str, object] | None:
|
|
|
70
70
|
return {"workspaces": {repo_root: workspace}}
|
|
71
71
|
|
|
72
72
|
|
|
73
|
-
def build_user_agent(originator: str) -> str:
|
|
73
|
+
def build_user_agent(originator: 'str') -> 'str':
|
|
74
74
|
version = get_package_version()
|
|
75
75
|
terminal = get_terminal_user_agent_token()
|
|
76
76
|
os_name, os_version = get_os_info()
|
|
@@ -79,20 +79,25 @@ def build_user_agent(originator: str) -> str:
|
|
|
79
79
|
return f"{originator}/{version} ({os_name} {os_version}; {arch}) {terminal}{suffix}"
|
|
80
80
|
|
|
81
81
|
|
|
82
|
-
def get_package_version() -> str:
|
|
82
|
+
def get_package_version() -> 'str':
|
|
83
83
|
detected = _detect_upstream_codex_version()
|
|
84
84
|
if detected is not None:
|
|
85
85
|
return detected
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
for distribution_name in ("python-codex", "pycodex"):
|
|
87
|
+
try:
|
|
88
|
+
return importlib_metadata.version(distribution_name)
|
|
89
|
+
except importlib_metadata.PackageNotFoundError:
|
|
90
|
+
continue
|
|
91
|
+
local_version = _read_local_package_version()
|
|
92
|
+
if local_version is not None:
|
|
93
|
+
return local_version
|
|
94
|
+
return "0.1.0"
|
|
90
95
|
|
|
91
96
|
|
|
92
|
-
def get_os_info() ->
|
|
97
|
+
def get_os_info() -> 'typing.Tuple[str, str]':
|
|
93
98
|
os_release = Path("/etc/os-release")
|
|
94
99
|
if os_release.is_file():
|
|
95
|
-
values:
|
|
100
|
+
values: 'typing.Dict[str, str]' = {}
|
|
96
101
|
for line in os_release.read_text().splitlines():
|
|
97
102
|
if "=" not in line:
|
|
98
103
|
continue
|
|
@@ -105,7 +110,7 @@ def get_os_info() -> tuple[str, str]:
|
|
|
105
110
|
return platform.system(), platform.release()
|
|
106
111
|
|
|
107
112
|
|
|
108
|
-
def get_terminal_user_agent_token() -> str:
|
|
113
|
+
def get_terminal_user_agent_token() -> 'str':
|
|
109
114
|
term_program = os.environ.get("TERM_PROGRAM", "")
|
|
110
115
|
if term_program.lower() == "tmux":
|
|
111
116
|
client_termname = _tmux_display_message("#{client_termname}")
|
|
@@ -118,14 +123,15 @@ def get_terminal_user_agent_token() -> str:
|
|
|
118
123
|
return "unknown"
|
|
119
124
|
|
|
120
125
|
|
|
121
|
-
def _git_output(cwd: Path, args:
|
|
126
|
+
def _git_output(cwd: 'Path', args: 'typing.List[str]') -> 'typing.Union[str, None]':
|
|
122
127
|
try:
|
|
123
128
|
completed = subprocess.run(
|
|
124
129
|
["git", *args],
|
|
125
130
|
cwd=str(cwd),
|
|
126
131
|
check=True,
|
|
127
|
-
|
|
128
|
-
|
|
132
|
+
stdout=subprocess.PIPE,
|
|
133
|
+
stderr=subprocess.PIPE,
|
|
134
|
+
universal_newlines=True,
|
|
129
135
|
)
|
|
130
136
|
except (OSError, subprocess.CalledProcessError):
|
|
131
137
|
return None
|
|
@@ -133,11 +139,11 @@ def _git_output(cwd: Path, args: list[str]) -> str | None:
|
|
|
133
139
|
return value or None
|
|
134
140
|
|
|
135
141
|
|
|
136
|
-
def _git_remote_urls(cwd: Path) ->
|
|
142
|
+
def _git_remote_urls(cwd: 'Path') -> 'typing.Dict[str, str]':
|
|
137
143
|
remote_names = _git_output(cwd, ["remote"])
|
|
138
144
|
if remote_names is None:
|
|
139
145
|
return {}
|
|
140
|
-
remotes:
|
|
146
|
+
remotes: 'typing.Dict[str, str]' = {}
|
|
141
147
|
for name in remote_names.splitlines():
|
|
142
148
|
remote_name = name.strip()
|
|
143
149
|
if not remote_name:
|
|
@@ -148,21 +154,22 @@ def _git_remote_urls(cwd: Path) -> dict[str, str]:
|
|
|
148
154
|
return remotes
|
|
149
155
|
|
|
150
156
|
|
|
151
|
-
def _git_has_changes(cwd: Path) -> bool
|
|
157
|
+
def _git_has_changes(cwd: 'Path') -> 'typing.Union[bool, None]':
|
|
152
158
|
try:
|
|
153
159
|
completed = subprocess.run(
|
|
154
160
|
["git", "status", "--porcelain"],
|
|
155
161
|
cwd=str(cwd),
|
|
156
162
|
check=True,
|
|
157
|
-
|
|
158
|
-
|
|
163
|
+
stdout=subprocess.PIPE,
|
|
164
|
+
stderr=subprocess.PIPE,
|
|
165
|
+
universal_newlines=True,
|
|
159
166
|
)
|
|
160
167
|
except (OSError, subprocess.CalledProcessError):
|
|
161
168
|
return None
|
|
162
169
|
return bool(completed.stdout.strip())
|
|
163
170
|
|
|
164
171
|
|
|
165
|
-
def _user_agent_suffix(originator: str, version: str) -> str:
|
|
172
|
+
def _user_agent_suffix(originator: 'str', version: 'str') -> 'str':
|
|
166
173
|
if originator == "codex_exec":
|
|
167
174
|
return f" (codex-exec; {version})"
|
|
168
175
|
if originator == "codex-tui":
|
|
@@ -170,7 +177,7 @@ def _user_agent_suffix(originator: str, version: str) -> str:
|
|
|
170
177
|
return ""
|
|
171
178
|
|
|
172
179
|
|
|
173
|
-
def _normalize_os_version(version: str) -> str:
|
|
180
|
+
def _normalize_os_version(version: 'str') -> 'str':
|
|
174
181
|
parts = version.split(".")
|
|
175
182
|
if len(parts) == 2 and all(part.isdigit() for part in parts):
|
|
176
183
|
major, minor = parts
|
|
@@ -178,13 +185,28 @@ def _normalize_os_version(version: str) -> str:
|
|
|
178
185
|
return version
|
|
179
186
|
|
|
180
187
|
|
|
181
|
-
def
|
|
188
|
+
def _read_local_package_version() -> 'typing.Union[str, None]':
|
|
189
|
+
pyproject_path = Path(__file__).resolve().parents[2] / "pyproject.toml"
|
|
190
|
+
if not pyproject_path.is_file():
|
|
191
|
+
return None
|
|
192
|
+
match = re.search(
|
|
193
|
+
r'^\s*version\s*=\s*"([^"]+)"\s*$',
|
|
194
|
+
pyproject_path.read_text(encoding="utf-8"),
|
|
195
|
+
flags=re.MULTILINE,
|
|
196
|
+
)
|
|
197
|
+
if match is None:
|
|
198
|
+
return None
|
|
199
|
+
return match.group(1).strip() or None
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _tmux_display_message(fmt: 'str') -> 'typing.Union[str, None]':
|
|
182
203
|
try:
|
|
183
204
|
output = subprocess.run(
|
|
184
205
|
["tmux", "display-message", "-p", fmt],
|
|
185
206
|
check=True,
|
|
186
|
-
|
|
187
|
-
|
|
207
|
+
stdout=subprocess.PIPE,
|
|
208
|
+
stderr=subprocess.PIPE,
|
|
209
|
+
universal_newlines=True,
|
|
188
210
|
)
|
|
189
211
|
except (OSError, subprocess.CalledProcessError):
|
|
190
212
|
return None
|
|
@@ -192,7 +214,7 @@ def _tmux_display_message(fmt: str) -> str | None:
|
|
|
192
214
|
return value or None
|
|
193
215
|
|
|
194
216
|
|
|
195
|
-
def _sanitize_header_token(value: str) -> str:
|
|
217
|
+
def _sanitize_header_token(value: 'str') -> 'str':
|
|
196
218
|
return "".join(
|
|
197
219
|
character
|
|
198
220
|
if (character.isalnum() or character in {"-", "_", ".", "/"})
|
|
@@ -201,13 +223,14 @@ def _sanitize_header_token(value: str) -> str:
|
|
|
201
223
|
)
|
|
202
224
|
|
|
203
225
|
|
|
204
|
-
def _detect_upstream_codex_version() -> str
|
|
226
|
+
def _detect_upstream_codex_version() -> 'typing.Union[str, None]':
|
|
205
227
|
try:
|
|
206
228
|
output = subprocess.run(
|
|
207
229
|
["codex", "--version"],
|
|
208
230
|
check=True,
|
|
209
|
-
|
|
210
|
-
|
|
231
|
+
stdout=subprocess.PIPE,
|
|
232
|
+
stderr=subprocess.PIPE,
|
|
233
|
+
universal_newlines=True,
|
|
211
234
|
)
|
|
212
235
|
except (OSError, subprocess.CalledProcessError):
|
|
213
236
|
return None
|
pycodex/utils/random_ids.py
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
1
|
|
|
3
2
|
import random
|
|
4
3
|
import time
|
|
5
4
|
import uuid
|
|
6
5
|
|
|
7
6
|
|
|
8
|
-
def uuid7_string() -> str:
|
|
7
|
+
def uuid7_string() -> 'str':
|
|
9
8
|
timestamp_ms = int(time.time() * 1000) & ((1 << 48) - 1)
|
|
10
9
|
rand_a = random.getrandbits(12)
|
|
11
10
|
rand_b = random.getrandbits(62)
|