codex-sdk-python 0.98.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.
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/PKG-INFO +21 -7
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/README.md +19 -5
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/pyproject.toml +3 -6
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/__init__.py +5 -11
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/app_server.py +309 -16
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/integrations/pydantic_ai_model.py +122 -81
- codex_sdk_python-0.104.0/src/codex_sdk/tool_envelope.py +524 -0
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/abort.py +0 -0
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/codex.py +0 -0
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/config_overrides.py +0 -0
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/events.py +0 -0
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/exceptions.py +0 -0
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/exec.py +0 -0
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/hooks.py +0 -0
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/integrations/__init__.py +0 -0
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/integrations/pydantic_ai.py +0 -0
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/items.py +0 -0
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/options.py +0 -0
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/telemetry.py +0 -0
- {codex_sdk_python-0.98.0 → codex_sdk_python-0.104.0}/src/codex_sdk/thread.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: codex-sdk-python
|
|
3
|
-
Version: 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
|
|
@@ -18,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
19
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
20
|
Classifier: Topic :: Software Development :: Build Tools
|
|
21
|
-
Requires-Dist: logfire
|
|
21
|
+
Requires-Dist: logfire ; extra == 'logfire'
|
|
22
22
|
Requires-Dist: pydantic>=2 ; extra == 'pydantic'
|
|
23
23
|
Requires-Dist: pydantic-ai ; python_full_version >= '3.10' and extra == 'pydantic-ai'
|
|
24
24
|
Maintainer: 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.
|
|
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
|
|
370
|
-
to compute
|
|
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
|
|
|
@@ -410,8 +423,9 @@ Supported target triples:
|
|
|
410
423
|
- macOS: `x86_64-apple-darwin`, `aarch64-apple-darwin`
|
|
411
424
|
- Windows: `x86_64-pc-windows-msvc`, `aarch64-pc-windows-msvc`
|
|
412
425
|
|
|
413
|
-
If you are working from source and the vendor directory is missing, run
|
|
414
|
-
|
|
426
|
+
If you are working from source and the vendor directory is missing, run
|
|
427
|
+
`python scripts/setup_binary.py` to fetch and assemble the platform `@openai/codex`
|
|
428
|
+
artifacts into `src/codex_sdk/vendor/`.
|
|
415
429
|
|
|
416
430
|
<a id="auth"></a>
|
|
417
431
|
## 
|
|
@@ -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.
|
|
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
|
|
334
|
-
to compute
|
|
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
|
|
|
@@ -374,8 +387,9 @@ Supported target triples:
|
|
|
374
387
|
- macOS: `x86_64-apple-darwin`, `aarch64-apple-darwin`
|
|
375
388
|
- Windows: `x86_64-pc-windows-msvc`, `aarch64-pc-windows-msvc`
|
|
376
389
|
|
|
377
|
-
If you are working from source and the vendor directory is missing, run
|
|
378
|
-
|
|
390
|
+
If you are working from source and the vendor directory is missing, run
|
|
391
|
+
`python scripts/setup_binary.py` to fetch and assemble the platform `@openai/codex`
|
|
392
|
+
artifacts into `src/codex_sdk/vendor/`.
|
|
379
393
|
|
|
380
394
|
<a id="auth"></a>
|
|
381
395
|
## 
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["uv_build>=0.9.21,<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.
|
|
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"}
|
|
@@ -40,10 +40,7 @@ pydantic-ai = [
|
|
|
40
40
|
"pydantic-ai; python_version >= '3.10'",
|
|
41
41
|
]
|
|
42
42
|
logfire = [
|
|
43
|
-
|
|
44
|
-
# `logfire-api` distribution. Avoid the unrelated legacy `logfire` package
|
|
45
|
-
# on PyPI which can shadow it and break imports.
|
|
46
|
-
"logfire-api>=4",
|
|
43
|
+
"logfire",
|
|
47
44
|
]
|
|
48
45
|
|
|
49
46
|
[dependency-groups]
|
|
@@ -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 (
|
|
@@ -41,11 +43,6 @@ from .exceptions import (
|
|
|
41
43
|
from .hooks import ThreadHooks
|
|
42
44
|
from .items import (
|
|
43
45
|
AgentMessageItem,
|
|
44
|
-
CollabAgentState,
|
|
45
|
-
CollabAgentStatus,
|
|
46
|
-
CollabTool,
|
|
47
|
-
CollabToolCallItem,
|
|
48
|
-
CollabToolCallStatus,
|
|
49
46
|
CommandExecutionItem,
|
|
50
47
|
CommandExecutionStatus,
|
|
51
48
|
ErrorItem,
|
|
@@ -82,7 +79,7 @@ from .thread import (
|
|
|
82
79
|
Turn,
|
|
83
80
|
)
|
|
84
81
|
|
|
85
|
-
__version__ = "0.
|
|
82
|
+
__version__ = "0.104.0"
|
|
86
83
|
|
|
87
84
|
__all__ = [
|
|
88
85
|
"AbortController",
|
|
@@ -97,6 +94,8 @@ __all__ = [
|
|
|
97
94
|
"ApprovalDecisions",
|
|
98
95
|
"AppServerInput",
|
|
99
96
|
"AppServerUserInput",
|
|
97
|
+
"SkillsRemoteReadRequest",
|
|
98
|
+
"SkillsRemoteWriteRequest",
|
|
100
99
|
"Thread",
|
|
101
100
|
"ThreadHooks",
|
|
102
101
|
"Input",
|
|
@@ -122,7 +121,6 @@ __all__ = [
|
|
|
122
121
|
"CommandExecutionItem",
|
|
123
122
|
"FileChangeItem",
|
|
124
123
|
"McpToolCallItem",
|
|
125
|
-
"CollabToolCallItem",
|
|
126
124
|
"McpToolCallItemResult",
|
|
127
125
|
"McpToolCallItemError",
|
|
128
126
|
"WebSearchItem",
|
|
@@ -132,10 +130,6 @@ __all__ = [
|
|
|
132
130
|
"PatchChangeKind",
|
|
133
131
|
"PatchApplyStatus",
|
|
134
132
|
"McpToolCallStatus",
|
|
135
|
-
"CollabToolCallStatus",
|
|
136
|
-
"CollabTool",
|
|
137
|
-
"CollabAgentStatus",
|
|
138
|
-
"CollabAgentState",
|
|
139
133
|
"TodoItem",
|
|
140
134
|
"CodexOptions",
|
|
141
135
|
"ThreadOptions",
|
|
@@ -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(
|
|
@@ -636,14 +640,41 @@ class AppServerClient:
|
|
|
636
640
|
"""
|
|
637
641
|
return await self._request_dict("thread/unarchive", {"threadId": thread_id})
|
|
638
642
|
|
|
639
|
-
async def thread_compact_start(
|
|
643
|
+
async def thread_compact_start(
|
|
644
|
+
self, thread_id: str, *, instructions: Optional[str] = None
|
|
645
|
+
) -> Dict[str, Any]:
|
|
640
646
|
"""
|
|
641
647
|
Starts a compaction operation for the specified thread on the app-server.
|
|
642
648
|
|
|
649
|
+
Args:
|
|
650
|
+
thread_id: Identifier of the thread to compact.
|
|
651
|
+
instructions: Optional server hint for compaction behavior.
|
|
652
|
+
|
|
643
653
|
Returns:
|
|
644
654
|
dict: The app-server's result payload for the compaction start request.
|
|
645
655
|
"""
|
|
646
|
-
|
|
656
|
+
payload: Dict[str, Any] = {"thread_id": thread_id}
|
|
657
|
+
if instructions is not None:
|
|
658
|
+
payload["instructions"] = instructions
|
|
659
|
+
return await self._request_dict("thread/compact/start", _coerce_keys(payload))
|
|
660
|
+
|
|
661
|
+
async def thread_background_terminals_clean(
|
|
662
|
+
self, thread_id: str, *, terminal_ids: Sequence[str]
|
|
663
|
+
) -> Dict[str, Any]:
|
|
664
|
+
"""
|
|
665
|
+
Clean up background terminal sessions for a thread.
|
|
666
|
+
|
|
667
|
+
Args:
|
|
668
|
+
thread_id: Identifier of the thread.
|
|
669
|
+
terminal_ids: Terminal ids to clean.
|
|
670
|
+
|
|
671
|
+
Returns:
|
|
672
|
+
App-server response payload.
|
|
673
|
+
"""
|
|
674
|
+
payload = {"thread_id": thread_id, "terminal_ids": list(terminal_ids)}
|
|
675
|
+
return await self._request_dict(
|
|
676
|
+
"thread/backgroundTerminals/clean", _coerce_keys(payload)
|
|
677
|
+
)
|
|
647
678
|
|
|
648
679
|
async def thread_rollback(
|
|
649
680
|
self, thread_id: str, *, num_turns: int
|
|
@@ -741,43 +772,110 @@ class AppServerClient:
|
|
|
741
772
|
payload["cwds"] = [str(path) for path in cwds]
|
|
742
773
|
return await self._request_dict("skills/list", _coerce_keys(payload))
|
|
743
774
|
|
|
744
|
-
async def skills_remote_read(
|
|
775
|
+
async def skills_remote_read(
|
|
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,
|
|
783
|
+
) -> Dict[str, Any]:
|
|
745
784
|
"""
|
|
746
785
|
Read remote skills metadata from the app server.
|
|
747
786
|
|
|
787
|
+
Args:
|
|
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.
|
|
793
|
+
|
|
748
794
|
Returns:
|
|
749
795
|
result (Dict[str, Any]): The app-server response payload for the `skills/remote/read` request.
|
|
750
796
|
"""
|
|
751
|
-
|
|
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))
|
|
752
817
|
|
|
753
818
|
async def skills_remote_write(
|
|
754
|
-
self,
|
|
819
|
+
self,
|
|
820
|
+
*,
|
|
821
|
+
hazelnut_id: Optional[str] = None,
|
|
822
|
+
is_preload: Optional[bool] = None,
|
|
823
|
+
params: Optional["SkillsRemoteWriteRequest"] = None,
|
|
755
824
|
) -> Dict[str, Any]:
|
|
756
825
|
"""
|
|
757
|
-
Start a remote skill write operation
|
|
826
|
+
Start a remote skill write operation.
|
|
758
827
|
|
|
759
828
|
Args:
|
|
760
|
-
hazelnut_id:
|
|
761
|
-
is_preload:
|
|
829
|
+
hazelnut_id: Optional Hazelnut identifier.
|
|
830
|
+
is_preload: Optional preload flag.
|
|
831
|
+
params: Optional raw request payload.
|
|
762
832
|
|
|
763
833
|
Returns:
|
|
764
834
|
Result returned by the app-server for the "skills/remote/write" request.
|
|
765
835
|
"""
|
|
766
|
-
payload
|
|
836
|
+
payload: Dict[str, Any] = {}
|
|
837
|
+
if params is not None:
|
|
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))
|
|
847
|
+
if hazelnut_id is not None:
|
|
848
|
+
payload["hazelnut_id"] = hazelnut_id
|
|
849
|
+
if is_preload is not None:
|
|
850
|
+
payload["is_preload"] = is_preload
|
|
767
851
|
return await self._request_dict("skills/remote/write", _coerce_keys(payload))
|
|
768
852
|
|
|
769
|
-
async def skills_config_write(
|
|
853
|
+
async def skills_config_write(
|
|
854
|
+
self,
|
|
855
|
+
*,
|
|
856
|
+
path: Optional[str] = None,
|
|
857
|
+
enabled: Optional[bool] = None,
|
|
858
|
+
params: Optional["SkillsConfigWriteRequest"] = None,
|
|
859
|
+
) -> Dict[str, Any]:
|
|
770
860
|
"""
|
|
771
|
-
Set
|
|
861
|
+
Set skill configuration state.
|
|
772
862
|
|
|
773
863
|
Args:
|
|
774
|
-
path:
|
|
775
|
-
enabled:
|
|
864
|
+
path: Optional configuration path identifying the skill.
|
|
865
|
+
enabled: Optional enabled state for the skill.
|
|
866
|
+
params: Optional typed request payload for evolving protocol fields.
|
|
776
867
|
|
|
777
868
|
Returns:
|
|
778
869
|
The app-server response as a dictionary.
|
|
779
870
|
"""
|
|
780
|
-
|
|
871
|
+
# TODO(app-server-schema): tighten request shape after protocol stabilizes.
|
|
872
|
+
payload: Dict[str, Any] = {}
|
|
873
|
+
if params is not None:
|
|
874
|
+
payload.update(_coerce_keys(dict(params)))
|
|
875
|
+
if path is not None:
|
|
876
|
+
payload["path"] = path
|
|
877
|
+
if enabled is not None:
|
|
878
|
+
payload["enabled"] = enabled
|
|
781
879
|
return await self._request_dict("skills/config/write", payload)
|
|
782
880
|
|
|
783
881
|
async def turn_start(
|
|
@@ -848,8 +946,29 @@ class AppServerClient:
|
|
|
848
946
|
"turn/interrupt", {"threadId": thread_id, "turnId": turn_id}
|
|
849
947
|
)
|
|
850
948
|
|
|
949
|
+
async def turn_steer(
|
|
950
|
+
self, thread_id: str, turn_id: str, *, prompt: str
|
|
951
|
+
) -> Dict[str, Any]:
|
|
952
|
+
"""
|
|
953
|
+
Send steering guidance to an in-progress turn.
|
|
954
|
+
|
|
955
|
+
Args:
|
|
956
|
+
thread_id: Identifier of the thread.
|
|
957
|
+
turn_id: Identifier of the turn.
|
|
958
|
+
prompt: Steering prompt text.
|
|
959
|
+
|
|
960
|
+
Returns:
|
|
961
|
+
App-server response payload.
|
|
962
|
+
"""
|
|
963
|
+
payload = {"thread_id": thread_id, "turn_id": turn_id, "prompt": prompt}
|
|
964
|
+
return await self._request_dict("turn/steer", _coerce_keys(payload))
|
|
965
|
+
|
|
851
966
|
async def model_list(
|
|
852
|
-
self,
|
|
967
|
+
self,
|
|
968
|
+
*,
|
|
969
|
+
cursor: Optional[str] = None,
|
|
970
|
+
limit: Optional[int] = None,
|
|
971
|
+
include_hidden: Optional[bool] = None,
|
|
853
972
|
) -> Dict[str, Any]:
|
|
854
973
|
"""List models available to the app-server."""
|
|
855
974
|
params: Dict[str, Any] = {}
|
|
@@ -857,7 +976,9 @@ class AppServerClient:
|
|
|
857
976
|
params["cursor"] = cursor
|
|
858
977
|
if limit is not None:
|
|
859
978
|
params["limit"] = limit
|
|
860
|
-
|
|
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)
|
|
861
982
|
|
|
862
983
|
async def app_list(
|
|
863
984
|
self, *, cursor: Optional[str] = None, limit: Optional[int] = None
|
|
@@ -874,6 +995,26 @@ class AppServerClient:
|
|
|
874
995
|
"""List supported collaboration modes from the app-server."""
|
|
875
996
|
return await self._request_dict("collaborationMode/list", {})
|
|
876
997
|
|
|
998
|
+
async def experimental_feature_list(
|
|
999
|
+
self, *, cursor: Optional[str] = None, limit: Optional[int] = None
|
|
1000
|
+
) -> Dict[str, Any]:
|
|
1001
|
+
"""
|
|
1002
|
+
List experimental features available from the app-server.
|
|
1003
|
+
|
|
1004
|
+
Args:
|
|
1005
|
+
cursor: Optional pagination cursor.
|
|
1006
|
+
limit: Optional page size.
|
|
1007
|
+
|
|
1008
|
+
Returns:
|
|
1009
|
+
App-server response payload.
|
|
1010
|
+
"""
|
|
1011
|
+
params: Dict[str, Any] = {}
|
|
1012
|
+
if cursor is not None:
|
|
1013
|
+
params["cursor"] = cursor
|
|
1014
|
+
if limit is not None:
|
|
1015
|
+
params["limit"] = limit
|
|
1016
|
+
return await self._request_dict("experimentalFeature/list", params or None)
|
|
1017
|
+
|
|
877
1018
|
async def command_exec(
|
|
878
1019
|
self,
|
|
879
1020
|
*,
|
|
@@ -938,6 +1079,103 @@ class AppServerClient:
|
|
|
938
1079
|
"account/read", {"refreshToken": refresh_token} if refresh_token else None
|
|
939
1080
|
)
|
|
940
1081
|
|
|
1082
|
+
async def account_chatgpt_auth_tokens_refresh(
|
|
1083
|
+
self, *, params: Mapping[str, Any]
|
|
1084
|
+
) -> Dict[str, Any]:
|
|
1085
|
+
"""
|
|
1086
|
+
Refresh ChatGPT auth tokens via the app-server.
|
|
1087
|
+
|
|
1088
|
+
Args:
|
|
1089
|
+
params: Refresh payload (snake_case or camelCase keys are accepted).
|
|
1090
|
+
|
|
1091
|
+
Returns:
|
|
1092
|
+
App-server response payload.
|
|
1093
|
+
"""
|
|
1094
|
+
return await self._request_dict(
|
|
1095
|
+
"account/chatgptAuthTokens/refresh", _coerce_keys(dict(params))
|
|
1096
|
+
)
|
|
1097
|
+
|
|
1098
|
+
async def item_tool_call(self, *, params: "ItemToolCallRequest") -> Dict[str, Any]:
|
|
1099
|
+
"""
|
|
1100
|
+
Send an item tool-call payload.
|
|
1101
|
+
|
|
1102
|
+
Args:
|
|
1103
|
+
params: Typed request payload for `item/tool/call`.
|
|
1104
|
+
|
|
1105
|
+
Returns:
|
|
1106
|
+
App-server response payload.
|
|
1107
|
+
"""
|
|
1108
|
+
# TODO(app-server-schema): tighten request shape after protocol stabilizes.
|
|
1109
|
+
return await self._request_dict("item/tool/call", _coerce_keys(dict(params)))
|
|
1110
|
+
|
|
1111
|
+
async def item_tool_request_user_input(
|
|
1112
|
+
self, *, params: Mapping[str, Any]
|
|
1113
|
+
) -> Dict[str, Any]:
|
|
1114
|
+
"""
|
|
1115
|
+
Send an item request-user-input payload.
|
|
1116
|
+
|
|
1117
|
+
Args:
|
|
1118
|
+
params: Request payload for `item/tool/requestUserInput`.
|
|
1119
|
+
|
|
1120
|
+
Returns:
|
|
1121
|
+
App-server response payload.
|
|
1122
|
+
"""
|
|
1123
|
+
return await self._request_dict(
|
|
1124
|
+
"item/tool/requestUserInput", _coerce_keys(dict(params))
|
|
1125
|
+
)
|
|
1126
|
+
|
|
1127
|
+
async def item_command_execution_request_approval(
|
|
1128
|
+
self, *, params: Mapping[str, Any]
|
|
1129
|
+
) -> Dict[str, Any]:
|
|
1130
|
+
"""
|
|
1131
|
+
Send an item command-execution approval payload.
|
|
1132
|
+
|
|
1133
|
+
Args:
|
|
1134
|
+
params: Request payload for `item/commandExecution/requestApproval`.
|
|
1135
|
+
|
|
1136
|
+
Returns:
|
|
1137
|
+
App-server response payload.
|
|
1138
|
+
"""
|
|
1139
|
+
return await self._request_dict(
|
|
1140
|
+
"item/commandExecution/requestApproval", _coerce_keys(dict(params))
|
|
1141
|
+
)
|
|
1142
|
+
|
|
1143
|
+
async def item_file_change_request_approval(
|
|
1144
|
+
self, *, params: Mapping[str, Any]
|
|
1145
|
+
) -> Dict[str, Any]:
|
|
1146
|
+
"""
|
|
1147
|
+
Send an item file-change approval payload.
|
|
1148
|
+
|
|
1149
|
+
Args:
|
|
1150
|
+
params: Request payload for `item/fileChange/requestApproval`.
|
|
1151
|
+
|
|
1152
|
+
Returns:
|
|
1153
|
+
App-server response payload.
|
|
1154
|
+
"""
|
|
1155
|
+
return await self._request_dict(
|
|
1156
|
+
"item/fileChange/requestApproval", _coerce_keys(dict(params))
|
|
1157
|
+
)
|
|
1158
|
+
|
|
1159
|
+
async def mock_experimental_method(
|
|
1160
|
+
self, *, params: Optional[Mapping[str, Any]] = None
|
|
1161
|
+
) -> Dict[str, Any]:
|
|
1162
|
+
"""
|
|
1163
|
+
Call a mock experimental app-server endpoint.
|
|
1164
|
+
|
|
1165
|
+
Args:
|
|
1166
|
+
params: Optional request payload.
|
|
1167
|
+
|
|
1168
|
+
Returns:
|
|
1169
|
+
App-server response payload.
|
|
1170
|
+
"""
|
|
1171
|
+
if not self._options.experimental_api_enabled:
|
|
1172
|
+
raise CodexError(
|
|
1173
|
+
"`mock/experimentalMethod` requires "
|
|
1174
|
+
"AppServerOptions(experimental_api_enabled=True)."
|
|
1175
|
+
)
|
|
1176
|
+
payload = _coerce_keys(dict(params)) if params is not None else {}
|
|
1177
|
+
return await self._request_dict("mock/experimentalMethod", payload)
|
|
1178
|
+
|
|
941
1179
|
async def feedback_upload(
|
|
942
1180
|
self,
|
|
943
1181
|
*,
|
|
@@ -1109,6 +1347,46 @@ class AppServerSkillInput(TypedDict):
|
|
|
1109
1347
|
path: str
|
|
1110
1348
|
|
|
1111
1349
|
|
|
1350
|
+
class SkillsConfigWriteRequest(TypedDict, total=False):
|
|
1351
|
+
"""Typed payload for `skills/config/write` requests."""
|
|
1352
|
+
|
|
1353
|
+
path: str
|
|
1354
|
+
enabled: bool
|
|
1355
|
+
mode: str
|
|
1356
|
+
|
|
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
|
+
|
|
1378
|
+
class ItemToolCallRequest(TypedDict, total=False):
|
|
1379
|
+
"""Typed payload for `item/tool/call` requests."""
|
|
1380
|
+
|
|
1381
|
+
name: str
|
|
1382
|
+
tool_name: str
|
|
1383
|
+
toolName: str
|
|
1384
|
+
tool_call_id: str
|
|
1385
|
+
toolCallId: str
|
|
1386
|
+
arguments: Mapping[str, Any]
|
|
1387
|
+
args: Mapping[str, Any]
|
|
1388
|
+
|
|
1389
|
+
|
|
1112
1390
|
AppServerUserInput = Union[
|
|
1113
1391
|
AppServerTextInput,
|
|
1114
1392
|
AppServerImageInput,
|
|
@@ -1180,6 +1458,21 @@ def _coerce_keys(params: Mapping[str, Any]) -> Dict[str, Any]:
|
|
|
1180
1458
|
return coerced
|
|
1181
1459
|
|
|
1182
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
|
+
|
|
1183
1476
|
def _snake_to_camel(value: str) -> str:
|
|
1184
1477
|
"""Convert snake_case strings to lowerCamelCase."""
|
|
1185
1478
|
parts = value.split("_")
|