python-codex 0.2.6__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 +18 -14
  2. pycodex/agent.py +468 -462
  3. pycodex/bootstrap.py +417 -0
  4. pycodex/cli.py +236 -436
  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 +329 -252
  12. pycodex/model_metadata.py +19 -7
  13. pycodex/portable.py +90 -52
  14. pycodex/portable_server.py +32 -24
  15. pycodex/prompts/models.json +235 -803
  16. pycodex/protocol.py +177 -137
  17. pycodex/runtime.py +579 -174
  18. pycodex/runtime_services.py +204 -157
  19. pycodex/tools/__init__.py +4 -1
  20. pycodex/tools/apply_patch_tool.py +69 -48
  21. pycodex/tools/base_tool.py +89 -42
  22. pycodex/tools/clock_tool.py +201 -0
  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 +13 -13
  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 +50 -66
  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/utils/image_utils.py +76 -0
  52. pycodex/utils/random_ids.py +1 -2
  53. pycodex/utils/session_persist.py +263 -161
  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 +25 -22
  61. responses_server/messages_api.py +96 -49
  62. responses_server/payload_processors.py +25 -19
  63. responses_server/server.py +11 -11
  64. responses_server/session_store.py +14 -11
  65. responses_server/stream_router.py +196 -107
  66. responses_server/tools/custom_adapter.py +17 -16
  67. responses_server/tools/web_search.py +39 -36
  68. responses_server/trajectory_dump.py +51 -13
  69. workspace_server/__main__.py +0 -1
  70. workspace_server/app.py +470 -384
  71. workspace_server/workspace.html +859 -232
  72. workspace_server/workspaces.html +94 -95
  73. workspace_server/workspaces.py +168 -100
  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 -553
  80. python_codex-0.2.6.dist-info/METADATA +0 -441
  81. python_codex-0.2.6.dist-info/RECORD +0 -91
  82. {python_codex-0.2.6.dist-info → python_codex-0.3.0.dist-info}/WHEEL +0 -0
  83. {python_codex-0.2.6.dist-info → python_codex-0.3.0.dist-info}/entry_points.txt +0 -0
  84. {python_codex-0.2.6.dist-info → python_codex-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,76 @@
1
+ """Image preparation helpers for the Python Codex prototype.
2
+
3
+ Original Codex mapping:
4
+ - Corresponds to `codex-rs/utils/image/src/lib.rs`.
5
+
6
+ Expected behavior:
7
+ - Resize images down to `MAX_DIMENSION` on the longest side before they are
8
+ attached to a model request, matching upstream `PromptImageMode::ResizeToFit`.
9
+ - Keep the original bytes when the caller asks for `original` detail or the
10
+ image already fits.
11
+ """
12
+
13
+ import base64
14
+ import io
15
+ import mimetypes
16
+ import typing
17
+ from pathlib import Path
18
+
19
+ from PIL import Image
20
+
21
+ MAX_DIMENSION = 2048
22
+
23
+ _PRESERVABLE_MIME_TYPES = ("image/png", "image/jpeg", "image/webp")
24
+
25
+
26
+ class ImageProcessingError(RuntimeError):
27
+ pass
28
+
29
+
30
+ def load_image_data_url(
31
+ path: "Path",
32
+ resize_to_fit: "bool" = True,
33
+ ) -> "str":
34
+ mime_type, _ = mimetypes.guess_type(path.name)
35
+ if not mime_type or not mime_type.startswith("image/"):
36
+ raise ImageProcessingError(
37
+ "`{0}` does not look like an image file".format(path)
38
+ )
39
+
40
+ image_bytes = path.read_bytes()
41
+ if resize_to_fit:
42
+ mime_type, image_bytes = _resize_to_fit(mime_type, image_bytes)
43
+ encoded = base64.b64encode(image_bytes).decode("ascii")
44
+ return "data:{0};base64,{1}".format(mime_type, encoded)
45
+
46
+
47
+ def _resize_to_fit(
48
+ mime_type: "str",
49
+ image_bytes: "bytes",
50
+ ) -> "typing.Tuple[str, bytes]":
51
+ with Image.open(io.BytesIO(image_bytes)) as image:
52
+ width, height = image.size
53
+ if width <= MAX_DIMENSION and height <= MAX_DIMENSION:
54
+ return mime_type, image_bytes
55
+
56
+ scale = float(MAX_DIMENSION) / float(max(width, height))
57
+ target_size = (
58
+ max(1, int(width * scale)),
59
+ max(1, int(height * scale)),
60
+ )
61
+ resized = image.resize(target_size, Image.BILINEAR)
62
+ target_mime = mime_type if mime_type in _PRESERVABLE_MIME_TYPES else "image/png"
63
+ if target_mime == "image/jpeg":
64
+ resized = resized.convert("RGB")
65
+ save_format, save_kwargs = "JPEG", {"quality": 85}
66
+ elif target_mime == "image/webp":
67
+ resized = resized.convert("RGBA")
68
+ save_format, save_kwargs = "WEBP", {"lossless": True}
69
+ else:
70
+ resized = resized.convert("RGBA")
71
+ save_format, save_kwargs = "PNG", {}
72
+
73
+ buffer = io.BytesIO()
74
+ resized.save(buffer, format=save_format, **save_kwargs)
75
+
76
+ return target_mime, buffer.getvalue()
@@ -1,10 +1,9 @@
1
-
2
1
  import random
3
2
  import time
4
3
  import uuid
5
4
 
6
5
 
7
- def uuid7_string() -> 'str':
6
+ def uuid7_string() -> "str":
8
7
  timestamp_ms = int(time.time() * 1000) & ((1 << 48) - 1)
9
8
  rand_a = random.getrandbits(12)
10
9
  rand_b = random.getrandbits(62)