oauth-codex 3.2.0__tar.gz → 3.2.2__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 (73) hide show
  1. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/PKG-INFO +1 -1
  2. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/pyproject.toml +1 -1
  3. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/_sdk_client.py +6 -6
  4. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/_streaming.py +12 -1
  5. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/_version.py +1 -1
  6. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/chat/completions.py +34 -24
  7. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/responses/_helpers.py +30 -2
  8. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex.egg-info/PKG-INFO +1 -1
  9. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/README.md +0 -0
  10. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/setup.cfg +0 -0
  11. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/__init__.py +0 -0
  12. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/_base_client.py +0 -0
  13. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/_engine.py +0 -0
  14. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/_exceptions.py +0 -0
  15. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/_models.py +0 -0
  16. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/_module_client.py +0 -0
  17. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/_resource.py +0 -0
  18. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/_types.py +0 -0
  19. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/auth/__init__.py +0 -0
  20. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/auth/_oauth.py +0 -0
  21. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/auth/_provider.py +0 -0
  22. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/auth/config.py +0 -0
  23. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/auth/pkce.py +0 -0
  24. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/auth/store.py +0 -0
  25. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/auth/token_manager.py +0 -0
  26. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/compat_store.py +0 -0
  27. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/core_types.py +0 -0
  28. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/errors.py +0 -0
  29. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/py.typed +0 -0
  30. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/__init__.py +0 -0
  31. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/_wrappers.py +0 -0
  32. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/beta.py +0 -0
  33. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/chat/__init__.py +0 -0
  34. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/files.py +0 -0
  35. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/models.py +0 -0
  36. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/responses/__init__.py +0 -0
  37. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/responses/input_tokens.py +0 -0
  38. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/responses/responses.py +0 -0
  39. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/responses.py +0 -0
  40. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/vector_stores/__init__.py +0 -0
  41. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/vector_stores/file_batches.py +0 -0
  42. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/vector_stores/files.py +0 -0
  43. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/resources/vector_stores/vector_stores.py +0 -0
  44. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/store.py +0 -0
  45. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/tooling.py +0 -0
  46. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/__init__.py +0 -0
  47. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/chat/__init__.py +0 -0
  48. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/chat/completions.py +0 -0
  49. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/file_deleted.py +0 -0
  50. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/file_object.py +0 -0
  51. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/responses/__init__.py +0 -0
  52. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/responses/input_token_count_response.py +0 -0
  53. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/responses/response.py +0 -0
  54. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/responses/response_stream_event.py +0 -0
  55. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/shared/__init__.py +0 -0
  56. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/shared/model_capabilities.py +0 -0
  57. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/shared/usage.py +0 -0
  58. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/vector_stores/__init__.py +0 -0
  59. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/vector_stores/vector_store.py +0 -0
  60. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/vector_stores/vector_store_deleted.py +0 -0
  61. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/vector_stores/vector_store_file.py +0 -0
  62. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/vector_stores/vector_store_file_batch.py +0 -0
  63. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/types/vector_stores/vector_store_search_response.py +0 -0
  64. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex/version.py +0 -0
  65. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex.egg-info/SOURCES.txt +0 -0
  66. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex.egg-info/dependency_links.txt +0 -0
  67. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex.egg-info/requires.txt +0 -0
  68. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/src/oauth_codex.egg-info/top_level.txt +0 -0
  69. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/tests/test_beta_chat_completions.py +0 -0
  70. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/tests/test_client_authentication.py +0 -0
  71. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/tests/test_client_resource_surface.py +0 -0
  72. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/tests/test_public_api_docstrings.py +0 -0
  73. {oauth_codex-3.2.0 → oauth_codex-3.2.2}/tests/test_public_surface.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oauth-codex
3
- Version: 3.2.0
3
+ Version: 3.2.2
4
4
  Summary: Codex OAuth-based Python SDK with a single Client and generate-first API
5
5
  Author: Codex
6
6
  Requires-Python: >=3.11
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "oauth-codex"
7
- version = "3.2.0"
7
+ version = "3.2.2"
8
8
  description = "Codex OAuth-based Python SDK with a single Client and generate-first API"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -59,14 +59,14 @@ class _SyncEngine:
59
59
  return self._stream_responses(payload)
60
60
 
61
61
  response = self._client.request("POST", "/responses", json_data=payload)
62
- return _to_namespace(response.json())
62
+ return response.json()
63
63
 
64
64
  def responses_input_tokens_count(self, **kwargs: Any) -> Any:
65
65
  payload = _payload_without_none(kwargs)
66
66
  response = self._client.request(
67
67
  "POST", "/responses/input_tokens", json_data=payload
68
68
  )
69
- return _to_namespace(response.json())
69
+ return response.json()
70
70
 
71
71
  def _stream_responses(self, payload: dict[str, Any]) -> Iterator[Any]:
72
72
  payload = dict(payload)
@@ -75,7 +75,7 @@ class _SyncEngine:
75
75
  events = response.json()
76
76
  if isinstance(events, list):
77
77
  for event in events:
78
- yield _to_namespace(event)
78
+ yield event
79
79
 
