python-codex 0.1.2__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 +43 -42
- 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 +69 -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 +2 -4
- 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 +62 -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 +37 -33
- pycodex/utils/random_ids.py +1 -2
- pycodex/utils/visualize.py +79 -79
- {python_codex-0.1.2.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.2.dist-info → python_codex-0.1.3.dist-info}/WHEEL +1 -1
- responses_server/app.py +29 -19
- responses_server/config.py +17 -17
- responses_server/payload_processors.py +16 -16
- responses_server/server.py +11 -11
- responses_server/session_store.py +10 -10
- responses_server/stream_router.py +58 -58
- responses_server/tools/custom_adapter.py +12 -12
- responses_server/tools/web_search.py +33 -33
- python_codex-0.1.2.dist-info/RECORD +0 -73
- {python_codex-0.1.2.dist-info → python_codex-0.1.3.dist-info}/entry_points.txt +0 -0
- {python_codex-0.1.2.dist-info → python_codex-0.1.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
1
|
|
|
3
2
|
import json
|
|
4
3
|
import ssl
|
|
@@ -21,6 +20,7 @@ from .tools.web_search import (
|
|
|
21
20
|
hydrate_tool_call_names,
|
|
22
21
|
partition_tool_calls,
|
|
23
22
|
)
|
|
23
|
+
import typing
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class UnsupportedIncommingFeature(ValueError):
|
|
@@ -32,15 +32,15 @@ class OutcommingChatError(RuntimeError):
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
class StreamRouter:
|
|
35
|
-
def __init__(self, config: CompatServerConfig) -> None:
|
|
35
|
+
def __init__(self, config: 'CompatServerConfig') -> 'None':
|
|
36
36
|
self._config = config
|
|
37
37
|
self._mock_web_search = WebSearchTool()
|
|
38
38
|
|
|
39
39
|
def _provider_capability(
|
|
40
40
|
self,
|
|
41
|
-
explicit_support:
|
|
42
|
-
default: bool
|
|
43
|
-
) -> bool:
|
|
41
|
+
explicit_support: 'typing.Dict[str, bool]',
|
|
42
|
+
default: 'typing.Union[bool, None]' = None,
|
|
43
|
+
) -> 'bool':
|
|
44
44
|
provider_name = str(self._config.model_provider or "").strip().lower()
|
|
45
45
|
if provider_name in explicit_support:
|
|
46
46
|
return explicit_support[provider_name]
|
|
@@ -50,7 +50,7 @@ class StreamRouter:
|
|
|
50
50
|
return default
|
|
51
51
|
raise KeyError("provider capability map is missing `vllm` fallback")
|
|
52
52
|
|
|
53
|
-
def _supports_chat_reasoning(self) -> bool:
|
|
53
|
+
def _supports_chat_reasoning(self) -> 'bool':
|
|
54
54
|
# Unknown providers inherit the vLLM compatibility behavior unless a
|
|
55
55
|
# provider is explicitly declared otherwise.
|
|
56
56
|
return self._provider_capability(
|
|
@@ -60,7 +60,7 @@ class StreamRouter:
|
|
|
60
60
|
}
|
|
61
61
|
)
|
|
62
62
|
|
|
63
|
-
def _supports_stream_usage(self) -> bool:
|
|
63
|
+
def _supports_stream_usage(self) -> 'bool':
|
|
64
64
|
return self._provider_capability(
|
|
65
65
|
{
|
|
66
66
|
"vllm": True,
|
|
@@ -70,8 +70,8 @@ class StreamRouter:
|
|
|
70
70
|
|
|
71
71
|
def validate_incomming_request(
|
|
72
72
|
self,
|
|
73
|
-
incomming_request:
|
|
74
|
-
) -> None:
|
|
73
|
+
incomming_request: 'typing.Dict[str, object]',
|
|
74
|
+
) -> 'None':
|
|
75
75
|
model = str(incomming_request.get("model", "")).strip()
|
|
76
76
|
if not model:
|
|
77
77
|
raise UnsupportedIncommingFeature("incomming request is missing `model`")
|
|
@@ -90,11 +90,11 @@ class StreamRouter:
|
|
|
90
90
|
|
|
91
91
|
def collect_custom_tool_names(
|
|
92
92
|
self,
|
|
93
|
-
incomming_request:
|
|
94
|
-
) ->
|
|
93
|
+
incomming_request: 'typing.Dict[str, object]',
|
|
94
|
+
) -> 'typing.Set[str]':
|
|
95
95
|
return collect_custom_tool_names(incomming_request.get("tools") or [])
|
|
96
96
|
|
|
97
|
-
def list_models(self) ->
|
|
97
|
+
def list_models(self) -> 'typing.Dict[str, object]':
|
|
98
98
|
request = urllib.request.Request(
|
|
99
99
|
self._config.outcomming_models_url(),
|
|
100
100
|
headers=self._build_headers(accept="application/json"),
|
|
@@ -104,8 +104,8 @@ class StreamRouter:
|
|
|
104
104
|
|
|
105
105
|
def build_outcomming_request(
|
|
106
106
|
self,
|
|
107
|
-
incomming_request:
|
|
108
|
-
) ->
|
|
107
|
+
incomming_request: 'typing.Dict[str, object]',
|
|
108
|
+
) -> 'typing.Dict[str, object]':
|
|
109
109
|
model = str(incomming_request.get("model", "")).strip()
|
|
110
110
|
if not model:
|
|
111
111
|
raise UnsupportedIncommingFeature("incomming request is missing `model`")
|
|
@@ -121,7 +121,7 @@ class StreamRouter:
|
|
|
121
121
|
if not isinstance(input_items, list):
|
|
122
122
|
raise UnsupportedIncommingFeature("incomming `input` must be a list")
|
|
123
123
|
|
|
124
|
-
payload:
|
|
124
|
+
payload: 'typing.Dict[str, object]' = {
|
|
125
125
|
"model": model,
|
|
126
126
|
"messages": self._responses_input_to_chat_messages(
|
|
127
127
|
instructions,
|
|
@@ -148,7 +148,7 @@ class StreamRouter:
|
|
|
148
148
|
|
|
149
149
|
return payload
|
|
150
150
|
|
|
151
|
-
def open_outcomming_stream(self, outcomming_request:
|
|
151
|
+
def open_outcomming_stream(self, outcomming_request: 'typing.Dict[str, object]'):
|
|
152
152
|
request = urllib.request.Request(
|
|
153
153
|
self._config.outcomming_chat_completions_url(),
|
|
154
154
|
data=json.dumps(outcomming_request).encode("utf-8"),
|
|
@@ -180,9 +180,9 @@ class StreamRouter:
|
|
|
180
180
|
def route_stream(
|
|
181
181
|
self,
|
|
182
182
|
incomming_stream,
|
|
183
|
-
stored_response: StoredResponse,
|
|
184
|
-
outcomming_request:
|
|
185
|
-
custom_tool_names:
|
|
183
|
+
stored_response: 'StoredResponse',
|
|
184
|
+
outcomming_request: 'typing.Dict[str, object]',
|
|
185
|
+
custom_tool_names: 'typing.Union[typing.Set[str], None]' = None,
|
|
186
186
|
):
|
|
187
187
|
yield (
|
|
188
188
|
"response.created",
|
|
@@ -197,15 +197,15 @@ class StreamRouter:
|
|
|
197
197
|
},
|
|
198
198
|
)
|
|
199
199
|
|
|
200
|
-
text_parts:
|
|
201
|
-
reasoning_parts:
|
|
202
|
-
latest_usage:
|
|
200
|
+
text_parts: 'typing.List[str]' = []
|
|
201
|
+
reasoning_parts: 'typing.List[str]' = []
|
|
202
|
+
latest_usage: 'typing.Dict[str, object]' = {}
|
|
203
203
|
current_request = json.loads(json.dumps(outcomming_request))
|
|
204
204
|
current_stream = incomming_stream
|
|
205
205
|
|
|
206
206
|
while True:
|
|
207
|
-
tool_calls:
|
|
208
|
-
current_usage:
|
|
207
|
+
tool_calls: 'typing.Dict[int, typing.Dict[str, object]]' = {}
|
|
208
|
+
current_usage: 'typing.Dict[str, object]' = {}
|
|
209
209
|
for chunk in current_stream:
|
|
210
210
|
for event_name, payload in self._consume_chat_chunk(
|
|
211
211
|
chunk,
|
|
@@ -290,16 +290,16 @@ class StreamRouter:
|
|
|
290
290
|
|
|
291
291
|
def _responses_input_to_chat_messages(
|
|
292
292
|
self,
|
|
293
|
-
instructions: str,
|
|
294
|
-
input_items:
|
|
295
|
-
) ->
|
|
296
|
-
messages:
|
|
293
|
+
instructions: 'str',
|
|
294
|
+
input_items: 'typing.List[object]',
|
|
295
|
+
) -> 'typing.List[typing.Dict[str, object]]':
|
|
296
|
+
messages: 'typing.List[typing.Dict[str, object]]' = []
|
|
297
297
|
if instructions:
|
|
298
298
|
messages.append({"role": "developer", "content": instructions})
|
|
299
299
|
|
|
300
|
-
pending_assistant:
|
|
300
|
+
pending_assistant: 'typing.Union[typing.Dict[str, object], None]' = None
|
|
301
301
|
|
|
302
|
-
def flush_pending_assistant() -> None:
|
|
302
|
+
def flush_pending_assistant() -> 'None':
|
|
303
303
|
nonlocal pending_assistant
|
|
304
304
|
if pending_assistant is None:
|
|
305
305
|
return
|
|
@@ -420,7 +420,7 @@ class StreamRouter:
|
|
|
420
420
|
flush_pending_assistant()
|
|
421
421
|
return messages
|
|
422
422
|
|
|
423
|
-
def _coalesce_content_text(self, raw_content: object) -> str:
|
|
423
|
+
def _coalesce_content_text(self, raw_content: 'object') -> 'str':
|
|
424
424
|
if raw_content is None:
|
|
425
425
|
return ""
|
|
426
426
|
if isinstance(raw_content, str):
|
|
@@ -430,7 +430,7 @@ class StreamRouter:
|
|
|
430
430
|
"message `content` must be a list or string"
|
|
431
431
|
)
|
|
432
432
|
|
|
433
|
-
text_parts:
|
|
433
|
+
text_parts: 'typing.List[str]' = []
|
|
434
434
|
for part in raw_content:
|
|
435
435
|
if not isinstance(part, dict):
|
|
436
436
|
raise UnsupportedIncommingFeature(
|
|
@@ -445,17 +445,17 @@ class StreamRouter:
|
|
|
445
445
|
)
|
|
446
446
|
return "".join(text_parts)
|
|
447
447
|
|
|
448
|
-
def _coalesce_tool_output_text(self, raw_output: object) -> str:
|
|
448
|
+
def _coalesce_tool_output_text(self, raw_output: 'object') -> 'str':
|
|
449
449
|
if isinstance(raw_output, str):
|
|
450
450
|
return raw_output
|
|
451
451
|
if isinstance(raw_output, list):
|
|
452
452
|
return self._coalesce_content_text(raw_output)
|
|
453
453
|
return json.dumps(raw_output, ensure_ascii=False)
|
|
454
454
|
|
|
455
|
-
def _coalesce_reasoning_text(self, raw_item:
|
|
455
|
+
def _coalesce_reasoning_text(self, raw_item: 'typing.Dict[str, object]') -> 'str':
|
|
456
456
|
content = raw_item.get("content")
|
|
457
457
|
if isinstance(content, list):
|
|
458
|
-
text_parts:
|
|
458
|
+
text_parts: 'typing.List[str]' = []
|
|
459
459
|
for part in content:
|
|
460
460
|
if not isinstance(part, dict):
|
|
461
461
|
continue
|
|
@@ -482,8 +482,8 @@ class StreamRouter:
|
|
|
482
482
|
return value
|
|
483
483
|
return ""
|
|
484
484
|
|
|
485
|
-
def _translate_tools(self, incomming_tools:
|
|
486
|
-
translated:
|
|
485
|
+
def _translate_tools(self, incomming_tools: 'typing.List[object]') -> 'typing.List[typing.Dict[str, object]]':
|
|
486
|
+
translated: 'typing.List[typing.Dict[str, object]]' = []
|
|
487
487
|
for raw_tool in incomming_tools:
|
|
488
488
|
if not isinstance(raw_tool, dict):
|
|
489
489
|
raise UnsupportedIncommingFeature("tool definitions must be objects")
|
|
@@ -518,7 +518,7 @@ class StreamRouter:
|
|
|
518
518
|
)
|
|
519
519
|
return translated
|
|
520
520
|
|
|
521
|
-
def _translate_tool_choice(self, raw_tool_choice: object) -> object:
|
|
521
|
+
def _translate_tool_choice(self, raw_tool_choice: 'object') -> 'object':
|
|
522
522
|
if isinstance(raw_tool_choice, str):
|
|
523
523
|
return raw_tool_choice
|
|
524
524
|
if not isinstance(raw_tool_choice, dict):
|
|
@@ -541,13 +541,13 @@ class StreamRouter:
|
|
|
541
541
|
|
|
542
542
|
def _consume_chat_chunk(
|
|
543
543
|
self,
|
|
544
|
-
payload:
|
|
545
|
-
reasoning_parts:
|
|
546
|
-
text_parts:
|
|
547
|
-
tool_calls:
|
|
548
|
-
current_usage:
|
|
549
|
-
) ->
|
|
550
|
-
events:
|
|
544
|
+
payload: 'typing.Dict[str, object]',
|
|
545
|
+
reasoning_parts: 'typing.List[str]',
|
|
546
|
+
text_parts: 'typing.List[str]',
|
|
547
|
+
tool_calls: 'typing.Dict[int, typing.Dict[str, object]]',
|
|
548
|
+
current_usage: 'typing.Dict[str, object]',
|
|
549
|
+
) -> 'typing.List[typing.Tuple[str, typing.Dict[str, object]]]':
|
|
550
|
+
events: 'typing.List[typing.Tuple[str, typing.Dict[str, object]]]' = []
|
|
551
551
|
usage = payload.get("usage")
|
|
552
552
|
if isinstance(usage, dict):
|
|
553
553
|
self._capture_usage_snapshot(current_usage, usage)
|
|
@@ -627,9 +627,9 @@ class StreamRouter:
|
|
|
627
627
|
|
|
628
628
|
def _capture_usage_snapshot(
|
|
629
629
|
self,
|
|
630
|
-
current_usage:
|
|
631
|
-
usage:
|
|
632
|
-
) -> None:
|
|
630
|
+
current_usage: 'typing.Dict[str, object]',
|
|
631
|
+
usage: 'typing.Dict[str, object]',
|
|
632
|
+
) -> 'None':
|
|
633
633
|
scalar_mappings = (
|
|
634
634
|
("input_tokens", usage.get("input_tokens", usage.get("prompt_tokens"))),
|
|
635
635
|
(
|
|
@@ -661,12 +661,12 @@ class StreamRouter:
|
|
|
661
661
|
|
|
662
662
|
def _build_output_items(
|
|
663
663
|
self,
|
|
664
|
-
reasoning_parts:
|
|
665
|
-
text_parts:
|
|
666
|
-
tool_calls:
|
|
667
|
-
custom_tool_names:
|
|
668
|
-
) ->
|
|
669
|
-
items:
|
|
664
|
+
reasoning_parts: 'typing.List[str]',
|
|
665
|
+
text_parts: 'typing.List[str]',
|
|
666
|
+
tool_calls: 'typing.Dict[int, typing.Dict[str, object]]',
|
|
667
|
+
custom_tool_names: 'typing.Set[str]',
|
|
668
|
+
) -> 'typing.List[typing.Dict[str, object]]':
|
|
669
|
+
items: 'typing.List[typing.Dict[str, object]]' = []
|
|
670
670
|
reasoning_text = "".join(reasoning_parts)
|
|
671
671
|
if reasoning_text:
|
|
672
672
|
items.append(
|
|
@@ -731,7 +731,7 @@ class StreamRouter:
|
|
|
731
731
|
|
|
732
732
|
return items
|
|
733
733
|
|
|
734
|
-
def _request_json(self, request: urllib.request.Request) ->
|
|
734
|
+
def _request_json(self, request: 'urllib.request.Request') -> 'typing.Dict[str, object]':
|
|
735
735
|
try:
|
|
736
736
|
with urllib.request.urlopen(
|
|
737
737
|
request,
|
|
@@ -749,7 +749,7 @@ class StreamRouter:
|
|
|
749
749
|
f"outcomming request failed: {exc.reason}"
|
|
750
750
|
) from exc
|
|
751
751
|
|
|
752
|
-
def _build_headers(self, accept: str) ->
|
|
752
|
+
def _build_headers(self, accept: 'str') -> 'typing.Dict[str, str]':
|
|
753
753
|
headers = {
|
|
754
754
|
"Accept": accept,
|
|
755
755
|
"Content-Type": "application/json",
|
|
@@ -760,8 +760,8 @@ class StreamRouter:
|
|
|
760
760
|
return headers
|
|
761
761
|
|
|
762
762
|
def _iter_sse_events(self, response):
|
|
763
|
-
event_name: str
|
|
764
|
-
data_lines:
|
|
763
|
+
event_name: 'typing.Union[str, None]' = None
|
|
764
|
+
data_lines: 'typing.List[str]' = []
|
|
765
765
|
|
|
766
766
|
for raw_line in response:
|
|
767
767
|
line = raw_line.decode("utf-8", errors="replace").rstrip("\r\n")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
1
|
|
|
3
2
|
from copy import deepcopy
|
|
4
3
|
import json
|
|
4
|
+
import typing
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class CustomToolAdapterError(ValueError):
|
|
@@ -82,8 +82,8 @@ It is important to remember:
|
|
|
82
82
|
"""
|
|
83
83
|
|
|
84
84
|
|
|
85
|
-
def collect_custom_tool_names(raw_tools: object) ->
|
|
86
|
-
names:
|
|
85
|
+
def collect_custom_tool_names(raw_tools: 'object') -> 'typing.Set[str]':
|
|
86
|
+
names: 'typing.Set[str]' = set()
|
|
87
87
|
if not isinstance(raw_tools, list):
|
|
88
88
|
return names
|
|
89
89
|
for raw_tool in raw_tools:
|
|
@@ -95,7 +95,7 @@ def collect_custom_tool_names(raw_tools: object) -> set[str]:
|
|
|
95
95
|
return names
|
|
96
96
|
|
|
97
97
|
|
|
98
|
-
def build_tool_definition(raw_tool:
|
|
98
|
+
def build_tool_definition(raw_tool: 'typing.Dict[str, object]') -> 'typing.Dict[str, object]':
|
|
99
99
|
name = _required_tool_name(raw_tool)
|
|
100
100
|
description = _build_description(raw_tool)
|
|
101
101
|
input_description = (
|
|
@@ -125,7 +125,7 @@ def build_tool_definition(raw_tool: dict[str, object]) -> dict[str, object]:
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
|
|
128
|
-
def build_tool_call(raw_item:
|
|
128
|
+
def build_tool_call(raw_item: 'typing.Dict[str, object]') -> 'typing.Dict[str, object]':
|
|
129
129
|
name = _required_item_name(raw_item)
|
|
130
130
|
return {
|
|
131
131
|
"id": str(raw_item.get("call_id", "")).strip() or name,
|
|
@@ -141,7 +141,7 @@ def build_tool_call(raw_item: dict[str, object]) -> dict[str, object]:
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
|
|
144
|
-
def build_output_item(tool_call:
|
|
144
|
+
def build_output_item(tool_call: 'typing.Dict[str, object]', index: 'int') -> 'typing.Dict[str, object]':
|
|
145
145
|
function = tool_call.get("function") or {}
|
|
146
146
|
if not isinstance(function, dict):
|
|
147
147
|
raise CustomToolAdapterError(
|
|
@@ -160,7 +160,7 @@ def build_output_item(tool_call: dict[str, object], index: int) -> dict[str, obj
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
|
|
163
|
-
def extract_input_text(raw_arguments: object) -> str:
|
|
163
|
+
def extract_input_text(raw_arguments: 'object') -> 'str':
|
|
164
164
|
if isinstance(raw_arguments, dict):
|
|
165
165
|
parsed = deepcopy(raw_arguments)
|
|
166
166
|
else:
|
|
@@ -186,7 +186,7 @@ def extract_input_text(raw_arguments: object) -> str:
|
|
|
186
186
|
return str(raw_arguments or "")
|
|
187
187
|
|
|
188
188
|
|
|
189
|
-
def _build_description(raw_tool:
|
|
189
|
+
def _build_description(raw_tool: 'typing.Dict[str, object]') -> 'str':
|
|
190
190
|
name = _tool_name(raw_tool)
|
|
191
191
|
if name == APPLY_PATCH_NAME:
|
|
192
192
|
return APPLY_PATCH_CHAT_DESCRIPTION
|
|
@@ -200,7 +200,7 @@ def _build_description(raw_tool: dict[str, object]) -> str:
|
|
|
200
200
|
|
|
201
201
|
raw_format = raw_tool.get("format")
|
|
202
202
|
if isinstance(raw_format, dict):
|
|
203
|
-
format_lines:
|
|
203
|
+
format_lines: 'typing.List[str]' = []
|
|
204
204
|
format_type = str(raw_format.get("type", "")).strip()
|
|
205
205
|
syntax = str(raw_format.get("syntax", "")).strip()
|
|
206
206
|
definition = str(raw_format.get("definition", "") or "").strip()
|
|
@@ -217,18 +217,18 @@ def _build_description(raw_tool: dict[str, object]) -> str:
|
|
|
217
217
|
return "\n\n".join(parts)
|
|
218
218
|
|
|
219
219
|
|
|
220
|
-
def _tool_name(raw_tool:
|
|
220
|
+
def _tool_name(raw_tool: 'typing.Dict[str, object]') -> 'str':
|
|
221
221
|
return str(raw_tool.get("name", "")).strip()
|
|
222
222
|
|
|
223
223
|
|
|
224
|
-
def _required_tool_name(raw_tool:
|
|
224
|
+
def _required_tool_name(raw_tool: 'typing.Dict[str, object]') -> 'str':
|
|
225
225
|
name = _tool_name(raw_tool)
|
|
226
226
|
if not name:
|
|
227
227
|
raise CustomToolAdapterError("custom tool definition is missing `name`")
|
|
228
228
|
return name
|
|
229
229
|
|
|
230
230
|
|
|
231
|
-
def _required_item_name(raw_item:
|
|
231
|
+
def _required_item_name(raw_item: 'typing.Dict[str, object]') -> 'str':
|
|
232
232
|
name = str(raw_item.get("name", "")).strip()
|
|
233
233
|
if not name:
|
|
234
234
|
raise CustomToolAdapterError("custom tool call is missing `name`")
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
1
|
|
|
3
2
|
from copy import deepcopy
|
|
4
3
|
import json
|
|
5
4
|
|
|
6
5
|
from pycodex.protocol import JSONValue
|
|
7
6
|
from pycodex.tools.base_tool import BaseTool, ToolContext
|
|
7
|
+
import typing
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class WebSearchTool(BaseTool):
|
|
@@ -29,10 +29,10 @@ class WebSearchTool(BaseTool):
|
|
|
29
29
|
}
|
|
30
30
|
supports_parallel = False
|
|
31
31
|
|
|
32
|
-
async def run(self, context: ToolContext, args: JSONValue) -> JSONValue:
|
|
32
|
+
async def run(self, context: 'ToolContext', args: 'JSONValue') -> 'JSONValue':
|
|
33
33
|
del context
|
|
34
34
|
query, queries = extract_queries(args)
|
|
35
|
-
output_payload:
|
|
35
|
+
output_payload: 'typing.Dict[str, object]' = {
|
|
36
36
|
"results": [],
|
|
37
37
|
"mock": True,
|
|
38
38
|
}
|
|
@@ -43,7 +43,7 @@ class WebSearchTool(BaseTool):
|
|
|
43
43
|
return output_payload
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
def build_tool_definition(tool: WebSearchTool) ->
|
|
46
|
+
def build_tool_definition(tool: 'WebSearchTool') -> 'typing.Dict[str, object]':
|
|
47
47
|
return {
|
|
48
48
|
"type": "function",
|
|
49
49
|
"name": tool.name,
|
|
@@ -57,13 +57,13 @@ def build_tool_definition(tool: WebSearchTool) -> dict[str, object]:
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
def partition_tool_calls(
|
|
60
|
-
tool: WebSearchTool,
|
|
61
|
-
tool_calls:
|
|
62
|
-
outcomming_request:
|
|
63
|
-
) ->
|
|
60
|
+
tool: 'WebSearchTool',
|
|
61
|
+
tool_calls: 'typing.Dict[int, typing.Dict[str, object]]',
|
|
62
|
+
outcomming_request: 'typing.Dict[str, object]',
|
|
63
|
+
) -> 'typing.Tuple[typing.List[typing.Dict[str, object]], typing.Dict[int, typing.Dict[str, object]]]':
|
|
64
64
|
mock_tool_names = _collect_mock_tool_names(tool, outcomming_request)
|
|
65
|
-
mock_calls:
|
|
66
|
-
ordinary_tool_calls:
|
|
65
|
+
mock_calls: 'typing.List[typing.Dict[str, object]]' = []
|
|
66
|
+
ordinary_tool_calls: 'typing.Dict[int, typing.Dict[str, object]]' = {}
|
|
67
67
|
for index in sorted(tool_calls):
|
|
68
68
|
tool_call = tool_calls[index]
|
|
69
69
|
function = tool_call.get("function") or {}
|
|
@@ -78,9 +78,9 @@ def partition_tool_calls(
|
|
|
78
78
|
|
|
79
79
|
|
|
80
80
|
def hydrate_tool_call_names(
|
|
81
|
-
tool_calls:
|
|
82
|
-
outcomming_request:
|
|
83
|
-
) -> None:
|
|
81
|
+
tool_calls: 'typing.Dict[int, typing.Dict[str, object]]',
|
|
82
|
+
outcomming_request: 'typing.Dict[str, object]',
|
|
83
|
+
) -> 'None':
|
|
84
84
|
raw_tools = outcomming_request.get("tools") or []
|
|
85
85
|
if not isinstance(raw_tools, list):
|
|
86
86
|
return
|
|
@@ -104,15 +104,15 @@ def hydrate_tool_call_names(
|
|
|
104
104
|
|
|
105
105
|
|
|
106
106
|
def build_output_items(
|
|
107
|
-
mock_search_calls:
|
|
108
|
-
) ->
|
|
109
|
-
items:
|
|
107
|
+
mock_search_calls: 'typing.List[typing.Dict[str, object]]',
|
|
108
|
+
) -> 'typing.List[typing.Dict[str, object]]':
|
|
109
|
+
items: 'typing.List[typing.Dict[str, object]]' = []
|
|
110
110
|
for tool_call in mock_search_calls:
|
|
111
111
|
function = tool_call.get("function") or {}
|
|
112
112
|
if not isinstance(function, dict):
|
|
113
113
|
continue
|
|
114
114
|
query, queries = extract_queries(function.get("arguments"))
|
|
115
|
-
action:
|
|
115
|
+
action: 'typing.Dict[str, object]' = {"type": "search"}
|
|
116
116
|
if query:
|
|
117
117
|
action["query"] = query
|
|
118
118
|
if queries:
|
|
@@ -128,17 +128,17 @@ def build_output_items(
|
|
|
128
128
|
|
|
129
129
|
|
|
130
130
|
def build_followup_request(
|
|
131
|
-
tool: WebSearchTool,
|
|
132
|
-
outcomming_request:
|
|
133
|
-
mock_search_calls:
|
|
134
|
-
reasoning_text: str
|
|
135
|
-
) ->
|
|
131
|
+
tool: 'WebSearchTool',
|
|
132
|
+
outcomming_request: 'typing.Dict[str, object]',
|
|
133
|
+
mock_search_calls: 'typing.List[typing.Dict[str, object]]',
|
|
134
|
+
reasoning_text: 'typing.Union[str, None]' = None,
|
|
135
|
+
) -> 'typing.Dict[str, object]':
|
|
136
136
|
followup_request = deepcopy(outcomming_request)
|
|
137
137
|
messages = followup_request.get("messages") or []
|
|
138
138
|
if not isinstance(messages, list):
|
|
139
139
|
raise ValueError("outcomming request messages must be a list")
|
|
140
140
|
|
|
141
|
-
assistant_tool_calls:
|
|
141
|
+
assistant_tool_calls: 'typing.List[typing.Dict[str, object]]' = []
|
|
142
142
|
for tool_call in mock_search_calls:
|
|
143
143
|
function = tool_call.get("function") or {}
|
|
144
144
|
if not isinstance(function, dict):
|
|
@@ -154,7 +154,7 @@ def build_followup_request(
|
|
|
154
154
|
}
|
|
155
155
|
)
|
|
156
156
|
if assistant_tool_calls:
|
|
157
|
-
assistant_message:
|
|
157
|
+
assistant_message: 'typing.Dict[str, object]' = {
|
|
158
158
|
"role": "assistant",
|
|
159
159
|
"tool_calls": assistant_tool_calls,
|
|
160
160
|
}
|
|
@@ -187,7 +187,7 @@ def build_followup_request(
|
|
|
187
187
|
return followup_request
|
|
188
188
|
|
|
189
189
|
|
|
190
|
-
def extract_queries(raw_arguments: JSONValue) ->
|
|
190
|
+
def extract_queries(raw_arguments: 'JSONValue') -> 'typing.Tuple[str, typing.List[str]]':
|
|
191
191
|
if isinstance(raw_arguments, dict):
|
|
192
192
|
parsed = raw_arguments
|
|
193
193
|
else:
|
|
@@ -211,7 +211,7 @@ def extract_queries(raw_arguments: JSONValue) -> tuple[str, list[str]]:
|
|
|
211
211
|
|
|
212
212
|
query = str(parsed.get("query", "")).strip()
|
|
213
213
|
queries_value = parsed.get("queries") or []
|
|
214
|
-
queries:
|
|
214
|
+
queries: 'typing.List[str]' = []
|
|
215
215
|
if isinstance(queries_value, list):
|
|
216
216
|
for value in queries_value:
|
|
217
217
|
normalized = str(value).strip()
|
|
@@ -224,7 +224,7 @@ def extract_queries(raw_arguments: JSONValue) -> tuple[str, list[str]]:
|
|
|
224
224
|
return query, queries
|
|
225
225
|
|
|
226
226
|
|
|
227
|
-
def is_mock_tool(tool: WebSearchTool, raw_tool: object) -> bool:
|
|
227
|
+
def is_mock_tool(tool: 'WebSearchTool', raw_tool: 'object') -> 'bool':
|
|
228
228
|
if not isinstance(raw_tool, dict) or raw_tool.get("type") != "function":
|
|
229
229
|
return False
|
|
230
230
|
function = raw_tool.get("function") or {}
|
|
@@ -237,10 +237,10 @@ def is_mock_tool(tool: WebSearchTool, raw_tool: object) -> bool:
|
|
|
237
237
|
|
|
238
238
|
|
|
239
239
|
def _collect_mock_tool_names(
|
|
240
|
-
tool: WebSearchTool,
|
|
241
|
-
outcomming_request:
|
|
242
|
-
) ->
|
|
243
|
-
names:
|
|
240
|
+
tool: 'WebSearchTool',
|
|
241
|
+
outcomming_request: 'typing.Dict[str, object]',
|
|
242
|
+
) -> 'typing.Set[str]':
|
|
243
|
+
names: 'typing.Set[str]' = set()
|
|
244
244
|
raw_tools = outcomming_request.get("tools") or []
|
|
245
245
|
if not isinstance(raw_tools, list):
|
|
246
246
|
return names
|
|
@@ -250,9 +250,9 @@ def _collect_mock_tool_names(
|
|
|
250
250
|
return names
|
|
251
251
|
|
|
252
252
|
|
|
253
|
-
def _build_mock_output(raw_arguments: JSONValue) ->
|
|
253
|
+
def _build_mock_output(raw_arguments: 'JSONValue') -> 'typing.Dict[str, object]':
|
|
254
254
|
query, queries = extract_queries(raw_arguments)
|
|
255
|
-
output_payload:
|
|
255
|
+
output_payload: 'typing.Dict[str, object]' = {
|
|
256
256
|
"results": [],
|
|
257
257
|
"mock": True,
|
|
258
258
|
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
pycodex/__init__.py,sha256=T11JU1QHEk81TchhrTAOqVkvUUiQGlesk9PNaivjPrU,3052
|
|
2
|
-
pycodex/agent.py,sha256=ApIneWSqDxryf9hdmTRFL65AH4e-sn0MWuuR80951Ec,10069
|
|
3
|
-
pycodex/cli.py,sha256=ju4aF_kwbraqZ-NfoymzB6CjvvMX22afeXDvse2ykf8,24676
|
|
4
|
-
pycodex/collaboration.py,sha256=XAM2enljzHMjzZVlLxbOQF0JhWgKW4qaaDfVcUdE47g,632
|
|
5
|
-
pycodex/context.py,sha256=8-Eg1TE4-GVbEfW0fNZjDWhjLypK3jBlKZY1haYYVPY,23143
|
|
6
|
-
pycodex/doctor.py,sha256=VN-qetM2qJCNRNTZXBMe44VSrEOu8kUXE01luLMF050,10357
|
|
7
|
-
pycodex/model.py,sha256=ZqXSucpzBm0kn2XfhBdKebdwvJQH1Jc9xMqBfPwOKGM,19672
|
|
8
|
-
pycodex/portable.py,sha256=Y2pY08pDiWITY0QYgH3F9YKpOe2EYtxE0qqSmrCkp_g,15260
|
|
9
|
-
pycodex/portable_server.py,sha256=xhEwySCJ41WnsowXM-Db6kkmCOVM02Lmd4pbN6hZzh0,7232
|
|
10
|
-
pycodex/protocol.py,sha256=8mQ7I-y9bxYueSr7d_yGj2Tw69t47OCgwvmxhwihdFw,10807
|
|
11
|
-
pycodex/runtime.py,sha256=tfEuyZmnTP625BQ0NMm-AGhjfQpXcv2EaZLtCJTnEmM,7757
|
|
12
|
-
pycodex/runtime_services.py,sha256=hmdwFiOZ1DPEJ5T8vfDSLfujgGQBPrzPQkn6uX_9vZ8,12503
|
|
13
|
-
pycodex/prompts/collaboration_default.md,sha256=MBTmPuMubeWfZgIeFVj49wwnwD4n_o3fVYAbgWKwu6Q,955
|
|
14
|
-
pycodex/prompts/collaboration_plan.md,sha256=IzjQAA5oHJz-3FmJdOjsJ4LHq6LW1tlEYMoy09n0HKk,8777
|
|
15
|
-
pycodex/prompts/default_base_instructions.md,sha256=D65mcj6bo4CDvVom-D9cbJRJVNquo0NghKt164_fRsg,20923
|
|
16
|
-
pycodex/prompts/exec_tools.json,sha256=2wYLsjL6VGzMnhFNCxE9IA_kxsxUspN68lr7JOlZq54,23369
|
|
17
|
-
pycodex/prompts/models.json,sha256=Xmuy5-FiiWdAe-Zz9w_-_kdEcRvIVssS1PugQSA64i8,251450
|
|
18
|
-
pycodex/prompts/subagent_tools.json,sha256=2ZOXyAiAaai2aazIlXdjjXb7cra5gZ2WYYbPltPaiYg,6199
|
|
19
|
-
pycodex/prompts/permissions/approval_policy/never.md,sha256=QceTG6wjkaJARjYr0HYV1aPnPcpGcrkRUW-smWRr6MQ,120
|
|
20
|
-
pycodex/prompts/permissions/approval_policy/on_failure.md,sha256=dfJjpXkpO6_ANdCKxbVJ8o4vyLxevrJWfKsGHTqtbkc,289
|
|
21
|
-
pycodex/prompts/permissions/approval_policy/on_request.md,sha256=hVQalzh0FAdkKzw5u-N4H7-LtC9ijVDlYsh3OKsZKzo,3661
|
|
22
|
-
pycodex/prompts/permissions/approval_policy/on_request_rule_request_permission.md,sha256=mOinishp1k-wlPsaEuIOMn5GoVm_dAIsWIuEMmv2r7o,1725
|
|
23
|
-
pycodex/prompts/permissions/approval_policy/unless_trusted.md,sha256=XHpi1Lfx1iIXFbbQ_ho_kGstA3JN-RLho291HM30UNw,247
|
|
24
|
-
pycodex/prompts/permissions/sandbox_mode/danger_full_access.md,sha256=nZ7YHacBd3cAHKRZc9XClOOOnXJPXPh0WFBueh5C2D0,197
|
|
25
|
-
pycodex/prompts/permissions/sandbox_mode/read_only.md,sha256=2rAPEXsBYCcuttI5j3euS-3uv_v97catIsnhxlSQSIM,173
|
|
26
|
-
pycodex/prompts/permissions/sandbox_mode/workspace_write.md,sha256=lVN-LwrBbHqlv5yVjcd_mU8tzZW8jfKpTatJKIZu9HI,277
|
|
27
|
-
pycodex/tools/__init__.py,sha256=aSLXrr_31KGQgDfRow5zVIc-2-KdXlHaCE6qUnE4HWI,1772
|
|
28
|
-
pycodex/tools/agent_tool_schemas.py,sha256=adzoo0L6jCM7rLF-O1mNrq85HENQ_oKakjzwP6id1Yk,2069
|
|
29
|
-
pycodex/tools/apply_patch_tool.py,sha256=8hHxoWxWovAYdhr0XzDCZwljtMlApp7-TMZtyxe3adY,13691
|
|
30
|
-
pycodex/tools/base_tool.py,sha256=34NaExjTCyDn333MzlU4ShQ9WHocW3WREfg9ifdAqY4,5299
|
|
31
|
-
pycodex/tools/close_agent_tool.py,sha256=InKhe2gFWOcqE187J3XYrCckecsyAR48VeVmGdYhKWE,1623
|
|
32
|
-
pycodex/tools/code_mode_manager.py,sha256=pEczPyCq-3DpJlTtfUEpl4JAGolz8cOpI8mBc7gdrn0,18603
|
|
33
|
-
pycodex/tools/exec_command_tool.py,sha256=_fWfkQLGeINb2-cniY9CWskkAPjC9hE8pfjcBKkWXAg,3459
|
|
34
|
-
pycodex/tools/exec_runtime.js,sha256=ZczdhrzpSZ-qNnJDDJOe8Ap86HpzHb2FZ_vSpHszgLs,3625
|
|
35
|
-
pycodex/tools/exec_tool.py,sha256=xJfEpcQXpL3OX-ZzKxQ2sI781OuEqpeyPvVkkwhgZ1c,1415
|
|
36
|
-
pycodex/tools/grep_files_tool.py,sha256=twsx1KsvOWh8mi-lbycAtEyh6PeLxtNzl9LzdjwgAf4,4742
|
|
37
|
-
pycodex/tools/list_dir_tool.py,sha256=7S0RsE-NL04G47FmFZtzo-N-O3fPCYQFF0HrjEVuv3U,4749
|
|
38
|
-
pycodex/tools/read_file_tool.py,sha256=GVamhSNEZ1F1IU_og9GgSCzV12TL5t5b1fOUlzTOQBQ,8084
|
|
39
|
-
pycodex/tools/request_permissions_tool.py,sha256=GzYG-mc1ifTiIM8xK8WD-vPGUKpYgMX9zyqq9O6K-EE,3036
|
|
40
|
-
pycodex/tools/request_user_input_tool.py,sha256=hVqCYGPLA29uxBblIjUIoIrzXVg5KZ8PcxJ84obgNro,5715
|
|
41
|
-
pycodex/tools/resume_agent_tool.py,sha256=vF-vLtx90bOuSjLFvn9vgqrKiznIbwpmZ3HVJlCP1LE,1640
|
|
42
|
-
pycodex/tools/send_input_tool.py,sha256=z9PR5VoFd9SF4A-ol04Op8AXQF_3YLE74C6coiTXsZ0,3546
|
|
43
|
-
pycodex/tools/shell_command_tool.py,sha256=Bbah_5HirG1BJOIiqzuMa8kNHNYVPCUvxCFa09eRU6A,3500
|
|
44
|
-
pycodex/tools/shell_tool.py,sha256=BWSaEJZwfQg9Ta-ld2wqeXqavrZC7Y8qgF_vBEOxfYA,3678
|
|
45
|
-
pycodex/tools/spawn_agent_tool.py,sha256=LfJlGI0Ecp9HWNLlTubyybFq-xeRNChILq9ozT7piA8,3556
|
|
46
|
-
pycodex/tools/unified_exec_manager.py,sha256=ZEaMXmO83Iu20V4dwxAuUjy4EF5IHqHmwnTvFJh8zGc,13330
|
|
47
|
-
pycodex/tools/update_plan_tool.py,sha256=l_EG39bEw5K9BIUKoSUsXYDb0W7aLn8SviKSb-bs7Os,2887
|
|
48
|
-
pycodex/tools/view_image_tool.py,sha256=yB915Jd3he4RjPANdm-dYdvio24OXKhBkAsp-9WVPBg,3924
|
|
49
|
-
pycodex/tools/wait_agent_tool.py,sha256=1tJ5spBtpZ_MjoMv5xmZz5WWKl7UwMqHIJ3SYKXEPZw,2596
|
|
50
|
-
pycodex/tools/wait_tool.py,sha256=G4YhaYeWAvUedzxTDAxbczVmXXUp7H2OKWO3qZlEyyk,2324
|
|
51
|
-
pycodex/tools/web_search_tool.py,sha256=hq78XF6MRvmNyPFSIp5eI0eYn9ryKdKvvoIOFNU3tuY,987
|
|
52
|
-
pycodex/tools/write_stdin_tool.py,sha256=DghlwPJnAqDoRBYyh1zeXRsfTXoQUdLJ8JQfrdE4RLs,2542
|
|
53
|
-
pycodex/utils/__init__.py,sha256=Hj_0a7RhkAblWkaHyFhpi0cs2nSjJ1NdavbkBgEHieY,1024
|
|
54
|
-
pycodex/utils/dotenv.py,sha256=sOpu6PA1VrsPZK13ynh3nZg3-u9pdiCXkW648v3pwZQ,1789
|
|
55
|
-
pycodex/utils/get_env.py,sha256=Ehh0mVPhkDlPMd1WXhrz1UqjPCePg8YfZH7zrtu1EOQ,6894
|
|
56
|
-
pycodex/utils/random_ids.py,sha256=vOEVgkwKeQXaHoEVU7IfsPPjKUABkGIeQ7lu9MZctU8,413
|
|
57
|
-
pycodex/utils/visualize.py,sha256=fK79pTfOwMmRrQujAosGt0nGyyJjpz0GfpWY8BkK91c,35369
|
|
58
|
-
responses_server/__init__.py,sha256=3yPv_zeGT7P11tTnmj5kXktISLNsNW-02MUnnbiZcb0,394
|
|
59
|
-
responses_server/__main__.py,sha256=9SRp-Yw7ShGxc6DhSIXcDLKgGEdAVm3oBZ59rBOPjT0,62
|
|
60
|
-
responses_server/app.py,sha256=VJSceVaXxbPLu9KGafLIt5fiGvxrqVTkWeOg81O5-FQ,7016
|
|
61
|
-
responses_server/config.py,sha256=XAJmvvLiCYN5jCUcP_6uZyoW79OzxigMbik8X-ZTdKE,2174
|
|
62
|
-
responses_server/payload_processors.py,sha256=_3Sl7HLG00BgN_TKcvT3_3drCDAq1MAeK1HxbRXNta4,3019
|
|
63
|
-
responses_server/server.py,sha256=Q-gjtHzb7K1Guex10G38PgH9hxqJgdzYnBV7Ycy9L7Y,2049
|
|
64
|
-
responses_server/session_store.py,sha256=oP3aFHsGmEMoXuUcxNh6B4vzp6KwaeRdLzM-3AOwM98,1078
|
|
65
|
-
responses_server/stream_router.py,sha256=uYPjrlBUnNqiuQQ91eKmwDfNF6e5NYDtf5C8BdPRPRc,29536
|
|
66
|
-
responses_server/tools/__init__.py,sha256=ivsBSEy0SBUhY-Uea5v1XMLXShkwHdCVl0id-1FwdZg,150
|
|
67
|
-
responses_server/tools/custom_adapter.py,sha256=ivROeI8D9B1saS7skGLXnwF7fbsjAmEVSbeMceYno4E,8238
|
|
68
|
-
responses_server/tools/web_search.py,sha256=HR9E5uMxWU07khsaIO9zvdg1GCCrWNy73263zfMaxsw,8565
|
|
69
|
-
python_codex-0.1.2.dist-info/METADATA,sha256=wy8bEToZxyf9Cio-upoAS8XmC3MscN8wiKTVXp9MW9g,13969
|
|
70
|
-
python_codex-0.1.2.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
71
|
-
python_codex-0.1.2.dist-info/entry_points.txt,sha256=sNUVakoVuTrzJH505ZgRTQxmtRRPUHV_EH0i6EbYTyM,45
|
|
72
|
-
python_codex-0.1.2.dist-info/licenses/LICENSE,sha256=0X8ifk312hYAORM4hlzg8wVSEXYKNmiPgWlB1YIy2Nw,10926
|
|
73
|
-
python_codex-0.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|