oauth-codex 2.0.1__tar.gz → 2.0.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.
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/PKG-INFO +1 -1
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/pyproject.toml +1 -1
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/_client.py +5 -12
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/_engine.py +14 -3
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/_version.py +1 -1
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/core_types.py +1 -1
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/tooling.py +13 -3
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex.egg-info/PKG-INFO +1 -1
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/tests/test_engine_stream_and_continuity.py +1 -3
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/tests/test_generate_sync.py +27 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/README.md +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/setup.cfg +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/__init__.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/_base_client.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/_exceptions.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/_models.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/_module_client.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/_resource.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/_types.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/auth/__init__.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/auth/config.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/auth/pkce.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/auth/store.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/auth/token_manager.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/compat_store.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/errors.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/py.typed +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/resources/__init__.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/resources/_wrappers.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/resources/files.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/resources/models.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/resources/responses/__init__.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/resources/responses/_helpers.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/resources/responses/input_tokens.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/resources/responses/responses.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/resources/vector_stores/__init__.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/resources/vector_stores/file_batches.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/resources/vector_stores/files.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/resources/vector_stores/vector_stores.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/store.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/__init__.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/file_deleted.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/file_object.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/responses/__init__.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/responses/input_token_count_response.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/responses/response.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/responses/response_stream_event.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/shared/__init__.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/shared/model_capabilities.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/shared/usage.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/vector_stores/__init__.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/vector_stores/vector_store.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/vector_stores/vector_store_deleted.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/vector_stores/vector_store_file.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/vector_stores/vector_store_file_batch.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/vector_stores/vector_store_search_response.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/version.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex.egg-info/SOURCES.txt +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex.egg-info/dependency_links.txt +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex.egg-info/requires.txt +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex.egg-info/top_level.txt +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/tests/test_generate_async.py +0 -0
- {oauth_codex-2.0.1 → oauth_codex-2.0.2}/tests/test_public_surface.py +0 -0
|
@@ -20,7 +20,7 @@ from .core_types import (
|
|
|
20
20
|
ToolResult,
|
|
21
21
|
)
|
|
22
22
|
from .store import FallbackTokenStore
|
|
23
|
-
from .tooling import callable_to_tool_schema
|
|
23
|
+
from .tooling import callable_to_tool_schema, normalize_tool_output
|
|
24
24
|
|
|
25
25
|
DEFAULT_MODEL = "gpt-5.3-codex"
|
|
26
26
|
DEFAULT_MAX_TOOL_ROUNDS = 8
|
|
@@ -364,7 +364,7 @@ class OAuthCodexClient(SyncAPIClient):
|
|
|
364
364
|
) -> list[ToolResult]:
|
|
365
365
|
results: list[ToolResult] = []
|
|
366
366
|
for call in tool_calls:
|
|
367
|
-
output:
|
|
367
|
+
output: dict[str, Any]
|
|
368
368
|
tool = tools_by_name.get(call.name)
|
|
369
369
|
if tool is None:
|
|
370
370
|
output = {"error": f"tool not found: {call.name}"}
|
|
@@ -387,7 +387,7 @@ class OAuthCodexClient(SyncAPIClient):
|
|
|
387
387
|
) -> list[ToolResult]:
|
|
388
388
|
results: list[ToolResult] = []
|
|
389
389
|
for call in tool_calls:
|
|
390
|
-
output:
|
|
390
|
+
output: dict[str, Any]
|
|
391
391
|
tool = tools_by_name.get(call.name)
|
|
392
392
|
if tool is None:
|
|
393
393
|
output = {"error": f"tool not found: {call.name}"}
|
|
@@ -411,15 +411,8 @@ class OAuthCodexClient(SyncAPIClient):
|
|
|
411
411
|
raise TypeError("tool arguments must be a JSON object")
|
|
412
412
|
return parsed
|
|
413
413
|
|
|
414
|
-
def _normalize_tool_output(self, output: Any) ->
|
|
415
|
-
|
|
416
|
-
return output
|
|
417
|
-
if isinstance(output, str):
|
|
418
|
-
return output
|
|
419
|
-
try:
|
|
420
|
-
return json.dumps(output, ensure_ascii=True)
|
|
421
|
-
except TypeError:
|
|
422
|
-
return str(output)
|
|
414
|
+
def _normalize_tool_output(self, output: Any) -> dict[str, Any]:
|
|
415
|
+
return normalize_tool_output(output)
|
|
423
416
|
|
|
424
417
|
|
|
425
418
|
Client = OAuthCodexClient
|
|
@@ -40,7 +40,12 @@ from .errors import (
|
|
|
40
40
|
TokenRefreshError,
|
|
41
41
|
)
|
|
42
42
|
from .store import FallbackTokenStore
|
|
43
|
-
from .tooling import
|
|
43
|
+
from .tooling import (
|
|
44
|
+
normalize_tool_inputs,
|
|
45
|
+
normalize_tool_output,
|
|
46
|
+
to_responses_tools,
|
|
47
|
+
tool_results_to_response_items,
|
|
48
|
+
)
|
|
44
49
|
from .core_types import (
|
|
45
50
|
GenerateResult,
|
|
46
51
|
InputTokensCountResult,
|
|
@@ -1408,14 +1413,20 @@ class OAuthCodexClient:
|
|
|
1408
1413
|
normalized: list[ToolResult] = []
|
|
1409
1414
|
for item in tool_results:
|
|
1410
1415
|
if isinstance(item, ToolResult):
|
|
1411
|
-
normalized.append(
|
|
1416
|
+
normalized.append(
|
|
1417
|
+
ToolResult(
|
|
1418
|
+
tool_call_id=item.tool_call_id,
|
|
1419
|
+
name=item.name,
|
|
1420
|
+
output=normalize_tool_output(item.output),
|
|
1421
|
+
)
|
|
1422
|
+
)
|
|
1412
1423
|
continue
|
|
1413
1424
|
if isinstance(item, dict):
|
|
1414
1425
|
normalized.append(
|
|
1415
1426
|
ToolResult(
|
|
1416
1427
|
tool_call_id=str(item["tool_call_id"]),
|
|
1417
1428
|
name=str(item["name"]),
|
|
1418
|
-
output=item
|
|
1429
|
+
output=normalize_tool_output(item.get("output")),
|
|
1419
1430
|
)
|
|
1420
1431
|
)
|
|
1421
1432
|
continue
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__title__ = "oauth-codex"
|
|
2
|
-
__version__ = "2.0.
|
|
2
|
+
__version__ = "2.0.2"
|
|
@@ -157,10 +157,20 @@ def to_responses_tools(
|
|
|
157
157
|
return normalized
|
|
158
158
|
|
|
159
159
|
|
|
160
|
-
def
|
|
161
|
-
if isinstance(output,
|
|
160
|
+
def normalize_tool_output(output: Any) -> dict[str, Any]:
|
|
161
|
+
if isinstance(output, dict):
|
|
162
162
|
return output
|
|
163
|
-
|
|
163
|
+
if isinstance(output, str):
|
|
164
|
+
return {"output": output}
|
|
165
|
+
try:
|
|
166
|
+
json.dumps(output, ensure_ascii=True)
|
|
167
|
+
return {"output": output}
|
|
168
|
+
except TypeError:
|
|
169
|
+
return {"output": str(output)}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def serialize_tool_output(output: Any) -> str:
|
|
173
|
+
return json.dumps(normalize_tool_output(output), ensure_ascii=True)
|
|
164
174
|
|
|
165
175
|
|
|
166
176
|
def tool_results_to_response_items(tool_results: list[ToolResult] | None) -> list[dict[str, Any]]:
|
|
@@ -77,9 +77,7 @@ def test_map_stream_raises_when_call_id_cannot_be_restored() -> None:
|
|
|
77
77
|
|
|
78
78
|
def test_tool_results_to_response_items_rejects_empty_tool_call_id() -> None:
|
|
79
79
|
with pytest.raises(SDKRequestError) as exc_info:
|
|
80
|
-
tool_results_to_response_items(
|
|
81
|
-
[ToolResult(tool_call_id=" ", name="tool", output="This is a tool response.")]
|
|
82
|
-
)
|
|
80
|
+
tool_results_to_response_items([ToolResult(tool_call_id=" ", name="tool", output={"ok": True})])
|
|
83
81
|
assert exc_info.value.provider_code == "invalid_tool_call_id"
|
|
84
82
|
|
|
85
83
|
|
|
@@ -120,6 +120,33 @@ def test_generate_tool_failure_is_forwarded_to_model(monkeypatch: pytest.MonkeyP
|
|
|
120
120
|
assert tool_results[0].output == {"error": "boom"}
|
|
121
121
|
|
|
122
122
|
|
|
123
|
+
def test_generate_wraps_string_tool_output_as_dict(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
124
|
+
client = _client()
|
|
125
|
+
calls: list[dict[str, object]] = []
|
|
126
|
+
|
|
127
|
+
def fake_generate(**kwargs):
|
|
128
|
+
calls.append(kwargs)
|
|
129
|
+
if len(calls) == 1:
|
|
130
|
+
return GenerateResult(
|
|
131
|
+
text="",
|
|
132
|
+
tool_calls=[ToolCall(id="call_1", name="echo", arguments_json='{"query":"hello"}')],
|
|
133
|
+
finish_reason="tool_calls",
|
|
134
|
+
response_id="resp_1",
|
|
135
|
+
)
|
|
136
|
+
return GenerateResult(text="done", tool_calls=[], finish_reason="stop", response_id="resp_2")
|
|
137
|
+
|
|
138
|
+
monkeypatch.setattr(client._engine, "generate", fake_generate)
|
|
139
|
+
|
|
140
|
+
def echo(query: str) -> str:
|
|
141
|
+
return query
|
|
142
|
+
|
|
143
|
+
out = client.generate("run once", tools=[echo])
|
|
144
|
+
|
|
145
|
+
assert out == "done"
|
|
146
|
+
tool_results = calls[1]["tool_results"]
|
|
147
|
+
assert tool_results[0].output == {"output": "hello"}
|
|
148
|
+
|
|
149
|
+
|
|
123
150
|
def test_generate_raises_when_tool_round_limit_exceeded(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
124
151
|
client = _client()
|
|
125
152
|
client.max_tool_rounds = 2
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/resources/vector_stores/file_batches.py
RENAMED
|
File without changes
|
|
File without changes
|
{oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/resources/vector_stores/vector_stores.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/responses/response_stream_event.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/vector_stores/vector_store_deleted.py
RENAMED
|
File without changes
|
{oauth_codex-2.0.1 → oauth_codex-2.0.2}/src/oauth_codex/types/vector_stores/vector_store_file.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|