codex-sdk-python 0.101.0__tar.gz → 0.104.0__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 (20) hide show
  1. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/PKG-INFO +17 -4
  2. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/README.md +16 -3
  3. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/pyproject.toml +2 -2
  4. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/__init__.py +5 -1
  5. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/app_server.py +90 -9
  6. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/abort.py +0 -0
  7. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/codex.py +0 -0
  8. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/config_overrides.py +0 -0
  9. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/events.py +0 -0
  10. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/exceptions.py +0 -0
  11. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/exec.py +0 -0
  12. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/hooks.py +0 -0
  13. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/integrations/__init__.py +0 -0
  14. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/integrations/pydantic_ai.py +0 -0
  15. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/integrations/pydantic_ai_model.py +0 -0
  16. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/items.py +0 -0
  17. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/options.py +0 -0
  18. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/telemetry.py +0 -0
  19. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/thread.py +0 -0
  20. {codex_sdk_python-0.101.0 → codex_sdk_python-0.104.0}/src/codex_sdk/tool_envelope.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: codex-sdk-python
3
- Version: 0.101.0
3
+ Version: 0.104.0
4
4
  Summary: Python SDK for the Codex CLI agent with async threads, streaming events, and structured outputs
5
5
  Keywords: codex,sdk,python,api,cli,agent,async,streaming
6
6
  Author: Vectorfy Co
@@ -44,7 +44,7 @@ Embed the Codex agent in Python workflows. This SDK wraps the bundled `codex` CL
44
44
  <td><strong>Lifecycle</strong></td>
45
45
  <td>
46
46
  <a href="#ci-cd"><img src="https://img.shields.io/badge/CI%2FCD-Active-16a34a?style=flat&logo=githubactions&logoColor=white" alt="CI/CD badge" /></a>
47
- <img src="https://img.shields.io/badge/Release-0.101.0-6b7280?style=flat&logo=pypi&logoColor=white" alt="Release 0.101.0 badge" />
47
+ <img src="https://img.shields.io/badge/Release-0.104.0-6b7280?style=flat&logo=pypi&logoColor=white" alt="Release 0.104.0 badge" />
48
48
  <a href="#license"><img src="https://img.shields.io/badge/License-Apache--2.0-0f766e?style=flat&logo=apache&logoColor=white" alt="License badge" /></a>
49
49
  </td>
50
50
  </tr>
@@ -366,8 +366,21 @@ for payload shapes and event semantics.
366
366
  Note: some endpoints and fields are gated behind an experimental capability; set
367
367
  `AppServerOptions(experimental_api_enabled=True)` to opt in.
368
368
 
369
- `thread_list` supports `archived`, `sort_key`, and `source_kinds` filters, and `config_read` accepts an optional `cwd`
370
- to compute the effective layered config for a specific working directory.
369
+ `thread_list` supports `archived`, `sort_key`, and `source_kinds` filters (unchanged), and now also accepts `cwd`
370
+ for scoped thread queries. `config_read` accepts an optional `cwd` to compute effective layered config for a specific
371
+ working directory.
372
+
373
+ `skills_remote_read` supports `cwds`, `enabled`, `hazelnut_scope`, and `product_surface` filters. `model_list` accepts
374
+ an optional `include_hidden` flag.
375
+
376
+ ```python
377
+ threads = await app.thread_list(archived=False, sort_key="updatedAt", source_kinds=["local"], cwd=".")
378
+ config = await app.config_read(include_layers=True, cwd=".")
379
+ skills = await app.skills_remote_read(
380
+ cwds=["."], enabled=True, hazelnut_scope="user", product_surface="codex_desktop"
381
+ )
382
+ models = await app.model_list(limit=20, include_hidden=False)
383
+ ```
371
384
 
372
385
  ### Observability (OTEL) and notify
373
386
 
@@ -8,7 +8,7 @@ Embed the Codex agent in Python workflows. This SDK wraps the bundled `codex` CL
8
8
  <td><strong>Lifecycle</strong></td>
