codex-python 1.114.0__tar.gz → 1.114.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.
- {codex_python-1.114.0 → codex_python-1.114.2}/PKG-INFO +49 -2
- {codex_python-1.114.0 → codex_python-1.114.2}/README.md +48 -1
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/__init__.py +9 -1
- codex_python-1.114.2/codex/_config_types.py +108 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/_runtime.py +8 -3
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/__init__.py +4 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/_async_client.py +15 -4
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/_session.py +6 -3
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/_sync_client.py +6 -2
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/models.py +3 -26
- codex_python-1.114.2/codex/app_server/options.py +503 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/transports.py +19 -2
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/codex.py +39 -7
- codex_python-1.114.2/codex/dynamic_tools.py +325 -0
- codex_python-1.114.2/codex/options.py +266 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/thread.py +11 -4
- {codex_python-1.114.0 → codex_python-1.114.2}/crates/codex_native/Cargo.lock +1 -1
- {codex_python-1.114.0 → codex_python-1.114.2}/crates/codex_native/Cargo.toml +1 -1
- codex_python-1.114.0/codex/_config_types.py +0 -6
- codex_python-1.114.0/codex/app_server/options.py +0 -246
- codex_python-1.114.0/codex/options.py +0 -127
- {codex_python-1.114.0 → codex_python-1.114.2}/LICENSE +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/_binary.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/_file_utils.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/_turn_options.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/_async_services.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/_async_threads.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/_payloads.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/_protocol_helpers.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/_sync_services.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/_sync_support.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/_sync_threads.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/_types.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/app_server/errors.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/errors.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/output_schema.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/output_schema_file.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/protocol/__init__.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/protocol/types.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/py.typed +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/codex/vendor/.gitkeep +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/crates/codex_native/codex/__init__.py +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/crates/codex_native/src/lib.rs +0 -0
- {codex_python-1.114.0 → codex_python-1.114.2}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codex-python
|
|
3
|
-
Version: 1.114.
|
|
3
|
+
Version: 1.114.2
|
|
4
4
|
Classifier: Programming Language :: Python :: 3
|
|
5
5
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -66,13 +66,29 @@ Use `AppServerClient` when you want a deeper integration:
|
|
|
66
66
|
## Quickstart: `Codex`
|
|
67
67
|
|
|
68
68
|
```python
|
|
69
|
-
from codex import Codex
|
|
69
|
+
from codex import Codex, ThreadStartOptions
|
|
70
70
|
|
|
71
71
|
client = Codex()
|
|
72
|
+
|
|
73
|
+
# Simplest one-shot call.
|
|
72
74
|
summary = client.run_text("Diagnose the failing tests and propose a fix")
|
|
73
75
|
print(summary)
|
|
76
|
+
|
|
77
|
+
# One-shot call with thread-scoped defaults for that run's fresh internal thread.
|
|
78
|
+
summary = client.run_text(
|
|
79
|
+
"Diagnose the failing tests in this repo",
|
|
80
|
+
thread_options=ThreadStartOptions(
|
|
81
|
+
cwd="/repo",
|
|
82
|
+
model="gpt-5",
|
|
83
|
+
),
|
|
84
|
+
)
|
|
85
|
+
print(summary)
|
|
74
86
|
```
|
|
75
87
|
|
|
88
|
+
Use `thread_options=` on `run()`, `run_text()`, `run_json()`, and `run_model()` when you want to
|
|
89
|
+
set defaults on the fresh internal thread created for that one-shot call. Use
|
|
90
|
+
`start_thread()` / `resume_thread()` when later runs should share context.
|
|
91
|
+
|
|
76
92
|
More `Codex` examples: [docs/exec_api.md](docs/exec_api.md)
|
|
77
93
|
|
|
78
94
|
## Quickstart: `AppServerClient`
|
|
@@ -97,6 +113,35 @@ with AppServerClient.connect_stdio(initialize_options=initialize_options) as cli
|
|
|
97
113
|
More app-server examples: [docs/app_server.md](docs/app_server.md)
|
|
98
114
|
For websocket transport, install the optional extra: `pip install "codex-python[websocket]"`.
|
|
99
115
|
|
|
116
|
+
## Dynamic tools
|
|
117
|
+
|
|
118
|
+
Decorator-driven dynamic tools are available on both SDK surfaces.
|
|
119
|
+
|
|
120
|
+
### `Codex`
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from codex import Codex, dynamic_tool
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@dynamic_tool
|
|
127
|
+
def lookup_ticket(id: str) -> str:
|
|
128
|
+
"""Look up a support ticket by id."""
|
|
129
|
+
return f"Ticket {id}: Login requests time out in eu-west-1."
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
client = Codex()
|
|
133
|
+
summary = client.run_text(
|
|
134
|
+
"Use the lookup_ticket dynamic tool for ticket 123 and summarize the result.",
|
|
135
|
+
tools=[lookup_ticket],
|
|
136
|
+
)
|
|
137
|
+
print(summary)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### `AppServerClient`
|
|
141
|
+
|
|
142
|
+
For a complete app-server example using the same decorator-driven flow, see
|
|
143
|
+
[examples/app_server_dynamic_tool.py](examples/app_server_dynamic_tool.py).
|
|
144
|
+
|
|
100
145
|
## Structured output
|
|
101
146
|
|
|
102
147
|
### `Codex`
|
|
@@ -186,10 +231,12 @@ Advanced app-server usage, including typed stable RPC domains such as `client.mo
|
|
|
186
231
|
## Examples
|
|
187
232
|
|
|
188
233
|
- [examples/basic_conversation.py](examples/basic_conversation.py): minimal `Codex` flow
|
|
234
|
+
- [examples/basic_dynamic_tool.py](examples/basic_dynamic_tool.py): high-level `Codex` dynamic tool flow
|
|
189
235
|
- [examples/app_server_conversation.py](examples/app_server_conversation.py): minimal app-server flow
|
|
190
236
|
- [examples/app_server_websocket_conversation.py](examples/app_server_websocket_conversation.py): minimal websocket app-server flow
|
|
191
237
|
- [examples/app_server_stream_events.py](examples/app_server_stream_events.py): protocol-native app-server streaming
|
|
192
238
|
- [examples/app_server_tool_handler.py](examples/app_server_tool_handler.py): typed app-server request handling
|
|
239
|
+
- [examples/app_server_dynamic_tool.py](examples/app_server_dynamic_tool.py): decorator-driven dynamic tool registration
|
|
193
240
|
|
|
194
241
|
## Bundled binary behavior
|
|
195
242
|
|
|
@@ -44,13 +44,29 @@ Use `AppServerClient` when you want a deeper integration:
|
|
|
44
44
|
## Quickstart: `Codex`
|
|
45
45
|
|
|
46
46
|
```python
|
|
47
|
-
from codex import Codex
|
|
47
|
+
from codex import Codex, ThreadStartOptions
|
|
48
48
|
|
|
49
49
|
client = Codex()
|
|
50
|
+
|
|
51
|
+
# Simplest one-shot call.
|
|
50
52
|
summary = client.run_text("Diagnose the failing tests and propose a fix")
|
|
51
53
|
print(summary)
|
|
54
|
+
|
|
55
|
+
# One-shot call with thread-scoped defaults for that run's fresh internal thread.
|
|
56
|
+
summary = client.run_text(
|
|
57
|
+
"Diagnose the failing tests in this repo",
|
|
58
|
+
thread_options=ThreadStartOptions(
|
|
59
|
+
cwd="/repo",
|
|
60
|
+
model="gpt-5",
|
|
61
|
+
),
|
|
62
|
+
)
|
|
63
|
+
print(summary)
|
|
52
64
|
```
|
|
53
65
|
|
|
66
|
+
Use `thread_options=` on `run()`, `run_text()`, `run_json()`, and `run_model()` when you want to
|
|
67
|
+
set defaults on the fresh internal thread created for that one-shot call. Use
|
|
68
|
+
`start_thread()` / `resume_thread()` when later runs should share context.
|
|
69
|
+
|
|
54
70
|
More `Codex` examples: [docs/exec_api.md](docs/exec_api.md)
|
|
55
71
|
|
|
56
72
|
## Quickstart: `AppServerClient`
|
|
@@ -75,6 +91,35 @@ with AppServerClient.connect_stdio(initialize_options=initialize_options) as cli
|
|
|
75
91
|
More app-server examples: [docs/app_server.md](docs/app_server.md)
|
|
76
92
|
For websocket transport, install the optional extra: `pip install "codex-python[websocket]"`.
|
|
77
93
|
|
|
94
|
+
## Dynamic tools
|
|
95
|
+
|
|
96
|
+
Decorator-driven dynamic tools are available on both SDK surfaces.
|
|
97
|
+
|
|
98
|
+
### `Codex`
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from codex import Codex, dynamic_tool
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@dynamic_tool
|
|
105
|
+
def lookup_ticket(id: str) -> str:
|
|
106
|
+
"""Look up a support ticket by id."""
|
|
107
|
+
return f"Ticket {id}: Login requests time out in eu-west-1."
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
client = Codex()
|
|
111
|
+
summary = client.run_text(
|
|
112
|
+
"Use the lookup_ticket dynamic tool for ticket 123 and summarize the result.",
|
|
113
|
+
tools=[lookup_ticket],
|
|
114
|
+
)
|
|
115
|
+
print(summary)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### `AppServerClient`
|
|
119
|
+
|
|
120
|
+
For a complete app-server example using the same decorator-driven flow, see
|
|
121
|
+
[examples/app_server_dynamic_tool.py](examples/app_server_dynamic_tool.py).
|
|
122
|
+
|
|
78
123
|
## Structured output
|
|
79
124
|
|
|
80
125
|
### `Codex`
|
|
@@ -164,10 +209,12 @@ Advanced app-server usage, including typed stable RPC domains such as `client.mo
|
|
|
164
209
|
## Examples
|
|
165
210
|
|
|
166
211
|
- [examples/basic_conversation.py](examples/basic_conversation.py): minimal `Codex` flow
|
|
212
|
+
- [examples/basic_dynamic_tool.py](examples/basic_dynamic_tool.py): high-level `Codex` dynamic tool flow
|
|
167
213
|
- [examples/app_server_conversation.py](examples/app_server_conversation.py): minimal app-server flow
|
|
168
214
|
- [examples/app_server_websocket_conversation.py](examples/app_server_websocket_conversation.py): minimal websocket app-server flow
|
|
169
215
|
- [examples/app_server_stream_events.py](examples/app_server_stream_events.py): protocol-native app-server streaming
|
|
170
216
|
- [examples/app_server_tool_handler.py](examples/app_server_tool_handler.py): typed app-server request handling
|
|
217
|
+
- [examples/app_server_dynamic_tool.py](examples/app_server_dynamic_tool.py): decorator-driven dynamic tool registration
|
|
171
218
|
|
|
172
219
|
## Bundled binary behavior
|
|
173
220
|
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from codex.codex import Codex
|
|
6
|
+
from codex.dynamic_tools import dynamic_tool
|
|
6
7
|
from codex.errors import CodexError, CodexExecError, CodexParseError, ThreadRunError
|
|
7
8
|
from codex.options import (
|
|
8
9
|
CancelSignal,
|
|
10
|
+
CodexConfig,
|
|
9
11
|
CodexConfigObject,
|
|
10
12
|
CodexConfigValue,
|
|
11
13
|
CodexOptions,
|
|
@@ -13,11 +15,16 @@ from codex.options import (
|
|
|
13
15
|
ThreadStartOptions,
|
|
14
16
|
TurnOptions,
|
|
15
17
|
)
|
|
18
|
+
from codex.thread import CodexTurnStream, Input, Thread
|
|
16
19
|
|
|
17
|
-
__version__ = "1.114.
|
|
20
|
+
__version__ = "1.114.2"
|
|
18
21
|
|
|
19
22
|
__all__ = [
|
|
20
23
|
"Codex",
|
|
24
|
+
"CodexTurnStream",
|
|
25
|
+
"Thread",
|
|
26
|
+
"Input",
|
|
27
|
+
"dynamic_tool",
|
|
21
28
|
"CodexError",
|
|
22
29
|
"CodexExecError",
|
|
23
30
|
"CodexParseError",
|
|
@@ -26,6 +33,7 @@ __all__ = [
|
|
|
26
33
|
"ThreadStartOptions",
|
|
27
34
|
"ThreadResumeOptions",
|
|
28
35
|
"TurnOptions",
|
|
36
|
+
"CodexConfig",
|
|
29
37
|
"CodexConfigValue",
|
|
30
38
|
"CodexConfigObject",
|
|
31
39
|
"CancelSignal",
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
6
|
+
|
|
7
|
+
from codex.protocol import types as protocol
|
|
8
|
+
|
|
9
|
+
type CodexConfigValue = (
|
|
10
|
+
str | int | float | bool | list["CodexConfigValue"] | dict[str, "CodexConfigValue"]
|
|
11
|
+
)
|
|
12
|
+
type CodexConfigObject = dict[str, CodexConfigValue]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CodexConfig(BaseModel):
|
|
16
|
+
"""Typed top-level Codex config shape with forward-compatible extra keys."""
|
|
17
|
+
|
|
18
|
+
model_config = ConfigDict(extra="allow")
|
|
19
|
+
__pydantic_extra__: dict[str, CodexConfigValue]
|
|
20
|
+
|
|
21
|
+
analytics: CodexConfigObject | None = Field(
|
|
22
|
+
default=None,
|
|
23
|
+
description="Open-ended analytics configuration subtree.",
|
|
24
|
+
)
|
|
25
|
+
approval_policy: protocol.AskForApproval | None = Field(
|
|
26
|
+
default=None,
|
|
27
|
+
description="Default approval policy for new turns and commands.",
|
|
28
|
+
)
|
|
29
|
+
compact_prompt: str | None = Field(
|
|
30
|
+
default=None,
|
|
31
|
+
description="Prompt text used when the app-server compacts thread history.",
|
|
32
|
+
)
|
|
33
|
+
developer_instructions: str | None = Field(
|
|
34
|
+
default=None,
|
|
35
|
+
description="Default developer instructions applied to new turns.",
|
|
36
|
+
)
|
|
37
|
+
forced_chatgpt_workspace_id: str | None = Field(
|
|
38
|
+
default=None,
|
|
39
|
+
description="Workspace identifier to force for ChatGPT-managed auth flows.",
|
|
40
|
+
)
|
|
41
|
+
forced_login_method: Literal["chatgpt", "api"] | None = Field(
|
|
42
|
+
default=None,
|
|
43
|
+
description="Force Codex auth to ChatGPT or API-key mode.",
|
|
44
|
+
)
|
|
45
|
+
instructions: str | None = Field(
|
|
46
|
+
default=None,
|
|
47
|
+
description="Default user-visible instructions prepended to new conversations.",
|
|
48
|
+
)
|
|
49
|
+
model: str | None = Field(
|
|
50
|
+
default=None,
|
|
51
|
+
description="Default model id used when threads or turns do not override it.",
|
|
52
|
+
)
|
|
53
|
+
model_auto_compact_token_limit: int | None = Field(
|
|
54
|
+
default=None,
|
|
55
|
+
description="Token threshold that triggers automatic thread compaction.",
|
|
56
|
+
)
|
|
57
|
+
model_context_window: int | None = Field(
|
|
58
|
+
default=None,
|
|
59
|
+
description="Context window size override for the configured model.",
|
|
60
|
+
)
|
|
61
|
+
model_provider: str | None = Field(
|
|
62
|
+
default=None,
|
|
63
|
+
description="Default model provider name.",
|
|
64
|
+
)
|
|
65
|
+
model_reasoning_effort: protocol.ReasoningEffort | None = Field(
|
|
66
|
+
default=None,
|
|
67
|
+
description="Default reasoning effort for turns that do not override it.",
|
|
68
|
+
)
|
|
69
|
+
model_reasoning_summary: protocol.ReasoningSummary | None = Field(
|
|
70
|
+
default=None,
|
|
71
|
+
description="Default reasoning-summary behavior for supported models.",
|
|
72
|
+
)
|
|
73
|
+
model_verbosity: Literal["low", "medium", "high"] | None = Field(
|
|
74
|
+
default=None,
|
|
75
|
+
description="Default verbosity for supported models.",
|
|
76
|
+
)
|
|
77
|
+
profile: str | None = Field(
|
|
78
|
+
default=None,
|
|
79
|
+
description="Name of the active Codex profile.",
|
|
80
|
+
)
|
|
81
|
+
profiles: CodexConfigObject | None = Field(
|
|
82
|
+
default_factory=dict,
|
|
83
|
+
description="Open-ended profile definitions keyed by profile name.",
|
|
84
|
+
)
|
|
85
|
+
review_model: str | None = Field(
|
|
86
|
+
default=None,
|
|
87
|
+
description="Model override used for review flows.",
|
|
88
|
+
)
|
|
89
|
+
sandbox_mode: protocol.SandboxMode | None = Field(
|
|
90
|
+
default=None,
|
|
91
|
+
description="Default sandbox mode for new threads and turns.",
|
|
92
|
+
)
|
|
93
|
+
sandbox_workspace_write: CodexConfigObject | None = Field(
|
|
94
|
+
default=None,
|
|
95
|
+
description="Open-ended workspace-write sandbox configuration subtree.",
|
|
96
|
+
)
|
|
97
|
+
service_tier: protocol.ServiceTier | None = Field(
|
|
98
|
+
default=None,
|
|
99
|
+
description="Default service tier for requests that do not override it.",
|
|
100
|
+
)
|
|
101
|
+
tools: CodexConfigObject | None = Field(
|
|
102
|
+
default=None,
|
|
103
|
+
description="Open-ended tool configuration subtree.",
|
|
104
|
+
)
|
|
105
|
+
web_search: Literal["disabled", "cached", "live"] | None = Field(
|
|
106
|
+
default=None,
|
|
107
|
+
description="Default web-search mode.",
|
|
108
|
+
)
|
|
@@ -7,7 +7,7 @@ from collections.abc import Callable, Mapping
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
9
|
from codex._binary import BundledCodexNotFoundError
|
|
10
|
-
from codex._config_types import CodexConfigObject, CodexConfigValue
|
|
10
|
+
from codex._config_types import CodexConfig, CodexConfigObject, CodexConfigValue
|
|
11
11
|
|
|
12
12
|
INTERNAL_ORIGINATOR_ENV = "CODEX_INTERNAL_ORIGINATOR_OVERRIDE"
|
|
13
13
|
PYTHON_SDK_ORIGINATOR = "codex_sdk_py"
|
|
@@ -50,9 +50,14 @@ def resolve_codex_path(
|
|
|
50
50
|
return system_codex
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
def serialize_config_overrides(config_overrides: CodexConfigObject) -> list[str]:
|
|
53
|
+
def serialize_config_overrides(config_overrides: CodexConfig | CodexConfigObject) -> list[str]:
|
|
54
54
|
overrides: list[str] = []
|
|
55
|
-
|
|
55
|
+
root = (
|
|
56
|
+
config_overrides.model_dump(mode="python", exclude_none=True, exclude_unset=True)
|
|
57
|
+
if isinstance(config_overrides, CodexConfig)
|
|
58
|
+
else config_overrides
|
|
59
|
+
)
|
|
60
|
+
_flatten_config_overrides(root, "", overrides)
|
|
56
61
|
return overrides
|
|
57
62
|
|
|
58
63
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from codex._config_types import CodexConfig
|
|
3
4
|
from codex.app_server._async_client import AsyncAppServerClient, AsyncRpcClient
|
|
4
5
|
from codex.app_server._async_threads import AsyncAppServerThread, AsyncTurnStream
|
|
5
6
|
from codex.app_server._sync_client import AppServerClient, RpcClient
|
|
@@ -23,6 +24,7 @@ from codex.app_server.options import (
|
|
|
23
24
|
AppServerTurnOptions,
|
|
24
25
|
AppServerWebSocketOptions,
|
|
25
26
|
)
|
|
27
|
+
from codex.dynamic_tools import dynamic_tool
|
|
26
28
|
|
|
27
29
|
__all__ = [
|
|
28
30
|
"AsyncAppServerClient",
|
|
@@ -30,6 +32,7 @@ __all__ = [
|
|
|
30
32
|
"AsyncRpcClient",
|
|
31
33
|
"AsyncTurnStream",
|
|
32
34
|
"AppServerClient",
|
|
35
|
+
"dynamic_tool",
|
|
33
36
|
"AppServerThread",
|
|
34
37
|
"RpcClient",
|
|
35
38
|
"TurnStream",
|
|
@@ -40,6 +43,7 @@ __all__ = [
|
|
|
40
43
|
"AppServerRpcError",
|
|
41
44
|
"AppServerTurnError",
|
|
42
45
|
"AppServerClientInfo",
|
|
46
|
+
"CodexConfig",
|
|
43
47
|
"AppServerInitializeOptions",
|
|
44
48
|
"AppServerProcessOptions",
|
|
45
49
|
"AppServerWebSocketOptions",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from collections.abc import Collection, Mapping
|
|
5
|
+
from collections.abc import Callable, Collection, Mapping
|
|
6
6
|
from typing import TypeVar, cast
|
|
7
7
|
|
|
8
8
|
from pydantic import BaseModel
|
|
@@ -43,6 +43,7 @@ from codex.app_server.transports import (
|
|
|
43
43
|
AsyncStdioTransport,
|
|
44
44
|
AsyncWebSocketTransport,
|
|
45
45
|
)
|
|
46
|
+
from codex.dynamic_tools import _DynamicToolRuntime, merge_dynamic_tool_specs, resolve_dynamic_tools
|
|
46
47
|
from codex.protocol import types as protocol
|
|
47
48
|
|
|
48
49
|
_ModelT = TypeVar("_ModelT", bound=BaseModel)
|
|
@@ -60,8 +61,9 @@ __all__ = [
|
|
|
60
61
|
class AsyncRpcClient:
|
|
61
62
|
"""Low-level async JSON-RPC access to app-server methods."""
|
|
62
63
|
|
|
63
|
-
def __init__(self, session: _AsyncSession) -> None:
|
|
64
|
+
def __init__(self, session: _AsyncSession, dynamic_tools: _DynamicToolRuntime) -> None:
|
|
64
65
|
self._session = session
|
|
66
|
+
self._dynamic_tools = dynamic_tools
|
|
65
67
|
|
|
66
68
|
async def request(
|
|
67
69
|
self,
|
|
@@ -92,6 +94,7 @@ class AsyncRpcClient:
|
|
|
92
94
|
*,
|
|
93
95
|
request_model: type[_RequestT] | None = None,
|
|
94
96
|
) -> None:
|
|
97
|
+
self._dynamic_tools.check_manual_handler_registration(method)
|
|
95
98
|
self._session.on_request(method, handler, request_model=request_model)
|
|
96
99
|
|
|
97
100
|
|
|
@@ -114,7 +117,8 @@ class AsyncAppServerClient:
|
|
|
114
117
|
initialize_options: AppServerInitializeOptions | None = None,
|
|
115
118
|
) -> None:
|
|
116
119
|
self._session = _AsyncSession(transport, initialize_options)
|
|
117
|
-
self.
|
|
120
|
+
self._dynamic_tools = _DynamicToolRuntime(self._session.on_request)
|
|
121
|
+
self.rpc = AsyncRpcClient(self._session, self._dynamic_tools)
|
|
118
122
|
self.events = AsyncEventsClient(self._session)
|
|
119
123
|
self.models = AsyncModelsClient(self.rpc)
|
|
120
124
|
self.apps = AsyncAppsClient(self.rpc)
|
|
@@ -167,12 +171,19 @@ class AsyncAppServerClient:
|
|
|
167
171
|
async def start_thread(
|
|
168
172
|
self,
|
|
169
173
|
options: AppServerThreadStartOptions | None = None,
|
|
174
|
+
*,
|
|
175
|
+
tools: Collection[Callable[..., object]] | None = None,
|
|
170
176
|
) -> AsyncAppServerThread:
|
|
177
|
+
start_options = options or AppServerThreadStartOptions()
|
|
178
|
+
resolved_tools = resolve_dynamic_tools(list(tools or ()))
|
|
179
|
+
dynamic_tools = merge_dynamic_tool_specs(start_options.dynamic_tools, resolved_tools)
|
|
180
|
+
self._dynamic_tools.prepare_activation(resolved_tools)
|
|
171
181
|
result = await self.rpc.request_typed(
|
|
172
182
|
"thread/start",
|
|
173
|
-
(
|
|
183
|
+
start_options.model_copy(update={"dynamic_tools": dynamic_tools}).to_params(),
|
|
174
184
|
ThreadResult,
|
|
175
185
|
)
|
|
186
|
+
self._dynamic_tools.activate(result.thread.id, resolved_tools)
|
|
176
187
|
return AsyncAppServerThread(cast(_ThreadClient, self), result.thread)
|
|
177
188
|
|
|
178
189
|
async def resume_thread(
|
|
@@ -31,6 +31,7 @@ from codex.protocol import types as protocol
|
|
|
31
31
|
_ModelT = TypeVar("_ModelT", bound=BaseModel)
|
|
32
32
|
_RequestT = TypeVar("_RequestT", bound=BaseModel)
|
|
33
33
|
_NotificationPredicate = Callable[[Notification], bool]
|
|
34
|
+
_SubscriptionMessage = Notification | Exception | None
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
class _NotificationSink:
|
|
@@ -41,7 +42,7 @@ class _NotificationSink:
|
|
|
41
42
|
) -> None:
|
|
42
43
|
self.methods = methods
|
|
43
44
|
self.predicate = predicate
|
|
44
|
-
self.queue: asyncio.Queue[
|
|
45
|
+
self.queue: asyncio.Queue[_SubscriptionMessage] = asyncio.Queue()
|
|
45
46
|
|
|
46
47
|
def matches(self, method: str, notification: Notification) -> bool:
|
|
47
48
|
if self.methods is not None and method not in self.methods:
|
|
@@ -52,13 +53,15 @@ class _NotificationSink:
|
|
|
52
53
|
@dataclass(slots=True)
|
|
53
54
|
class _AsyncNotificationSubscription:
|
|
54
55
|
sink: _NotificationSink
|
|
55
|
-
queue: asyncio.Queue[
|
|
56
|
+
queue: asyncio.Queue[_SubscriptionMessage]
|
|
56
57
|
close_callback: Callable[[], None]
|
|
57
58
|
|
|
58
59
|
async def next(self) -> Notification:
|
|
59
60
|
message = await self.queue.get()
|
|
60
61
|
if message is None:
|
|
61
62
|
raise StopAsyncIteration
|
|
63
|
+
if isinstance(message, Exception):
|
|
64
|
+
raise message
|
|
62
65
|
return message
|
|
63
66
|
|
|
64
67
|
async def close(self) -> None:
|
|
@@ -253,7 +256,7 @@ class _AsyncSession:
|
|
|
253
256
|
self._reader_error = exc
|
|
254
257
|
self._fail_pending(exc)
|
|
255
258
|
for sink in list(self._notification_sinks):
|
|
256
|
-
await sink.queue.put(
|
|
259
|
+
await sink.queue.put(exc)
|
|
257
260
|
|
|
258
261
|
async def _await_future(self, future: asyncio.Future[object]) -> object:
|
|
259
262
|
while True:
|
|
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import concurrent.futures
|
|
7
7
|
import time
|
|
8
|
-
from collections.abc import Coroutine, Mapping
|
|
8
|
+
from collections.abc import Callable, Collection, Coroutine, Mapping
|
|
9
9
|
from contextlib import suppress
|
|
10
10
|
from threading import Thread
|
|
11
11
|
from typing import Any, TypeVar, cast
|
|
@@ -311,9 +311,13 @@ class AppServerClient(_SyncRunner):
|
|
|
311
311
|
def start_thread(
|
|
312
312
|
self,
|
|
313
313
|
options: AppServerThreadStartOptions | None = None,
|
|
314
|
+
*,
|
|
315
|
+
tools: Collection[Callable[..., object]] | None = None,
|
|
314
316
|
) -> AppServerThread:
|
|
315
317
|
return AppServerThread(
|
|
316
|
-
cast(
|
|
318
|
+
cast(
|
|
319
|
+
_AsyncThreadLike, self._run(self._async_client.start_thread(options, tools=tools))
|
|
320
|
+
),
|
|
317
321
|
self._run,
|
|
318
322
|
)
|
|
319
323
|
|
|
@@ -6,7 +6,7 @@ from pydantic import BaseModel, Field
|
|
|
6
6
|
from pydantic import ConfigDict as PydanticConfigDict
|
|
7
7
|
from pydantic.alias_generators import to_camel
|
|
8
8
|
|
|
9
|
-
from codex._config_types import CodexConfigObject, CodexConfigValue
|
|
9
|
+
from codex._config_types import CodexConfig, CodexConfigObject, CodexConfigValue
|
|
10
10
|
from codex.protocol import types as protocol
|
|
11
11
|
|
|
12
12
|
|
|
@@ -144,31 +144,8 @@ class AccountRateLimitsResult(AppServerResultModel):
|
|
|
144
144
|
rate_limits_by_limit_id: dict[str, protocol.RateLimitSnapshot] | None = None
|
|
145
145
|
|
|
146
146
|
|
|
147
|
-
class AppServerConfig(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
analytics: CodexConfigObject | None = None
|
|
151
|
-
approval_policy: protocol.AskForApproval | None = None
|
|
152
|
-
compact_prompt: str | None = None
|
|
153
|
-
developer_instructions: str | None = None
|
|
154
|
-
forced_chatgpt_workspace_id: str | None = None
|
|
155
|
-
forced_login_method: Literal["chatgpt", "api"] | None = None
|
|
156
|
-
instructions: str | None = None
|
|
157
|
-
model: str | None = None
|
|
158
|
-
model_auto_compact_token_limit: int | None = None
|
|
159
|
-
model_context_window: int | None = None
|
|
160
|
-
model_provider: str | None = None
|
|
161
|
-
model_reasoning_effort: protocol.ReasoningEffort | None = None
|
|
162
|
-
model_reasoning_summary: protocol.ReasoningSummary | None = None
|
|
163
|
-
model_verbosity: Literal["low", "medium", "high"] | None = None
|
|
164
|
-
profile: str | None = None
|
|
165
|
-
profiles: CodexConfigObject | None = Field(default_factory=dict)
|
|
166
|
-
review_model: str | None = None
|
|
167
|
-
sandbox_mode: protocol.SandboxMode | None = None
|
|
168
|
-
sandbox_workspace_write: CodexConfigObject | None = None
|
|
169
|
-
service_tier: protocol.ServiceTier | None = None
|
|
170
|
-
tools: CodexConfigObject | None = None
|
|
171
|
-
web_search: Literal["disabled", "cached", "live"] | None = None
|
|
147
|
+
class AppServerConfig(CodexConfig):
|
|
148
|
+
"""Typed config payload returned by app-server config APIs."""
|
|
172
149
|
|
|
173
150
|
|
|
174
151
|
class ConfigLayerMetadata(AppServerResultModel):
|