python-codex 0.1.6__tar.gz → 0.1.7__tar.gz

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 (103) hide show
  1. {python_codex-0.1.6 → python_codex-0.1.7}/PKG-INFO +1 -1
  2. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/cli.py +40 -4
  3. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/base_tool.py +16 -0
  4. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/utils/__init__.py +2 -0
  5. python_codex-0.1.7/pycodex/utils/debug.py +12 -0
  6. {python_codex-0.1.6 → python_codex-0.1.7}/pyproject.toml +1 -1
  7. {python_codex-0.1.6 → python_codex-0.1.7}/.github/workflows/publish.yml +0 -0
  8. {python_codex-0.1.6 → python_codex-0.1.7}/.github/workflows/test.yml +0 -0
  9. {python_codex-0.1.6 → python_codex-0.1.7}/.gitignore +0 -0
  10. {python_codex-0.1.6 → python_codex-0.1.7}/AGENTS.md +0 -0
  11. {python_codex-0.1.6 → python_codex-0.1.7}/LICENSE +0 -0
  12. {python_codex-0.1.6 → python_codex-0.1.7}/README.md +0 -0
  13. {python_codex-0.1.6 → python_codex-0.1.7}/README_ZH.md +0 -0
  14. {python_codex-0.1.6 → python_codex-0.1.7}/docs/ALIGNMENT.md +0 -0
  15. {python_codex-0.1.6 → python_codex-0.1.7}/docs/CONTEXT.md +0 -0
  16. {python_codex-0.1.6 → python_codex-0.1.7}/docs/responses_server/README.md +0 -0
  17. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/__init__.py +0 -0
  18. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/agent.py +0 -0
  19. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/collaboration.py +0 -0
  20. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/compat.py +0 -0
  21. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/context.py +0 -0
  22. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/doctor.py +0 -0
  23. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/model.py +0 -0
  24. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/portable.py +0 -0
  25. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/portable_server.py +0 -0
  26. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/prompts/collaboration_default.md +0 -0
  27. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/prompts/collaboration_plan.md +0 -0
  28. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/prompts/default_base_instructions.md +0 -0
  29. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/prompts/exec_tools.json +0 -0
  30. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/prompts/models.json +0 -0
  31. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/prompts/permissions/approval_policy/never.md +0 -0
  32. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/prompts/permissions/approval_policy/on_failure.md +0 -0
  33. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/prompts/permissions/approval_policy/on_request.md +0 -0
  34. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/prompts/permissions/approval_policy/on_request_rule_request_permission.md +0 -0
  35. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/prompts/permissions/approval_policy/unless_trusted.md +0 -0
  36. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/prompts/permissions/sandbox_mode/danger_full_access.md +0 -0
  37. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/prompts/permissions/sandbox_mode/read_only.md +0 -0
  38. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/prompts/permissions/sandbox_mode/workspace_write.md +0 -0
  39. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/prompts/subagent_tools.json +0 -0
  40. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/protocol.py +0 -0
  41. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/runtime.py +0 -0
  42. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/runtime_services.py +0 -0
  43. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/__init__.py +0 -0
  44. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/agent_tool_schemas.py +0 -0
  45. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/apply_patch_tool.py +0 -0
  46. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/close_agent_tool.py +0 -0
  47. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/code_mode_manager.py +0 -0
  48. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/exec_command_tool.py +0 -0
  49. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/exec_runtime.js +0 -0
  50. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/exec_tool.py +0 -0
  51. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/grep_files_tool.py +0 -0
  52. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/list_dir_tool.py +0 -0
  53. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/read_file_tool.py +0 -0
  54. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/request_permissions_tool.py +0 -0
  55. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/request_user_input_tool.py +0 -0
  56. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/resume_agent_tool.py +0 -0
  57. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/send_input_tool.py +0 -0
  58. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/shell_command_tool.py +0 -0
  59. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/shell_tool.py +0 -0
  60. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/spawn_agent_tool.py +0 -0
  61. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/unified_exec_manager.py +0 -0
  62. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/update_plan_tool.py +0 -0
  63. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/view_image_tool.py +0 -0
  64. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/wait_agent_tool.py +0 -0
  65. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/wait_tool.py +0 -0
  66. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/web_search_tool.py +0 -0
  67. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/tools/write_stdin_tool.py +0 -0
  68. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/utils/compactor.py +0 -0
  69. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/utils/dotenv.py +0 -0
  70. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/utils/get_env.py +0 -0
  71. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/utils/random_ids.py +0 -0
  72. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/utils/session_persist.py +0 -0
  73. {python_codex-0.1.6 → python_codex-0.1.7}/pycodex/utils/visualize.py +0 -0
  74. {python_codex-0.1.6 → python_codex-0.1.7}/responses_server/__init__.py +0 -0
  75. {python_codex-0.1.6 → python_codex-0.1.7}/responses_server/__main__.py +0 -0
  76. {python_codex-0.1.6 → python_codex-0.1.7}/responses_server/app.py +0 -0
  77. {python_codex-0.1.6 → python_codex-0.1.7}/responses_server/config.py +0 -0
  78. {python_codex-0.1.6 → python_codex-0.1.7}/responses_server/messages_api.py +0 -0
  79. {python_codex-0.1.6 → python_codex-0.1.7}/responses_server/payload_processors.py +0 -0
  80. {python_codex-0.1.6 → python_codex-0.1.7}/responses_server/server.py +0 -0
  81. {python_codex-0.1.6 → python_codex-0.1.7}/responses_server/session_store.py +0 -0
  82. {python_codex-0.1.6 → python_codex-0.1.7}/responses_server/stream_router.py +0 -0
  83. {python_codex-0.1.6 → python_codex-0.1.7}/responses_server/tools/__init__.py +0 -0
  84. {python_codex-0.1.6 → python_codex-0.1.7}/responses_server/tools/custom_adapter.py +0 -0
  85. {python_codex-0.1.6 → python_codex-0.1.7}/responses_server/tools/web_search.py +0 -0
  86. {python_codex-0.1.6 → python_codex-0.1.7}/tests/TESTS.md +0 -0
  87. {python_codex-0.1.6 → python_codex-0.1.7}/tests/__init__.py +0 -0
  88. {python_codex-0.1.6 → python_codex-0.1.7}/tests/compare_request_user_input_roundtrip.py +0 -0
  89. {python_codex-0.1.6 → python_codex-0.1.7}/tests/compare_steer_request_bodies.py +0 -0
  90. {python_codex-0.1.6 → python_codex-0.1.7}/tests/compare_tool_schemas.py +0 -0
  91. {python_codex-0.1.6 → python_codex-0.1.7}/tests/fake_responses_server.py +0 -0
  92. {python_codex-0.1.6 → python_codex-0.1.7}/tests/fakes.py +0 -0
  93. {python_codex-0.1.6 → python_codex-0.1.7}/tests/responses_server/fake_chat_completions_server.py +0 -0
  94. {python_codex-0.1.6 → python_codex-0.1.7}/tests/responses_server/test_server.py +0 -0
  95. {python_codex-0.1.6 → python_codex-0.1.7}/tests/test_agent.py +0 -0
  96. {python_codex-0.1.6 → python_codex-0.1.7}/tests/test_builtin_tools.py +0 -0
  97. {python_codex-0.1.6 → python_codex-0.1.7}/tests/test_cli.py +0 -0
  98. {python_codex-0.1.6 → python_codex-0.1.7}/tests/test_compactor.py +0 -0
  99. {python_codex-0.1.6 → python_codex-0.1.7}/tests/test_context.py +0 -0
  100. {python_codex-0.1.6 → python_codex-0.1.7}/tests/test_doctor.py +0 -0
  101. {python_codex-0.1.6 → python_codex-0.1.7}/tests/test_fake_responses_server.py +0 -0
  102. {python_codex-0.1.6 → python_codex-0.1.7}/tests/test_model.py +0 -0
  103. {python_codex-0.1.6 → python_codex-0.1.7}/tests/test_portable.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-codex