9
9
  <td>
10
10
  <a href="#ci-cd"><img src="https://img.shields.io/badge/CI%2FCD-Active-16a34a?style=flat&logo=githubactions&logoColor=white" alt="CI/CD badge" /></a>
11
- <img src="https://img.shields.io/badge/Release-0.101.0-6b7280?style=flat&logo=pypi&logoColor=white" alt="Release 0.101.0 badge" />
11
+ <img src="https://img.shields.io/badge/Release-0.104.0-6b7280?style=flat&logo=pypi&logoColor=white" alt="Release 0.104.0 badge" />
12
12
  <a href="#license"><img src="https://img.shields.io/badge/License-Apache--2.0-0f766e?style=flat&logo=apache&logoColor=white" alt="License badge" /></a>
13
13
  </td>
14
14
  </tr>
@@ -330,8 +330,21 @@ for payload shapes and event semantics.
330
330
  Note: some endpoints and fields are gated behind an experimental capability; set
331
331
  `AppServerOptions(experimental_api_enabled=True)` to opt in.
332
332
 
333
- `thread_list` supports `archived`, `sort_key`, and `source_kinds` filters, and `config_read` accepts an optional `cwd`
334
- to compute the effective layered config for a specific working directory.
333
+ `thread_list` supports `archived`, `sort_key`, and `source_kinds` filters (unchanged), and now also accepts `cwd`
334
+ for scoped thread queries. `config_read` accepts an optional `cwd` to compute effective layered config for a specific
335
+ working directory.
336
+
337
+ `skills_remote_read` supports `cwds`, `enabled`, `hazelnut_scope`, and `product_surface` filters. `model_list` accepts
338
+ an optional `include_hidden` flag.
339
+
340
+ ```python
341
+ threads = await app.thread_list(archived=False, sort_key="updatedAt", source_kinds=["local"], cwd=".")
342
+ config = await app.config_read(include_layers=True, cwd=".")
343
+ skills = await app.skills_remote_read(
344
+ cwds=["."], enabled=True, hazelnut_scope="user", product_surface="codex_desktop"
345
+ )
346
+ models = await app.model_list(limit=20, include_hidden=False)
347
+ ```
335
348
 
336
349
  ### Observability (OTEL) and notify
337
350
 
@@ -1,10 +1,10 @@
1
1
  [build-system]
2
- requires = ["uv_build>=0.9.21,<0.10.0"]
2
+ requires = ["uv_build>=0.9.21,<0.11.0"]
3
3
  build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "codex-sdk-python"
7
- version = "0.101.0"
7
+ version = "0.104.0"
8
8
  description = "Python SDK for the Codex CLI agent with async threads, streaming events, and structured outputs"
9
9
  readme = "README.md"
10
10
  license = {text = "Apache-2.0"}
@@ -15,6 +15,8 @@ from .app_server import (
15
15
  AppServerRequest,
16
16
  AppServerTurnSession,
17
17
  AppServerUserInput,
18
+ SkillsRemoteReadRequest,
19
+ SkillsRemoteWriteRequest,
18
20
  )
19
21
  from .codex import Codex
