codex-python-sdk 0.1.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.
@@ -0,0 +1,57 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio as asyncio
4
+
5
+ from .async_client import (
6
+ DEFAULT_APP_SERVER_ARGS,
7
+ DEFAULT_CLI_COMMAND,
8
+ AsyncCodexAgenticClient,
9
+ )
10
+ from .errors import (
11
+ AppServerConnectionError,
12
+ CodexAgenticError,
13
+ NotAuthenticatedError,
14
+ SessionNotFoundError,
15
+ )
16
+ from .factory import create_async_client, create_client
17
+ from .policy import (
18
+ DEFAULT_POLICY_RUBRIC,
19
+ DefaultPolicyEngine,
20
+ LlmRubricPolicyEngine,
21
+ PolicyContext,
22
+ PolicyEngine,
23
+ PolicyJudgeConfig,
24
+ PolicyRubric,
25
+ RuleBasedPolicyEngine,
26
+ build_policy_engine_from_rubric,
27
+ )
28
+ from .renderer import ExecStyleRenderer, render_exec_style_events
29
+ from .sync_client import CodexAgenticClient
30
+ from .types import AgentResponse, ResponseEvent
31
+
32
+ __all__ = [
33
+ "AgentResponse",
34
+ "AppServerConnectionError",
35
+ "AsyncCodexAgenticClient",
36
+ "CodexAgenticClient",
37
+ "CodexAgenticError",
38
+ "DEFAULT_APP_SERVER_ARGS",
39
+ "DEFAULT_CLI_COMMAND",
40
+ "ExecStyleRenderer",
41
+ "DEFAULT_POLICY_RUBRIC",
42
+ "DefaultPolicyEngine",
43
+ "LlmRubricPolicyEngine",
44
+ "NotAuthenticatedError",
45
+ "PolicyContext",
46
+ "PolicyEngine",
47
+ "PolicyJudgeConfig",
48
+ "PolicyRubric",
49
+ "ResponseEvent",
50
+ "RuleBasedPolicyEngine",
51
+ "SessionNotFoundError",
52
+ "asyncio",
53
+ "build_policy_engine_from_rubric",
54
+ "create_async_client",
55
+ "create_client",
56
+ "render_exec_style_events",
57
+ ]
@@ -0,0 +1,99 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime, timezone
4
+ from typing import Any
5
+
6
+
7
+ def utc_now() -> str:
8
+ return datetime.now(tz=timezone.utc).isoformat()
9
+
10
+
11
+ def first_nonempty_text(value: Any) -> str | None:
12
+ if isinstance(value, str):
13
+ text = value.strip()
14
+ return text or None
15
+ if isinstance(value, list):
16
+ out: list[str] = []
17
+ for item in value:
18
+ text = first_nonempty_text(item)
19
+ if text:
20
+ out.append(text)
21
+ if out:
22
+ return "\n".join(out)
23
+ return None
24
+ if isinstance(value, dict):
25
+ for key in ("message", "text", "delta", "error", "content"):
26
+ if key in value:
27
+ text = first_nonempty_text(value.get(key))
28
+ if text:
29
+ return text
30
+ for nested in value.values():
31
+ if isinstance(nested, (dict, list)):
32
+ text = first_nonempty_text(nested)
33
+ if text:
34
+ return text
35
+ return None
36
+
37
+
38
+ def token_usage_total_tokens(value: Any) -> int | None:
39
+ if not isinstance(value, dict):
40
+ return None
41
+ total = value.get("totalTokens")
42
+ if isinstance(total, int):
43
+ return total
44
+ total = value.get("total_tokens")
45
+ if isinstance(total, int):
46
+ return total
47
+ return None
48
+
49
+
50
+ def token_usage_summary(token_usage: dict[str, Any]) -> str | None:
51
+ last = token_usage.get("last")
52
+ total = token_usage.get("total")
53
+ last_total = token_usage_total_tokens(last)
54
+ total_total = token_usage_total_tokens(total)
55
+ if last_total is None and total_total is None:
56
+ return None
57
+ if last_total is None:
58
+ return f"total={total_total}"
59
+ if total_total is None:
60
+ return f"last={last_total}"
61
+ return f"last={last_total}, total={total_total}"
62
+
63
+
64
+ def diff_change_counts(diff: str) -> tuple[int, int]:
65
+ added = 0
66
+ removed = 0
67
+ for line in diff.splitlines():
68
+ if line.startswith("+++") or line.startswith("---"):
69
+ continue
70
+ if line.startswith("+"):
71
+ added += 1
72
+ elif line.startswith("-"):
73
+ removed += 1
74
+ return added, removed
75
+
76
+
77
+ def turn_plan_summary(params: dict[str, Any]) -> str | None:
78
+ plan = params.get("plan")
79
+ if not isinstance(plan, list):
80
+ return first_nonempty_text(params.get("explanation"))
81
+
82
+ status_counts: dict[str, int] = {}
83
+ for item in plan:
84
+ if not isinstance(item, dict):
85
+ continue
86
+ status = item.get("status")
87
+ if isinstance(status, str):
88
+ status_counts[status] = status_counts.get(status, 0) + 1
89
+
90
+ parts: list[str] = []
91
+ explanation = params.get("explanation")
92
+ if isinstance(explanation, str) and explanation.strip():
93
+ parts.append(explanation.strip())
94
+ parts.append(f"steps={len(plan)}")
95
+ for status in ("inProgress", "pending", "completed"):
96
+ if status in status_counts:
97
+ parts.append(f"{status}={status_counts[status]}")
98
+ return ", ".join(parts)
99
+