80
80
 
81
81
  class _AsyncEngine:
@@ -88,14 +88,14 @@ class _AsyncEngine:
88
88
  return self._stream_responses(payload)
89
89
 
90
90
  response = await self._client.request("POST", "/responses", json_data=payload)
91
- return _to_namespace(response.json())
91
+ return response.json()
92
92
 
93
93
  async def aresponses_input_tokens_count(self, **kwargs: Any) -> Any:
94
94
  payload = _payload_without_none(kwargs)
95
95
  response = await self._client.request(
96
96
  "POST", "/responses/input_tokens", json_data=payload
97
97
  )
98
- return _to_namespace(response.json())
98
+ return response.json()
99
99
 
100
100
  async def _stream_responses(self, payload: dict[str, Any]) -> AsyncIterator[Any]:
101
101
  payload = dict(payload)
@@ -104,7 +104,7 @@ class _AsyncEngine:
104
104
  events = response.json()
105
105
  if isinstance(events, list):
106
106
  for event in events:
107
- yield _to_namespace(event)
107
+ yield event
108
108
 
109
109
 
110
110
  class Client(SyncAPIClient):
@@ -16,7 +16,10 @@ def _extract_event_data(raw_event: str) -> str | None:
16
16
  data_lines: list[str] = []
17
17
  for line in raw_event.split("\n"):
18
18
  if line.startswith("data:"):
19
- data_lines.append(line[5:].lstrip())
19
+ content = line[5:].lstrip()
20
+ if content == "[DONE]":
21
+ return "[DONE]"
22
+ data_lines.append(content)
20
23
 
21
24
  if not data_lines:
22
25
  return None
@@ -41,12 +44,16 @@ class Stream(Generic[T]):
41
44
  while "\n\n" in buffer:
42
45
  raw_event, buffer = buffer.split("\n\n", 1)
43
46
  data = _extract_event_data(raw_event)
47
+ if data == "[DONE]":
48
+ return
44
49
  if data is None:
45
50
  continue
46
51
  yield self._cast_event(data)
47
52
 
48
53
  if buffer:
49
54
  data = _extract_event_data(buffer)
55
+ if data == "[DONE]":
56
+ return
50
57
  if data is not None:
51
58
  yield self._cast_event(data)
52
59
  finally:
@@ -71,12 +78,16 @@ class AsyncStream(Generic[T]):
71
78
  while "\n\n" in buffer:
72
79
  raw_event, buffer = buffer.split("\n\n", 1)
73
80
  data = _extract_event_data(raw_event)
81
+ if data == "[DONE]":
82
+ return
74
83
  if data is None:
75
84
  continue
76
85
  yield self._cast_event(data)
77
86
 
78
87
  if buffer:
79
88
  data = _extract_event_data(buffer)
89
+ if data == "[DONE]":
90
+ return
80
91
  if data is not None:
81
92
  yield self._cast_event(data)
82
93
  finally:
@@ -1,2 +1,2 @@
1
1
  __title__ = "oauth-codex"
2
- __version__ = "3.2.0"
2
+ __version__ = "3.2.2"
@@ -104,9 +104,16 @@ def _extract_tool_calls(response_data: dict[str, Any]) -> list[dict[str, Any]]:
104
104
  if not isinstance(name, str) or not name:
105
105
  continue
106
106
 
107
- arguments = item.get("arguments")
107
+ # In Codex, arguments are often in `arguments_json` or `arguments` as a dict
108
+ arguments = item.get("arguments_json")
108
109
  if not isinstance(arguments, str):
109
- arguments = "{}"
110
+ args_dict = item.get("arguments")
111
+ if isinstance(args_dict, dict):
112
+ arguments = json.dumps(args_dict)
113
+ elif isinstance(args_dict, str):
114
+ arguments = args_dict
115
+ else:
116
+ arguments = "{}"
110
117
 
111
118
  call_id = item.get("call_id") or item.get("id")
112
119
  if not isinstance(call_id, str) or not call_id:
@@ -125,7 +132,6 @@ def _extract_tool_calls(response_data: dict[str, Any]) -> list[dict[str, Any]]:
125
132
 
126
133
  return tool_calls
127
134
 
128
-
129
135
  def _build_assistant_message(completion: ChatCompletion) -> dict[str, Any]:
130
136
  message = completion.choices[0].message
131
137
  out: dict[str, Any] = {"role": "assistant"}
@@ -145,34 +151,38 @@ def _coerce_tool_output_content(value: Any) -> str:
145
151
  return str(value)
146
152
 
147
153
 
148
- def _parse_tool_arguments(arguments: str) -> Any:
149
- if not arguments.strip():
150
- return {}
151
- try:
152
- return json.loads(arguments)
153
- except json.JSONDecodeError:
154
- return {}
155
-
156
-
157
- def _build_tool_function_map(tools: Any) -> dict[str, Any]:
158
- if not isinstance(tools, list):
159
- return {}
160
-
161
- functions: dict[str, Any] = {}
154
+ def _build_tool_function_map(tools: list[Any]) -> dict[str, Any]:
155
+ tool_map = {}
162
156
  for tool in tools:
