python-codex 0.2.7__py3-none-any.whl → 0.3.0__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.
Files changed (84) hide show
  1. pycodex/__init__.py +14 -14
  2. pycodex/agent.py +465 -499
  3. pycodex/bootstrap.py +417 -0
  4. pycodex/cli.py +236 -510
  5. pycodex/compat.py +19 -5
  6. pycodex/context.py +222 -212
  7. pycodex/doctor.py +52 -48
  8. pycodex/events.py +857 -0
  9. pycodex/feishu_card.py +217 -163
  10. pycodex/feishu_link.py +43 -83
  11. pycodex/model.py +324 -253
  12. pycodex/model_metadata.py +19 -7
  13. pycodex/portable.py +76 -45
  14. pycodex/portable_server.py +32 -24
  15. pycodex/prompts/models.json +245 -983
  16. pycodex/protocol.py +177 -137
  17. pycodex/runtime.py +579 -176
  18. pycodex/runtime_services.py +204 -157
  19. pycodex/tools/__init__.py +1 -1
  20. pycodex/tools/apply_patch_tool.py +69 -48
  21. pycodex/tools/base_tool.py +89 -42
  22. pycodex/tools/clock_tool.py +58 -25
  23. pycodex/tools/close_agent_tool.py +2 -2
  24. pycodex/tools/code_mode_manager.py +77 -64
  25. pycodex/tools/exec_command_tool.py +26 -11
  26. pycodex/tools/exec_tool.py +4 -4
  27. pycodex/tools/grep_files_tool.py +12 -10
  28. pycodex/tools/ipython_tool.py +10 -13
  29. pycodex/tools/list_dir_tool.py +13 -9
  30. pycodex/tools/read_file_tool.py +29 -17
  31. pycodex/tools/request_permissions_tool.py +15 -5
  32. pycodex/tools/request_user_input_tool.py +13 -104
  33. pycodex/tools/resume_agent_tool.py +2 -2
  34. pycodex/tools/send_input_tool.py +11 -8
  35. pycodex/tools/shell_command_tool.py +7 -5
  36. pycodex/tools/shell_tool.py +7 -5
  37. pycodex/tools/spawn_agent_tool.py +7 -4
  38. pycodex/tools/unified_exec_manager.py +102 -69
  39. pycodex/tools/update_plan_tool.py +8 -5
  40. pycodex/tools/view_image_tool.py +7 -5
  41. pycodex/tools/wait_agent_tool.py +27 -4
  42. pycodex/tools/wait_tool.py +5 -4
  43. pycodex/tools/web_search_tool.py +4 -2
  44. pycodex/tools/write_stdin_tool.py +12 -11
  45. pycodex/utils/__init__.py +2 -17
  46. pycodex/utils/compactor.py +41 -72
  47. pycodex/utils/debug.py +2 -2
  48. pycodex/utils/dotenv.py +6 -7
  49. pycodex/utils/event_helpers.py +190 -0
  50. pycodex/utils/get_env.py +27 -70
  51. pycodex/{image_utils.py → utils/image_utils.py} +8 -11
  52. pycodex/utils/random_ids.py +1 -2
  53. pycodex/utils/session_persist.py +217 -163
  54. pycodex/utils/truncation.py +21 -45
  55. python_codex-0.3.0.dist-info/METADATA +704 -0
  56. python_codex-0.3.0.dist-info/RECORD +90 -0
  57. responses_server/__init__.py +1 -5
  58. responses_server/__main__.py +0 -1
  59. responses_server/app.py +36 -31
  60. responses_server/config.py +23 -23
  61. responses_server/messages_api.py +51 -53
  62. responses_server/payload_processors.py +25 -20
  63. responses_server/server.py +11 -11
  64. responses_server/session_store.py +14 -11
  65. responses_server/stream_router.py +101 -98
  66. responses_server/tools/custom_adapter.py +17 -16
  67. responses_server/tools/web_search.py +39 -36
  68. responses_server/trajectory_dump.py +36 -14
  69. workspace_server/__main__.py +0 -1
  70. workspace_server/app.py +461 -375
  71. workspace_server/workspace.html +852 -228
  72. workspace_server/workspaces.html +94 -95
  73. workspace_server/workspaces.py +137 -79
  74. pycodex/collaboration.py +0 -20
  75. pycodex/interactive_session.py +0 -415
  76. pycodex/prompts/collaboration_default.md +0 -11
  77. pycodex/prompts/collaboration_plan.md +0 -128
  78. pycodex/utils/toolcall_visualize.py +0 -713
  79. pycodex/utils/visualize.py +0 -560
  80. python_codex-0.2.7.dist-info/METADATA +0 -455
  81. python_codex-0.2.7.dist-info/RECORD +0 -93
  82. {python_codex-0.2.7.dist-info → python_codex-0.3.0.dist-info}/WHEEL +0 -0
  83. {python_codex-0.2.7.dist-info → python_codex-0.3.0.dist-info}/entry_points.txt +0 -0
  84. {python_codex-0.2.7.dist-info → python_codex-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,9 +1,10 @@
1
1
  """Shared truncation helpers for model-visible tool output."""
2
2
 
3
3
  import math
4
+ import typing
5
+ from dataclasses import replace
4
6
 
5
7
  from ..protocol import JSONValue, ToolResult
6
- import typing
7
8
 
8
9
  DEFAULT_MAX_OUTPUT_TOKENS = 10_000
9
10
  TRUNCATION_SERIALIZATION_BUDGET_MULTIPLIER = 1.2
@@ -13,7 +14,7 @@ HISTORY_TOOL_OUTPUT_TOKENS = int(
13
14
  APPROX_BYTES_PER_TOKEN = 4
14
15
 
15
16
 
16
- def approx_token_count(text: 'str') -> 'int':
17
+ def approx_token_count(text: "str") -> "int":
17
18
  """Estimate token count using the upstream Codex 4-bytes-per-token rule."""
18
19
  if not text:
19
20
  return 0
@@ -24,7 +25,7 @@ def approx_token_count(text: 'str') -> 'int':
24
25
  )
25
26
 
26
27
 
27
- def formatted_truncate_text(text: 'str', max_tokens: 'int') -> 'str':
28
+ def formatted_truncate_text(text: "str", max_tokens: "int") -> "str":
28
29
  """Format a direct tool response with line count plus middle truncation."""
29
30
  byte_budget = _approx_bytes_for_tokens(max_tokens)
30
31
  if len(text.encode("utf-8")) <= byte_budget:
@@ -35,8 +36,8 @@ def formatted_truncate_text(text: 'str', max_tokens: 'int') -> 'str':
35
36
 
36
37
 
37
38
  def truncate_tool_result_for_history(
38
- result: 'ToolResult',
39
- ) -> 'ToolResult':
39
+ result: "ToolResult",
40
+ ) -> "ToolResult":
40
41
  """Truncate model-visible ToolResult content before storing it in history."""