20
22
  from .events import (
@@ -77,7 +79,7 @@ from .thread import (
77
79
  Turn,
78
80
  )
79
81
 
80
- __version__ = "0.101.0"
82
+ __version__ = "0.104.0"
81
83
 
82
84
  __all__ = [
83
85
  "AbortController",
@@ -92,6 +94,8 @@ __all__ = [
92
94
  "ApprovalDecisions",
93
95
  "AppServerInput",
94
96
  "AppServerUserInput",
97
+ "SkillsRemoteReadRequest",
98
+ "SkillsRemoteWriteRequest",
95
99
  "Thread",
96
100
  "ThreadHooks",
97
101
  "Input",
@@ -558,6 +558,7 @@ class AppServerClient:
558
558
  model_providers: Optional[Sequence[str]] = None,
559
559
  source_kinds: Optional[Sequence[str]] = None,
560
560
  archived: Optional[bool] = None,
561
+ cwd: Optional[Union[str, Path]] = None,
561
562
  ) -> Dict[str, Any]:
562
563
  """
563
564
  Retrieve a page of threads from the app-server with optional filtering and sorting.
@@ -570,6 +571,7 @@ class AppServerClient:
570
571
  source_kinds: Filter threads by one or more source kinds.
571
572
  archived: If set, restrict results to archived (`True`) or unarchived (`False`)
572
573
  threads.
574
+ cwd: Optional working directory scope for server-side filtering.
573
575
 
574
576
  Returns:
575
577
  The raw response dictionary returned by the app-server for the `thread/list`
@@ -588,6 +590,8 @@ class AppServerClient:
588
590
  params["source_kinds"] = list(source_kinds)
589
591
  if archived is not None:
590
592
  params["archived"] = archived
593
+ if cwd is not None:
594
+ params["cwd"] = str(cwd)
591
595
  return await self._request_dict("thread/list", _coerce_keys(params) or None)
592
596
 
593
597
  async def thread_read(
@@ -769,26 +773,54 @@ class AppServerClient:
769
773
  return await self._request_dict("skills/list", _coerce_keys(payload))
770
774
 
771
775
  async def skills_remote_read(
772
- self, *, params: Optional[Mapping[str, Any]] = None
776
+ self,
777
+ *,
778
+ cwds: Optional[Sequence[Union[str, Path]]] = None,
779
+ enabled: Optional[bool] = None,
780
+ hazelnut_scope: Optional[str] = None,
781
+ product_surface: Optional[str] = None,
782
+ params: Optional["SkillsRemoteReadRequest"] = None,
773
783
  ) -> Dict[str, Any]:
774
784
  """
775
785
  Read remote skills metadata from the app server.
776
786
 
777
787
  Args:
778
- params: Optional request payload.
788
+ cwds: Optional workspace roots to scope the remote skill listing.
789
+ enabled: Optional filter for enabled/disabled remote skills.
790
+ hazelnut_scope: Optional Hazelnut scope identifier.
791
+ product_surface: Optional product surface identifier.
792
+ params: Optional raw request payload for protocol-forward fields.
779
793
 
780
794
  Returns:
781
795
  result (Dict[str, Any]): The app-server response payload for the `skills/remote/read` request.
782
796
  """
783
- payload = _coerce_keys(dict(params)) if params is not None else {}
784
- return await self._request_dict("skills/remote/read", payload)
797
+ payload: Dict[str, Any] = {}
798
+ if params is not None:
799
+ _validate_alias_conflicts(
800
+ params,
801
+ (
802
+ ("hazelnut_scope", "hazelnutScope"),
803
+ ("product_surface", "productSurface"),
804
+ ),
805
+ context="SkillsRemoteReadRequest",
806
+ )
807
+ payload.update(dict(params))
808
+ if cwds is not None:
809
+ payload["cwds"] = [str(path) for path in cwds]
810
+ if enabled is not None:
811
+ payload["enabled"] = enabled
812
+ if hazelnut_scope is not None:
813
+ payload["hazelnut_scope"] = hazelnut_scope
814
+ if product_surface is not None:
815
+ payload["product_surface"] = product_surface
816
+ return await self._request_dict("skills/remote/read", _coerce_keys(payload))
785
817
 
786
818
  async def skills_remote_write(
787
819
  self,
788
820
  *,
789
821
  hazelnut_id: Optional[str] = None,
790
822
  is_preload: Optional[bool] = None,
791
- params: Optional[Mapping[str, Any]] = None,
823
+ params: Optional["SkillsRemoteWriteRequest"] = None,
792
824
  ) -> Dict[str, Any]:
793
825
  """
794
826
  Start a remote skill write operation.
@@ -803,12 +835,20 @@ class AppServerClient:
803
835
  """
804
836
  payload: Dict[str, Any] = {}
805
837
  if params is not None:
806
- payload.update(_coerce_keys(dict(params)))
838
+ _validate_alias_conflicts(
839
+ params,
840
+ (
841
+ ("hazelnut_id", "hazelnutId"),
842
+ ("is_preload", "isPreload"),
843
+ ),
844
+ context="SkillsRemoteWriteRequest",
845
+ )
846
+ payload.update(dict(params))
807
847
  if hazelnut_id is not None:
808
848
  payload["hazelnut_id"] = hazelnut_id
809
849
  if is_preload is not None:
810
850
  payload["is_preload"] = is_preload
811
- return await self._request_dict("skills/remote/write", payload)
851
+ return await self._request_dict("skills/remote/write", _coerce_keys(payload))
812
852
 
813
853
  async def skills_config_write(
814
854
  self,
@@ -924,7 +964,11 @@ class AppServerClient:
924
964
  return await self._request_dict("turn/steer", _coerce_keys(payload))
925
965
 
926
966
  async def model_list(
927
- self, *, cursor: Optional[str] = None, limit: Optional[int] = None
967
+ self,
968
+ *,
969
+ cursor: Optional[str] = None,
970
+ limit: Optional[int] = None,
971
+ include_hidden: Optional[bool] = None,
928
972
  ) -> Dict[str, Any]:
929
973
  """List models available to the app-server."""
930
974
  params: Dict[str, Any] = {}
@@ -932,7 +976,9 @@ class AppServerClient:
932
976
  params["cursor"] = cursor
933
977
  if limit is not None:
934
978
  params["limit"] = limit
935
- return await self._request_dict("model/list", params or None)
979
+ if include_hidden is not None:
980
+ params["include_hidden"] = include_hidden
981
+ return await self._request_dict("model/list", _coerce_keys(params) or None)
936
982
 
937
983
  async def app_list(
938
984
  self, *, cursor: Optional[str] = None, limit: Optional[int] = None
@@ -1309,6 +1355,26 @@ class SkillsConfigWriteRequest(TypedDict, total=False):
1309
1355
  mode: str
1310
1356
 
1311
1357
 
1358
+ class SkillsRemoteReadRequest(TypedDict, total=False):
1359
+ """Typed payload for `skills/remote/read` requests."""
1360
+
1361
+ cwds: List[str]
1362
+ enabled: bool
1363
+ hazelnut_scope: str
1364
+ hazelnutScope: str
1365
+ product_surface: str
1366
+ productSurface: str
1367
+
1368
+
1369
+ class SkillsRemoteWriteRequest(TypedDict, total=False):
1370
+ """Typed payload for `skills/remote/write` requests."""
1371
+
1372
+ hazelnut_id: str
1373
+ hazelnutId: str
1374
+ is_preload: bool
1375
+ isPreload: bool
1376
+
1377
+
1312
1378
  class ItemToolCallRequest(TypedDict, total=False):
1313
1379
  """Typed payload for `item/tool/call` requests."""
1314
1380
 
@@ -1392,6 +1458,21 @@ def _coerce_keys(params: Mapping[str, Any]) -> Dict[str, Any]:
1392
1458
  return coerced
1393
1459
 
1394
1460
 
1461
+ def _validate_alias_conflicts(
1462
+ params: Mapping[str, Any],
1463
+ alias_pairs: Sequence[tuple[str, str]],
1464
+ *,
1465
+ context: str,
1466
+ ) -> None:
1467
+ """Reject payloads that provide both snake_case and camelCase aliases."""
1468
+ for snake_case_key, camel_case_key in alias_pairs:
1469
+ if snake_case_key in params and camel_case_key in params:
1470
+ raise CodexError(
1471
+ f"{context} received both '{snake_case_key}' and "
1472
+ f"'{camel_case_key}'. Provide only one key variant."
1473
+ )
1474
+
1475
+
1395
1476
  def _snake_to_camel(value: str) -> str:
1396
1477
  """Convert snake_case strings to lowerCamelCase."""
1397
1478
  parts = value.split("_")