163
157
  if callable(tool):
164
- name = getattr(tool, "__name__", "")
165
- if isinstance(name, str) and name:
166
- functions[name] = tool
167
- return functions
168
-
169
-
158
+ name = getattr(tool, "__name__", "tool")
159
+ tool_map[name] = tool
160
+ elif isinstance(tool, dict) and "function" in tool:
161
+ # Not a callable directly but maybe user wants it?
162
+ # OpenAI SDK run_tools specifically requires callables.
163
+ pass
164
+ return tool_map
165
+
166
+ def _parse_tool_arguments(arguments: Any) -> dict[str, Any]:
167
+ if isinstance(arguments, dict):
168
+ return arguments
169
+ if not isinstance(arguments, str) or not arguments.strip():
170
+ raise ValueError(f"Tool arguments must be a valid JSON object string, got: {arguments!r}")
171
+
172
+ try:
173
+ parsed = json.loads(arguments)
174
+ if isinstance(parsed, str):
175
+ parsed = json.loads(parsed)
176
+ if isinstance(parsed, dict):
177
+ return parsed
178
+ raise ValueError("Parsed arguments is not a dictionary")
179
+ except Exception as e:
180
+ raise ValueError(f"Failed to parse tool arguments: {arguments!r}") from e
170
181
  def _run_tool_function(*, fn: Any, arguments: Any) -> Any:
171
182
  if isinstance(arguments, dict):
172
183
  return fn(**arguments)
173
184
  return fn(arguments)
174
185
 
175
-
176
186
  def _to_chat_completion(
177
187
  *,
178
188
  response_data: dict[str, Any],
@@ -9,6 +9,8 @@ from ...types.shared import TokenUsage
9
9
  def usage_from_engine(usage: Any) -> TokenUsage | None:
10
10
  if usage is None:
11
11
  return None
12
+ if isinstance(usage, dict):
13
+ return TokenUsage(**usage)
12
14
  return TokenUsage(
13
15
  input_tokens=getattr(usage, "input_tokens", None),
14
16
  output_tokens=getattr(usage, "output_tokens", None),
@@ -21,14 +23,28 @@ def usage_from_engine(usage: Any) -> TokenUsage | None:
21
23
 
22
24
 
23
25
  def response_from_engine(resp: Any) -> Response:
26
+ if isinstance(resp, dict):
27
+ return Response(
28
+ id=resp.get("id", ""),
29
+ output=resp.get("output", []) or [],
30
+ output_text=resp.get("output_text", "") or "",
31
+ usage=usage_from_engine(resp.get("usage", None)),
32
+ error=resp.get("error", None),
33
+ reasoning_summary=resp.get("reasoning_summary", None),
34
+ reasoning_items=resp.get("reasoning_items", []) or [],
35
+ encrypted_reasoning_content=resp.get("encrypted_reasoning_content", None),
36
+ finish_reason=resp.get("finish_reason", None),
37
+ previous_response_id=resp.get("previous_response_id", None),
38
+ raw_response=resp.get("raw_response", None),
39
+ )
24
40
  return Response(
25
41
  id=getattr(resp, "id", ""),
26
- output=list(getattr(resp, "output", []) or []),
42
+ output=getattr(resp, "output", []) or [],
27
43
  output_text=getattr(resp, "output_text", "") or "",
28
44
  usage=usage_from_engine(getattr(resp, "usage", None)),
29
45
  error=getattr(resp, "error", None),
30
46
  reasoning_summary=getattr(resp, "reasoning_summary", None),
31
- reasoning_items=list(getattr(resp, "reasoning_items", []) or []),
47
+ reasoning_items=getattr(resp, "reasoning_items", []) or [],
32
48
  encrypted_reasoning_content=getattr(resp, "encrypted_reasoning_content", None),
33
49
  finish_reason=getattr(resp, "finish_reason", None),
34
50
  previous_response_id=getattr(resp, "previous_response_id", None),
@@ -37,6 +53,18 @@ def response_from_engine(resp: Any) -> Response:
37
53
 
38
54
 
39
55
  def event_from_engine(event: Any) -> ResponseStreamEvent:
56
+ if isinstance(event, dict):
57
+ return ResponseStreamEvent(
58
+ type=event.get("type", "event"),
59
+ delta=event.get("delta", None),
60
+ usage=usage_from_engine(event.get("usage", None)),
61
+ raw=event.get("raw", None),
62
+ error=event.get("error", None),
63
+ call_id=event.get("call_id", None),
64
+ response_id=event.get("response_id", None),
65
+ finish_reason=event.get("finish_reason", None),
66
+ schema_version=event.get("schema_version", "v1"),
67
+ )
40
68
  return ResponseStreamEvent(
41
69
  type=getattr(event, "type", "event"),
42
70
  delta=getattr(event, "delta", None),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oauth-codex
3
- Version: 3.2.0
3
+ Version: 3.2.2
4
4
  Summary: Codex OAuth-based Python SDK with a single Client and generate-first API
5
5
  Author: Codex
6
6
  Requires-Python: >=3.11
File without changes
File without changes