41
42
  if result.content_items is not None:
42
43
  truncated_content_items = _truncate_content_items(
@@ -45,41 +46,16 @@ def truncate_tool_result_for_history(
45
46
  )
46
47
  if truncated_content_items == result.content_items:
47
48
  return result
48
- return ToolResult(
49
- call_id=result.call_id,
50
- name=result.name,
51
- output=result.output,
52
- content_items=truncated_content_items,
53
- success=result.success,
54
- is_error=result.is_error,
55
- tool_type=result.tool_type,
56
- )
49
+ return replace(result, content_items=truncated_content_items)
57
50
 
58
51
  output_text = _tool_output_text(result.output)
59
52
  truncated_output = _truncate_text(output_text, HISTORY_TOOL_OUTPUT_TOKENS)
60
53
  if truncated_output == output_text:
61
54
  return result
62
- return ToolResult(
63
- call_id=result.call_id,
64
- name=result.name,
65
- output=truncated_output,
66
- success=result.success,
67
- is_error=result.is_error,
68
- tool_type=result.tool_type,
69
- )
70
-
71
-
72
- def truncate_tool_results_for_history(
73
- results: 'typing.Iterable[ToolResult]',
74
- ) -> 'typing.List[ToolResult]':
75
- """Apply history-layer truncation to a batch of completed tool results."""
76
- return [
77
- truncate_tool_result_for_history(result)
78
- for result in results
79
- ]
55
+ return replace(result, output=truncated_output)
80
56
 
81
57
 
82
- def _tool_output_text(output: 'JSONValue') -> 'str':
58
+ def _tool_output_text(output: "JSONValue") -> "str":
83
59
  if isinstance(output, str):
84
60
  return output
85
61
 
@@ -93,10 +69,10 @@ def _tool_output_text(output: 'JSONValue') -> 'str':
93
69
 
94
70
 
95
71
  def _truncate_content_items(
96
- content_items: 'typing.Tuple[typing.Dict[str, typing.Any], ...]',
97
- token_limit: 'int',
98
- ) -> 'typing.Tuple[typing.Dict[str, typing.Any], ...]':
99
- output: 'typing.List[typing.Dict[str, typing.Any]]' = []
72
+ content_items: "typing.Tuple[typing.Dict[str, typing.Any], ...]",
73
+ token_limit: "int",
74
+ ) -> "typing.Tuple[typing.Dict[str, typing.Any], ...]":
75
+ output: "typing.List[typing.Dict[str, typing.Any]]" = []
100
76
  remaining_budget = token_limit
101
77
  omitted_text_items = 0
102
78
 
@@ -135,26 +111,26 @@ def _truncate_content_items(
135
111
  return tuple(output)
136
112
 
137
113
 
138
- def _approx_tokens_from_byte_count(byte_count: 'int') -> 'int':
114
+ def _approx_tokens_from_byte_count(byte_count: "int") -> "int":
139
115
  if byte_count <= 0:
140
116
  return 0
141
117
  return (byte_count + APPROX_BYTES_PER_TOKEN - 1) // APPROX_BYTES_PER_TOKEN
142
118
 
143
119
 
144
- def _approx_bytes_for_tokens(token_count: 'int') -> 'int':
120
+ def _approx_bytes_for_tokens(token_count: "int") -> "int":
145
121
  return max(token_count, 0) * APPROX_BYTES_PER_TOKEN
146
122
 
147
123
 
148
- def _split_budget(byte_budget: 'int') -> 'typing.Tuple[int, int]':
124
+ def _split_budget(byte_budget: "int") -> "typing.Tuple[int, int]":
149
125
  left_budget = byte_budget // 2
150
126
  return left_budget, byte_budget - left_budget
151
127
 
152
128
 
153
129
  def _split_string(
154
- text: 'str',
155
- beginning_bytes: 'int',
156
- end_bytes: 'int',
157
- ) -> 'typing.Tuple[str, str]':
130
+ text: "str",
131
+ beginning_bytes: "int",
132
+ end_bytes: "int",
133
+ ) -> "typing.Tuple[str, str]":
158
134
  if not text:
159
135
  return "", ""
160
136
 
@@ -187,7 +163,7 @@ def _split_string(
187
163
  return text[:prefix_end], text[suffix_start:]
188
164
 
189
165
 
190
- def _truncate_text(text: 'str', max_tokens: 'int') -> 'str':
166
+ def _truncate_text(text: "str", max_tokens: "int") -> "str":
191
167
  if not text:
192
168
  return ""
193
169