codex-a2a 0.3.0__py3-none-any.whl
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_a2a/__init__.py +34 -0
- codex_a2a/cli.py +38 -0
- codex_a2a/config.py +284 -0
- codex_a2a/contracts/__init__.py +0 -0
- codex_a2a/contracts/extensions.py +720 -0
- codex_a2a/contracts/runtime_output.py +264 -0
- codex_a2a/execution/__init__.py +0 -0
- codex_a2a/execution/cancellation.py +82 -0
- codex_a2a/execution/directory_policy.py +44 -0
- codex_a2a/execution/executor.py +451 -0
- codex_a2a/execution/output_mapping.py +217 -0
- codex_a2a/execution/request_metadata.py +60 -0
- codex_a2a/execution/response_emitter.py +108 -0
- codex_a2a/execution/session_runtime.py +314 -0
- codex_a2a/execution/stream_chunks.py +413 -0
- codex_a2a/execution/stream_interrupts.py +225 -0
- codex_a2a/execution/stream_processor.py +501 -0
- codex_a2a/execution/stream_state.py +232 -0
- codex_a2a/execution/streaming.py +153 -0
- codex_a2a/execution/tool_call_payloads.py +338 -0
- codex_a2a/jsonrpc/__init__.py +0 -0
- codex_a2a/jsonrpc/application.py +183 -0
- codex_a2a/jsonrpc/control_params.py +227 -0
- codex_a2a/jsonrpc/errors.py +95 -0
- codex_a2a/jsonrpc/interrupt_lifecycle.py +120 -0
- codex_a2a/jsonrpc/interrupt_params.py +165 -0
- codex_a2a/jsonrpc/interrupts.py +164 -0
- codex_a2a/jsonrpc/params.py +41 -0
- codex_a2a/jsonrpc/params_common.py +131 -0
- codex_a2a/jsonrpc/payload_mapping.py +97 -0
- codex_a2a/jsonrpc/query_params.py +168 -0
- codex_a2a/jsonrpc/session_control.py +167 -0
- codex_a2a/jsonrpc/session_query.py +119 -0
- codex_a2a/logging_context.py +63 -0
- codex_a2a/metrics.py +72 -0
- codex_a2a/parts/text.py +15 -0
- codex_a2a/profile/__init__.py +0 -0
- codex_a2a/profile/runtime.py +346 -0
- codex_a2a/server/__init__.py +0 -0
- codex_a2a/server/agent_card.py +228 -0
- codex_a2a/server/application.py +163 -0
- codex_a2a/server/call_context.py +39 -0
- codex_a2a/server/http_middlewares.py +299 -0
- codex_a2a/server/openapi.py +315 -0
- codex_a2a/server/request_handler.py +183 -0
- codex_a2a/upstream/__init__.py +11 -0
- codex_a2a/upstream/client.py +1075 -0
- codex_a2a/upstream/interrupts.py +168 -0
- codex_a2a/upstream/models.py +47 -0
- codex_a2a/upstream/notification_mapping.py +150 -0
- codex_a2a/upstream/request_mapping.py +57 -0
- codex_a2a-0.3.0.dist-info/METADATA +189 -0
- codex_a2a-0.3.0.dist-info/RECORD +57 -0
- codex_a2a-0.3.0.dist-info/WHEEL +5 -0
- codex_a2a-0.3.0.dist-info/entry_points.txt +2 -0
- codex_a2a-0.3.0.dist-info/licenses/LICENSE +176 -0
- codex_a2a-0.3.0.dist-info/top_level.txt +1 -0
codex_a2a/__init__.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Codex A2A runtime package."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
6
|
+
|
|
7
|
+
_PACKAGE_NAME = "codex-a2a"
|
|
8
|
+
_UNKNOWN_VERSION = "0.0.0+unknown"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _package_version() -> str | None:
|
|
12
|
+
try:
|
|
13
|
+
return version(_PACKAGE_NAME)
|
|
14
|
+
except PackageNotFoundError:
|
|
15
|
+
return None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _scm_version() -> str | None:
|
|
19
|
+
try:
|
|
20
|
+
from setuptools_scm import get_version
|
|
21
|
+
except ImportError:
|
|
22
|
+
return None
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
return get_version(root="../..", relative_to=__file__)
|
|
26
|
+
except LookupError:
|
|
27
|
+
return None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _resolve_version() -> str:
|
|
31
|
+
return _package_version() or _scm_version() or _UNKNOWN_VERSION
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
__version__ = _resolve_version()
|
codex_a2a/cli.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import sys
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
|
|
7
|
+
from . import __version__
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
11
|
+
parser = argparse.ArgumentParser(
|
|
12
|
+
prog="codex-a2a",
|
|
13
|
+
description="Codex A2A CLI.",
|
|
14
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
15
|
+
)
|
|
16
|
+
parser.add_argument(
|
|
17
|
+
"--version",
|
|
18
|
+
action="version",
|
|
19
|
+
version=f"%(prog)s {__version__}",
|
|
20
|
+
)
|
|
21
|
+
return parser
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _serve_main() -> None:
|
|
25
|
+
from .server.application import main as serve_main
|
|
26
|
+
|
|
27
|
+
serve_main()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
31
|
+
parser = build_parser()
|
|
32
|
+
parser.parse_args(list(sys.argv[1:] if argv is None else argv))
|
|
33
|
+
_serve_main()
|
|
34
|
+
return 0
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
if __name__ == "__main__":
|
|
38
|
+
raise SystemExit(main())
|
codex_a2a/config.py
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Annotated, Any, cast
|
|
4
|
+
|
|
5
|
+
from pydantic import Field, field_validator
|
|
6
|
+
from pydantic_settings import BaseSettings, NoDecode, SettingsConfigDict
|
|
7
|
+
|
|
8
|
+
from codex_a2a import __version__
|
|
9
|
+
|
|
10
|
+
_SANDBOX_MODES = {
|
|
11
|
+
"unknown",
|
|
12
|
+
"read-only",
|
|
13
|
+
"workspace-write",
|
|
14
|
+
"danger-full-access",
|
|
15
|
+
}
|
|
16
|
+
_FILESYSTEM_SCOPES = {
|
|
17
|
+
"unknown",
|
|
18
|
+
"none",
|
|
19
|
+
"workspace_root",
|
|
20
|
+
"workspace_root_or_descendant",
|
|
21
|
+
"configured_roots",
|
|
22
|
+
"full_filesystem",
|
|
23
|
+
}
|
|
24
|
+
_NETWORK_ACCESS_MODES = {
|
|
25
|
+
"unknown",
|
|
26
|
+
"disabled",
|
|
27
|
+
"enabled",
|
|
28
|
+
"restricted",
|
|
29
|
+
}
|
|
30
|
+
_APPROVAL_POLICIES = {
|
|
31
|
+
"unknown",
|
|
32
|
+
"never",
|
|
33
|
+
"on-request",
|
|
34
|
+
"on-failure",
|
|
35
|
+
"untrusted-only",
|
|
36
|
+
}
|
|
37
|
+
_APPROVAL_ESCALATION_BEHAVIORS = {
|
|
38
|
+
"unknown",
|
|
39
|
+
"unavailable",
|
|
40
|
+
"per_request",
|
|
41
|
+
"fallback_only",
|
|
42
|
+
"restricted",
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _parse_str_list(value: Any) -> Any:
|
|
47
|
+
if value is None:
|
|
48
|
+
return []
|
|
49
|
+
if isinstance(value, str):
|
|
50
|
+
stripped = value.strip()
|
|
51
|
+
if not stripped:
|
|
52
|
+
return []
|
|
53
|
+
return [item.strip() for item in stripped.split(",") if item.strip()]
|
|
54
|
+
if isinstance(value, tuple):
|
|
55
|
+
return list(value)
|
|
56
|
+
return value
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _validate_choice(value: str, *, allowed: set[str], env_name: str) -> str:
|
|
60
|
+
if value not in allowed:
|
|
61
|
+
allowed_values = ", ".join(sorted(allowed))
|
|
62
|
+
raise ValueError(f"{env_name} must be one of: {allowed_values}")
|
|
63
|
+
return value
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class Settings(BaseSettings):
|
|
67
|
+
model_config = SettingsConfigDict(
|
|
68
|
+
env_prefix="",
|
|
69
|
+
case_sensitive=False,
|
|
70
|
+
env_file=".env",
|
|
71
|
+
extra="ignore",
|
|
72
|
+
populate_by_name=True,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Codex settings (app-server mode)
|
|
76
|
+
codex_workspace_root: str | None = Field(
|
|
77
|
+
default=None,
|
|
78
|
+
alias="CODEX_WORKSPACE_ROOT",
|
|
79
|
+
)
|
|
80
|
+
codex_provider_id: str | None = Field(
|
|
81
|
+
default=None,
|
|
82
|
+
alias="CODEX_PROVIDER_ID",
|
|
83
|
+
)
|
|
84
|
+
codex_model_id: str | None = Field(
|
|
85
|
+
default=None,
|
|
86
|
+
alias="CODEX_MODEL_ID",
|
|
87
|
+
)
|
|
88
|
+
codex_agent: str | None = Field(
|
|
89
|
+
default=None,
|
|
90
|
+
alias="CODEX_AGENT",
|
|
91
|
+
)
|
|
92
|
+
codex_variant: str | None = Field(
|
|
93
|
+
default=None,
|
|
94
|
+
alias="CODEX_VARIANT",
|
|
95
|
+
)
|
|
96
|
+
codex_timeout: float = Field(
|
|
97
|
+
default=120.0,
|
|
98
|
+
alias="CODEX_TIMEOUT",
|
|
99
|
+
)
|
|
100
|
+
codex_timeout_stream: float | None = Field(
|
|
101
|
+
default=None,
|
|
102
|
+
alias="CODEX_TIMEOUT_STREAM",
|
|
103
|
+
)
|
|
104
|
+
codex_cli_bin: str = Field(
|
|
105
|
+
default="codex",
|
|
106
|
+
alias="CODEX_CLI_BIN",
|
|
107
|
+
)
|
|
108
|
+
codex_app_server_listen: str = Field(
|
|
109
|
+
default="stdio://",
|
|
110
|
+
alias="CODEX_APP_SERVER_LISTEN",
|
|
111
|
+
)
|
|
112
|
+
codex_model: str = Field(
|
|
113
|
+
default="gpt-5.1-codex",
|
|
114
|
+
alias="CODEX_MODEL",
|
|
115
|
+
)
|
|
116
|
+
codex_model_reasoning_effort: str | None = Field(
|
|
117
|
+
default=None,
|
|
118
|
+
alias="CODEX_MODEL_REASONING_EFFORT",
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# A2A settings
|
|
122
|
+
a2a_public_url: str = Field(default="http://127.0.0.1:8000", alias="A2A_PUBLIC_URL")
|
|
123
|
+
a2a_project: str | None = Field(default=None, alias="A2A_PROJECT")
|
|
124
|
+
a2a_title: str = Field(default="Codex A2A", alias="A2A_TITLE")
|
|
125
|
+
a2a_description: str = Field(default="A2A wrapper service for Codex", alias="A2A_DESCRIPTION")
|
|
126
|
+
a2a_version: str = Field(default=__version__, alias="A2A_VERSION")
|
|
127
|
+
a2a_protocol_version: str = Field(default="0.3.0", alias="A2A_PROTOCOL_VERSION")
|
|
128
|
+
a2a_enable_health_endpoint: bool = Field(default=True, alias="A2A_ENABLE_HEALTH_ENDPOINT")
|
|
129
|
+
a2a_enable_session_shell: bool = Field(default=True, alias="A2A_ENABLE_SESSION_SHELL")
|
|
130
|
+
a2a_log_level: str = Field(default="INFO", alias="A2A_LOG_LEVEL")
|
|
131
|
+
a2a_log_payloads: bool = Field(default=False, alias="A2A_LOG_PAYLOADS")
|
|
132
|
+
a2a_log_body_limit: int = Field(default=0, alias="A2A_LOG_BODY_LIMIT")
|
|
133
|
+
a2a_documentation_url: str | None = Field(default=None, alias="A2A_DOCUMENTATION_URL")
|
|
134
|
+
a2a_allow_directory_override: bool = Field(default=True, alias="A2A_ALLOW_DIRECTORY_OVERRIDE")
|
|
135
|
+
a2a_host: str = Field(default="127.0.0.1", alias="A2A_HOST")
|
|
136
|
+
a2a_port: int = Field(default=8000, alias="A2A_PORT")
|
|
137
|
+
a2a_bearer_token: str = Field(..., min_length=1, alias="A2A_BEARER_TOKEN")
|
|
138
|
+
|
|
139
|
+
# Session cache settings
|
|
140
|
+
a2a_session_cache_ttl_seconds: int = Field(default=3600, alias="A2A_SESSION_CACHE_TTL_SECONDS")
|
|
141
|
+
a2a_session_cache_maxsize: int = Field(default=10_000, alias="A2A_SESSION_CACHE_MAXSIZE")
|
|
142
|
+
a2a_cancel_abort_timeout_seconds: float = Field(
|
|
143
|
+
default=1.0,
|
|
144
|
+
alias="A2A_CANCEL_ABORT_TIMEOUT_SECONDS",
|
|
145
|
+
)
|
|
146
|
+
a2a_stream_idle_diagnostic_seconds: float = Field(
|
|
147
|
+
default=60.0,
|
|
148
|
+
alias="A2A_STREAM_IDLE_DIAGNOSTIC_SECONDS",
|
|
149
|
+
)
|
|
150
|
+
a2a_interrupt_request_ttl_seconds: int = Field(
|
|
151
|
+
default=3600,
|
|
152
|
+
alias="A2A_INTERRUPT_REQUEST_TTL_SECONDS",
|
|
153
|
+
)
|
|
154
|
+
a2a_execution_sandbox_mode: str = Field(
|
|
155
|
+
default="unknown",
|
|
156
|
+
alias="A2A_EXECUTION_SANDBOX_MODE",
|
|
157
|
+
)
|
|
158
|
+
a2a_execution_sandbox_filesystem_scope: str | None = Field(
|
|
159
|
+
default=None,
|
|
160
|
+
alias="A2A_EXECUTION_SANDBOX_FILESYSTEM_SCOPE",
|
|
161
|
+
)
|
|
162
|
+
a2a_execution_sandbox_writable_roots: Annotated[list[str], NoDecode] = Field(
|
|
163
|
+
default_factory=list,
|
|
164
|
+
alias="A2A_EXECUTION_SANDBOX_WRITABLE_ROOTS",
|
|
165
|
+
)
|
|
166
|
+
a2a_execution_network_access: str = Field(
|
|
167
|
+
default="unknown",
|
|
168
|
+
alias="A2A_EXECUTION_NETWORK_ACCESS",
|
|
169
|
+
)
|
|
170
|
+
a2a_execution_network_allowed_domains: Annotated[list[str], NoDecode] = Field(
|
|
171
|
+
default_factory=list,
|
|
172
|
+
alias="A2A_EXECUTION_NETWORK_ALLOWED_DOMAINS",
|
|
173
|
+
)
|
|
174
|
+
a2a_execution_approval_policy: str = Field(
|
|
175
|
+
default="unknown",
|
|
176
|
+
alias="A2A_EXECUTION_APPROVAL_POLICY",
|
|
177
|
+
)
|
|
178
|
+
a2a_execution_approval_escalation_behavior: str | None = Field(
|
|
179
|
+
default=None,
|
|
180
|
+
alias="A2A_EXECUTION_APPROVAL_ESCALATION_BEHAVIOR",
|
|
181
|
+
)
|
|
182
|
+
a2a_execution_write_access_scope: str | None = Field(
|
|
183
|
+
default=None,
|
|
184
|
+
alias="A2A_EXECUTION_WRITE_ACCESS_SCOPE",
|
|
185
|
+
)
|
|
186
|
+
a2a_execution_write_outside_workspace: bool | None = Field(
|
|
187
|
+
default=None,
|
|
188
|
+
alias="A2A_EXECUTION_WRITE_OUTSIDE_WORKSPACE",
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
@field_validator("a2a_cancel_abort_timeout_seconds")
|
|
192
|
+
@classmethod
|
|
193
|
+
def validate_cancel_abort_timeout_seconds(cls, value: float) -> float:
|
|
194
|
+
if value < 0:
|
|
195
|
+
raise ValueError("A2A_CANCEL_ABORT_TIMEOUT_SECONDS must be >= 0")
|
|
196
|
+
return value
|
|
197
|
+
|
|
198
|
+
@field_validator("a2a_stream_idle_diagnostic_seconds")
|
|
199
|
+
@classmethod
|
|
200
|
+
def validate_stream_idle_diagnostic_seconds(cls, value: float) -> float:
|
|
201
|
+
if value <= 0:
|
|
202
|
+
raise ValueError("A2A_STREAM_IDLE_DIAGNOSTIC_SECONDS must be > 0")
|
|
203
|
+
return value
|
|
204
|
+
|
|
205
|
+
@field_validator("a2a_interrupt_request_ttl_seconds")
|
|
206
|
+
@classmethod
|
|
207
|
+
def validate_interrupt_request_ttl_seconds(cls, value: int) -> int:
|
|
208
|
+
if value < 1:
|
|
209
|
+
raise ValueError("A2A_INTERRUPT_REQUEST_TTL_SECONDS must be >= 1")
|
|
210
|
+
return value
|
|
211
|
+
|
|
212
|
+
@field_validator(
|
|
213
|
+
"a2a_execution_sandbox_writable_roots",
|
|
214
|
+
"a2a_execution_network_allowed_domains",
|
|
215
|
+
mode="before",
|
|
216
|
+
)
|
|
217
|
+
@classmethod
|
|
218
|
+
def parse_execution_lists(cls, value: Any) -> Any:
|
|
219
|
+
return _parse_str_list(value)
|
|
220
|
+
|
|
221
|
+
@field_validator("a2a_execution_sandbox_mode")
|
|
222
|
+
@classmethod
|
|
223
|
+
def validate_execution_sandbox_mode(cls, value: str) -> str:
|
|
224
|
+
return _validate_choice(
|
|
225
|
+
value,
|
|
226
|
+
allowed=_SANDBOX_MODES,
|
|
227
|
+
env_name="A2A_EXECUTION_SANDBOX_MODE",
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
@field_validator("a2a_execution_sandbox_filesystem_scope")
|
|
231
|
+
@classmethod
|
|
232
|
+
def validate_execution_sandbox_filesystem_scope(cls, value: str | None) -> str | None:
|
|
233
|
+
if value is None:
|
|
234
|
+
return value
|
|
235
|
+
return _validate_choice(
|
|
236
|
+
value,
|
|
237
|
+
allowed=_FILESYSTEM_SCOPES,
|
|
238
|
+
env_name="A2A_EXECUTION_SANDBOX_FILESYSTEM_SCOPE",
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
@field_validator("a2a_execution_network_access")
|
|
242
|
+
@classmethod
|
|
243
|
+
def validate_execution_network_access(cls, value: str) -> str:
|
|
244
|
+
return _validate_choice(
|
|
245
|
+
value,
|
|
246
|
+
allowed=_NETWORK_ACCESS_MODES,
|
|
247
|
+
env_name="A2A_EXECUTION_NETWORK_ACCESS",
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
@field_validator("a2a_execution_approval_policy")
|
|
251
|
+
@classmethod
|
|
252
|
+
def validate_execution_approval_policy(cls, value: str) -> str:
|
|
253
|
+
return _validate_choice(
|
|
254
|
+
value,
|
|
255
|
+
allowed=_APPROVAL_POLICIES,
|
|
256
|
+
env_name="A2A_EXECUTION_APPROVAL_POLICY",
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
@field_validator("a2a_execution_approval_escalation_behavior")
|
|
260
|
+
@classmethod
|
|
261
|
+
def validate_execution_approval_escalation_behavior(cls, value: str | None) -> str | None:
|
|
262
|
+
if value is None:
|
|
263
|
+
return value
|
|
264
|
+
return _validate_choice(
|
|
265
|
+
value,
|
|
266
|
+
allowed=_APPROVAL_ESCALATION_BEHAVIORS,
|
|
267
|
+
env_name="A2A_EXECUTION_APPROVAL_ESCALATION_BEHAVIOR",
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
@field_validator("a2a_execution_write_access_scope")
|
|
271
|
+
@classmethod
|
|
272
|
+
def validate_execution_write_access_scope(cls, value: str | None) -> str | None:
|
|
273
|
+
if value is None:
|
|
274
|
+
return value
|
|
275
|
+
return _validate_choice(
|
|
276
|
+
value,
|
|
277
|
+
allowed=_FILESYSTEM_SCOPES,
|
|
278
|
+
env_name="A2A_EXECUTION_WRITE_ACCESS_SCOPE",
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
@classmethod
|
|
282
|
+
def from_env(cls) -> Settings:
|
|
283
|
+
settings_cls: type[BaseSettings] = cls
|
|
284
|
+
return cast(Settings, settings_cls())
|
|
File without changes
|