3
- Version: 0.1.6
3
+ Version: 0.1.7
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
@@ -7,6 +7,7 @@ import os
7
7
  import shlex
8
8
  import sys
9
9
  import tempfile
10
+ import traceback
10
11
  from dataclasses import asdict, replace
11
12
  from pathlib import Path
12
13
  from typing import Sequence
@@ -20,7 +21,7 @@ from .portable import bootstrap_called_home, upload_codex_home
20
21
  from .protocol import AgentEvent
21
22
  from .runtime import AgentRuntime
22
23
  from .runtime_services import RuntimeEnvironment, create_runtime_environment
23
- from .utils import CliSessionView, load_codex_dotenv, uuid7_string
24
+ from .utils import CliSessionView, get_debug_dir, load_codex_dotenv, uuid7_string
24
25
  from .utils.compactor import compact_agent_loop
25
26
  from .utils.session_persist import (
26
27
  SessionRolloutRecorder,
@@ -57,9 +58,9 @@ def configure_loguru() -> 'None':
57
58
  return
58
59
 
59
60
  logger.remove()
60
- log_path = os.environ.get("PYCODEX_DEBUG_LOG", "").strip()
61
- if log_path:
62
- logger.add(log_path, level="DEBUG")
61
+ debug_dir = get_debug_dir()
62
+ if debug_dir is not None:
63
+ logger.add(str(debug_dir / "loguru.log"), level="DEBUG")
63
64
  return
64
65
 
65
66
  if os.environ.get("PYCODEX_DEBUG_STDERR", "").strip().lower() in {
@@ -743,6 +744,8 @@ async def run_interactive_session(
743
744
  async def run_cli(args: 'argparse.Namespace') -> 'int':
744
745
  runtime = None
745
746
  worker = None
747
+ debug_dir = get_debug_dir()
748
+ phase_handle = None if debug_dir is None else (debug_dir / "phase.log").open("a", encoding="utf-8")
746
749
  try:
747
750
  if args.put is not None and args.call:
748
751
  raise ValueError("--put and --call cannot be combined")
@@ -762,9 +765,18 @@ async def run_cli(args: 'argparse.Namespace') -> 'int':
762
765
  print(f"pycodex --call {shlex.quote(call_spec)}", flush=True)
763
766
  return 0
764
767
  if args.call:
768
+ if phase_handle is not None:
769
+ phase_handle.write("bootstrap_called_home:start\n")
770
+ phase_handle.flush()
765
771
  config_path = bootstrap_called_home(args.call)
772
+ if phase_handle is not None:
773
+ phase_handle.write("bootstrap_called_home:done\n")
774
+ phase_handle.flush()
766
775
  args.config = str(config_path)
767
776
  os.environ["CODEX_HOME"] = str(config_path.parent)
777
+ if phase_handle is not None:
778
+ phase_handle.write("build_model_client:start\n")
779
+ phase_handle.flush()
768
780
  client = _build_model_client(
769
781
  args.config,
770
782
  args.profile,
@@ -773,7 +785,13 @@ async def run_cli(args: 'argparse.Namespace') -> 'int':
773
785
  use_chat_completion=args.use_chat_completion,
774
786
  use_messages=args.use_messages,
775
787
  )
788
+ if phase_handle is not None:
789
+ phase_handle.write("build_model_client:done\n")
790
+ phase_handle.flush()
776
791
 
792
+ if phase_handle is not None:
793
+ phase_handle.write("build_runtime:start\n")
794
+ phase_handle.flush()
777
795
  runtime = build_runtime(
778
796
  args.config,
779
797
  args.profile,
@@ -781,6 +799,9 @@ async def run_cli(args: 'argparse.Namespace') -> 'int':
781
799
  client,
782
800
  session_mode="tui",
783
801
  )
802
+ if phase_handle is not None:
803
+ phase_handle.write("build_runtime:done\n")
804
+ phase_handle.flush()
784
805
  if should_run_interactive(args.prompt, sys.stdin.isatty()):
785
806
  return await run_interactive_session(
786
807
  runtime,
@@ -790,13 +811,28 @@ async def run_cli(args: 'argparse.Namespace') -> 'int':
790
811
  else:
791
812
  prompt_text = resolve_prompt_text(args.prompt)
792
813
  worker = asyncio.create_task(runtime.run_forever())
814
+ if phase_handle is not None:
815
+ phase_handle.write("submit_user_turn:start\n")
816
+ phase_handle.flush()
793
817
  result = await runtime.submit_user_turn(prompt_text)
818
+ if phase_handle is not None:
819
+ phase_handle.write("submit_user_turn:done\n")
820
+ phase_handle.flush()
794
821
  print(format_turn_output(result, args.json))
795
822
  return 0
796
823
  except Exception as exc:
824
+ if phase_handle is not None:
825
+ phase_handle.write("fatal_exception\n")
826
+ phase_handle.flush()
827
+ if debug_dir is not None:
828
+ (debug_dir / "fatal_error.txt").write_text(
829
+ traceback.format_exc(), encoding="utf-8"
830
+ )
797
831
  print(f"Error: {exc}", file=sys.stderr)
798
832
  return 1
799
833
  finally:
834
+ if phase_handle is not None:
835
+ phase_handle.close()
800
836
  if runtime is not None and worker is not None:
801
837
  await runtime.shutdown()
802
838
  await worker
@@ -16,8 +16,10 @@ from dataclasses import dataclass
16
16
  from functools import lru_cache
17
17
  import json
18
18
  from pathlib import Path
19
+ import traceback
19
20
 
20
21
  from ..protocol import ConversationItem, JSONDict, JSONValue, ToolCall, ToolResult, ToolSpec
22
+ from ..utils import get_debug_dir
21
23
  import typing
22
24
 
23
25
  EXEC_TOOLS_SNAPSHOT_PATH = (
@@ -140,6 +142,20 @@ class ToolRegistry:
140
142
  tool_type=call.tool_type,
141
143
  )
142
144
  except Exception as exc: # pragma: no cover - defensive wrapper
145
+ if (debug_dir := get_debug_dir()) is not None:
146
+ with (debug_dir / "tool_errors.jsonl").open("a", encoding="utf-8") as handle:
147
+ handle.write(
148
+ json.dumps(
149
+ {
150
+ "tool": call.name,
151
+ "call_id": call.call_id,
152
+ "error": f"{type(exc).__name__}: {exc}",
153
+ "traceback": traceback.format_exc(),
154
+ },
155
+ ensure_ascii=False,
156
+ )
157
+ )
158
+ handle.write("\n")
143
159
  return ToolResult(
144
160
  call_id=call.call_id,
145
161
  name=call.name,
@@ -1,4 +1,5 @@
1
1
  from .dotenv import DOTENV_FILENAME, load_codex_dotenv, parse_dotenv, parse_dotenv_value
2
+ from .debug import get_debug_dir
2
3
  from .get_env import build_user_agent, get_shell_name, get_timezone_name
3
4
  from .random_ids import uuid7_string
4
5
  from .compactor import DEFAULT_COMPACT_PROMPT, SUMMARY_PREFIX, compact
@@ -31,6 +32,7 @@ __all__ = [
31
32
  "format_cli_plan_messages",
32
33
  "format_cli_tool_call_message",
33
34
  "format_cli_tool_message",
35
+ "get_debug_dir",
34
36
  "get_shell_name",
35
37
  "get_timezone_name",
36
38
  "load_codex_dotenv",
@@ -0,0 +1,12 @@
1
+ import os
2
+ from pathlib import Path
3
+ import typing
4
+
5
+
6
+ def get_debug_dir() -> 'typing.Union[Path, None]':
7
+ value = os.environ.get("PYCODEX_DEBUG_LOG", "").strip()
8
+ if not value:
9
+ return None
10
+ path = Path(value).expanduser()
11
+ path.mkdir(parents=True, exist_ok=True)
12
+ return path
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "python-codex"
7
- version = "0.1.6"
7
+ version = "0.1.7"
8
8
  description = "A minimal Python extraction of Codex's main agent loop"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.6.2"
File without changes
File without changes
File without changes
File without changes
File without changes