oauth-codex 2.0.0__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.
Files changed (64) hide show
  1. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/PKG-INFO +22 -22
  2. oauth_codex-2.0.2/README.md +89 -0
  3. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/pyproject.toml +1 -1
  4. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/_client.py +5 -12
  5. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/_engine.py +372 -49
  6. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/_version.py +1 -1
  7. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/core_types.py +1 -1
  8. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/tooling.py +36 -11
  9. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex.egg-info/PKG-INFO +22 -22
  10. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex.egg-info/SOURCES.txt +1 -0
  11. oauth_codex-2.0.2/tests/test_engine_stream_and_continuity.py +170 -0
  12. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/tests/test_generate_sync.py +27 -0
  13. oauth_codex-2.0.0/README.md +0 -89
  14. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/setup.cfg +0 -0
  15. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/__init__.py +0 -0
  16. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/_base_client.py +0 -0
  17. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/_exceptions.py +0 -0
  18. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/_models.py +0 -0
  19. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/_module_client.py +0 -0
  20. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/_resource.py +0 -0
  21. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/_types.py +0 -0
  22. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/auth/__init__.py +0 -0
  23. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/auth/config.py +0 -0
  24. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/auth/pkce.py +0 -0
  25. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/auth/store.py +0 -0
  26. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/auth/token_manager.py +0 -0
  27. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/compat_store.py +0 -0
  28. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/errors.py +0 -0
  29. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/py.typed +0 -0
  30. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/resources/__init__.py +0 -0
  31. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/resources/_wrappers.py +0 -0
  32. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/resources/files.py +0 -0
  33. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/resources/models.py +0 -0
  34. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/resources/responses/__init__.py +0 -0
  35. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/resources/responses/_helpers.py +0 -0
  36. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/resources/responses/input_tokens.py +0 -0
  37. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/resources/responses/responses.py +0 -0
  38. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/resources/vector_stores/__init__.py +0 -0
  39. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/resources/vector_stores/file_batches.py +0 -0
  40. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/resources/vector_stores/files.py +0 -0
  41. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/resources/vector_stores/vector_stores.py +0 -0
  42. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/store.py +0 -0
  43. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/__init__.py +0 -0
  44. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/file_deleted.py +0 -0
  45. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/file_object.py +0 -0
  46. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/responses/__init__.py +0 -0
  47. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/responses/input_token_count_response.py +0 -0
  48. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/responses/response.py +0 -0
  49. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/responses/response_stream_event.py +0 -0
  50. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/shared/__init__.py +0 -0
  51. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/shared/model_capabilities.py +0 -0
  52. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/shared/usage.py +0 -0
  53. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/vector_stores/__init__.py +0 -0
  54. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/vector_stores/vector_store.py +0 -0
  55. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/vector_stores/vector_store_deleted.py +0 -0
  56. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/vector_stores/vector_store_file.py +0 -0
  57. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/vector_stores/vector_store_file_batch.py +0 -0
  58. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/types/vector_stores/vector_store_search_response.py +0 -0
  59. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex/version.py +0 -0
  60. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex.egg-info/dependency_links.txt +0 -0
  61. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex.egg-info/requires.txt +0 -0
  62. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/src/oauth_codex.egg-info/top_level.txt +0 -0
  63. {oauth_codex-2.0.0 → oauth_codex-2.0.2}/tests/test_generate_async.py +0 -0
  64. {oauth_codex-2.0.0 → oauth_codex-2.0.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: 2.0.0
3
+ Version: 2.0.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
@@ -16,22 +16,22 @@ Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
16
16
 
17
17
  # oauth-codex
18
18
 
19
- OAuth PKCE 기반 Codex Python SDK입니다.
19
+ OAuth PKCE-based Python SDK for the Codex backend.
20
20
 
21
- ## 핵심 변경점 (v2)
21
+ ## Key Changes (v2)
22
22
 
23
- - 공개 클라이언트는 `Client` 하나만 제공합니다.
24
- - 기본 사용 흐름은 `generate` 중심입니다.
25
- - async는 동일 클래스의 `agenerate`, `astream` 메서드로 제공합니다.
26
- - 텍스트 생성, 이미지 입력 분석, function calling 자동 실행, `reasoning_effort`를 지원합니다.
23
+ - The public API now exposes a single `Client`.
24
+ - The default workflow is centered around `generate`.
25
+ - Async support is provided on the same class via `agenerate` and `astream`.
26
+ - Supports text generation, image input analysis, automatic function-calling execution, and `reasoning_effort`.
27
27
 
28
- ## 설치
28
+ ## Installation
29
29
 
30
30
  ```bash
31
31
  pip install oauth-codex
32
32
  ```
33
33
 
34
- ## 빠른 시작
34
+ ## Quick Start
35
35
 
36
36
  ```python
37
37
  from oauth_codex import Client
@@ -41,30 +41,30 @@ text = client.generate("hello")
41
41
  print(text)
42
42
  ```
43
43
 
44
- ## 이미지 입력
44
+ ## Image Input
45
45
 
46
46
  ```python
47
47
  text = client.generate(
48
- " 이미지를 설명해줘",
48
+ "Describe this image",
49
49
  images=["https://example.com/cat.png", "./local-photo.jpg"],
50
50
  )
51
51
  print(text)
52
52
  ```
53
53
 
54
- ## Function Calling (자동 루프)
54
+ ## Function Calling (Automatic Loop)
55
55
 
56
56
  ```python
57
57
  def add(a: int, b: int) -> dict:
58
58
  return {"sum": a + b}
59
59
 
60
60
  text = client.generate(
61
- "2+3 계산해줘",
61
+ "Calculate 2+3",
62
62
  tools=[add],
63
63
  )
64
64
  print(text)
65
65
  ```
66
66
 
67
- 실행 예외가 발생하면 SDK `{\"error\": ...}` 형태로 모델에 전달하고 루프를 계속 진행합니다.
67
+ If a tool raises an exception, the SDK forwards it to the model as `{\"error\": ...}` and continues the loop.
68
68
 
69
69
  ## Async
70
70
 
@@ -82,22 +82,22 @@ async def main() -> None:
82
82
  asyncio.run(main())
83
83
  ```
84
84
 
85
- ## 버전 2.0 브레이킹 변경
85
+ ## Breaking Changes in v2.0
86
86
 
87
- - 제거됨: `AsyncOAuthCodexClient`, module-level proxies, `client.responses/files/vector_stores/models`, `oauth_codex.compat`
88
- - 단일 진입점: `Client.generate/stream/agenerate/astream`
87
+ - Removed: `AsyncOAuthCodexClient`, module-level proxies, `client.responses/files/vector_stores/models`, `oauth_codex.compat`
88
+ - Single entry points: `Client.generate/stream/agenerate/astream`
89
89
 
90
- ## 문서
90
+ ## Documentation
91
91
 
92
- - 영문 인덱스: [`docs/en/index.md`](docs/en/index.md)
93
- - 국문 인덱스: [`docs/ko/index.md`](docs/ko/index.md)
92
+ - English index: [`docs/en/index.md`](docs/en/index.md)
93
+ - Korean index: [`docs/ko/index.md`](docs/ko/index.md)
94
94
 
95
- ## 개발
95
+ ## Development
96
96
 
97
97
  ```bash
98
98
  pytest -q
99
99
  ```
100
100
 
101
- ## 변경 이력
101
+ ## Changelog
102
102
 
103
103
  - [`CHANGELOG.md`](CHANGELOG.md)
@@ -0,0 +1,89 @@
1
+ [English](README.md) | [한국어](README.ko.md)
2
+
3
+ # oauth-codex
4
+
5
+ OAuth PKCE-based Python SDK for the Codex backend.
6
+
7
+ ## Key Changes (v2)
8
+
9
+ - The public API now exposes a single `Client`.
10
+ - The default workflow is centered around `generate`.
11
+ - Async support is provided on the same class via `agenerate` and `astream`.
12
+ - Supports text generation, image input analysis, automatic function-calling execution, and `reasoning_effort`.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install oauth-codex
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ```python
23
+ from oauth_codex import Client
24
+
25
+ client = Client()
26
+ text = client.generate("hello")
27
+ print(text)
28
+ ```
29
+
30
+ ## Image Input
31
+
32
+ ```python
33
+ text = client.generate(
34
+ "Describe this image",
35
+ images=["https://example.com/cat.png", "./local-photo.jpg"],
36
+ )
37
+ print(text)
38
+ ```
39
+
40
+ ## Function Calling (Automatic Loop)
41
+
42
+ ```python
43
+ def add(a: int, b: int) -> dict:
44
+ return {"sum": a + b}
45
+
46
+ text = client.generate(
47
+ "Calculate 2+3",
48
+ tools=[add],
49
+ )
50
+ print(text)
51
+ ```
52
+
53
+ If a tool raises an exception, the SDK forwards it to the model as `{\"error\": ...}` and continues the loop.
54
+
55
+ ## Async
56
+
57
+ ```python
58
+ import asyncio
59
+ from oauth_codex import Client
60
+
61
+
62
+ async def main() -> None:
63
+ client = Client()
64
+ text = await client.agenerate("hello async")
65
+ print(text)
66
+
67
+
68
+ asyncio.run(main())
69
+ ```
70
+
71
+ ## Breaking Changes in v2.0
72
+
73
+ - Removed: `AsyncOAuthCodexClient`, module-level proxies, `client.responses/files/vector_stores/models`, `oauth_codex.compat`
74
+ - Single entry points: `Client.generate/stream/agenerate/astream`
75
+
76
+ ## Documentation
77
+
78
+ - English index: [`docs/en/index.md`](docs/en/index.md)
79
+ - Korean index: [`docs/ko/index.md`](docs/ko/index.md)
80
+
81
+ ## Development
82
+
83
+ ```bash
84
+ pytest -q
85
+ ```
86
+
87
+ ## Changelog
88
+
89
+ - [`CHANGELOG.md`](CHANGELOG.md)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "oauth-codex"
7
- version = "2.0.0"
7
+ version = "2.0.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"
@@ -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: str | dict[str, Any]
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: str | dict[str, Any]
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) -> str | dict[str, Any]:
415
- if isinstance(output, dict):
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