agentenv-framework-protocol 0.1.269__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.
- agentenv_framework_protocol-0.1.269.dist-info/METADATA +599 -0
- agentenv_framework_protocol-0.1.269.dist-info/RECORD +20 -0
- agentenv_framework_protocol-0.1.269.dist-info/WHEEL +4 -0
- agentenv_framework_protocol-0.1.269.dist-info/licenses/LICENSE +202 -0
- agentenv_framework_protocol-0.1.269.dist-info/licenses/NOTICE +4 -0
- agentenv_framework_protocol-0.1.269.dist-info/licenses/THIRD_PARTY_NOTICES.md +1701 -0
- agentenv_protocol/__init__.py +121 -0
- agentenv_protocol/a2a_agent/__init__.py +204 -0
- agentenv_protocol/a2a_agent/_triggers.py +489 -0
- agentenv_protocol/a2a_agent/extensions.py +1151 -0
- agentenv_protocol/a2a_agent/framework.py +1283 -0
- agentenv_protocol/a2a_agent/registry.py +449 -0
- agentenv_protocol/a2a_agent/tasks/__init__.py +39 -0
- agentenv_protocol/a2a_agent/tasks/v1.py +408 -0
- agentenv_protocol/agent_env_environment.py +653 -0
- agentenv_protocol/client.py +185 -0
- agentenv_protocol/manifest.py +203 -0
- agentenv_protocol/preflight.py +81 -0
- agentenv_protocol/transfers.py +554 -0
- agentenv_protocol/types.py +165 -0
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
"""Discovery and validation for A2A extension implementations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import inspect
|
|
6
|
+
from collections.abc import Callable, Iterable, Mapping
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from types import UnionType
|
|
9
|
+
from typing import Any, Union, get_args, get_origin, get_type_hints
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel
|
|
12
|
+
|
|
13
|
+
from .extensions import (
|
|
14
|
+
_HANDLER_BINDING,
|
|
15
|
+
ExtensionActivation,
|
|
16
|
+
ExtensionDefinition,
|
|
17
|
+
HandlerBinding,
|
|
18
|
+
ImplementationOwner,
|
|
19
|
+
OperationDefinition,
|
|
20
|
+
_validate_reserved_definition,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _validate_handler_signature(
|
|
25
|
+
handler: Callable,
|
|
26
|
+
request_model: type[BaseModel] | None,
|
|
27
|
+
*,
|
|
28
|
+
label: str,
|
|
29
|
+
allow_request_supertype: bool = False,
|
|
30
|
+
) -> None:
|
|
31
|
+
if not inspect.iscoroutinefunction(handler):
|
|
32
|
+
raise ValueError(f"handler for {label} must be an async function")
|
|
33
|
+
parameters = list(inspect.signature(handler).parameters.values())
|
|
34
|
+
if request_model is None:
|
|
35
|
+
if parameters:
|
|
36
|
+
raise ValueError(f"handler for {label} must not accept a request argument")
|
|
37
|
+
return
|
|
38
|
+
if len(parameters) != 1 or parameters[0].kind not in (
|
|
39
|
+
inspect.Parameter.POSITIONAL_ONLY,
|
|
40
|
+
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
41
|
+
):
|
|
42
|
+
raise ValueError(
|
|
43
|
+
f"handler for {label} must accept exactly one typed request argument"
|
|
44
|
+
)
|
|
45
|
+
parameter = parameters[0]
|
|
46
|
+
try:
|
|
47
|
+
annotation = get_type_hints(handler).get(parameter.name, parameter.annotation)
|
|
48
|
+
except (NameError, TypeError):
|
|
49
|
+
annotation = parameter.annotation
|
|
50
|
+
if isinstance(annotation, str):
|
|
51
|
+
annotation = handler.__globals__.get(annotation, annotation)
|
|
52
|
+
is_union = isinstance(annotation, UnionType) or get_origin(annotation) is Union
|
|
53
|
+
accepted = get_args(annotation) if is_union else (annotation,)
|
|
54
|
+
valid_annotation = request_model in accepted
|
|
55
|
+
if allow_request_supertype:
|
|
56
|
+
valid_annotation = any(
|
|
57
|
+
isinstance(model, type)
|
|
58
|
+
and issubclass(model, BaseModel)
|
|
59
|
+
and issubclass(request_model, model)
|
|
60
|
+
for model in accepted
|
|
61
|
+
)
|
|
62
|
+
if not valid_annotation:
|
|
63
|
+
raise ValueError(
|
|
64
|
+
f"handler for {label} must annotate its request argument as "
|
|
65
|
+
f"{request_model.__name__}"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _deep_merge(base: dict[str, Any], overlay: Mapping[str, Any]) -> dict[str, Any]:
|
|
70
|
+
result = dict(base)
|
|
71
|
+
for key, value in overlay.items():
|
|
72
|
+
if isinstance(value, Mapping) and isinstance(result.get(key), Mapping):
|
|
73
|
+
result[key] = _deep_merge(dict(result[key]), value)
|
|
74
|
+
else:
|
|
75
|
+
result[key] = value
|
|
76
|
+
return result
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _effective_methods(method: str) -> tuple[str, ...]:
|
|
80
|
+
method = method.upper()
|
|
81
|
+
return (method, "HEAD") if method == "GET" else (method,)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@dataclass(frozen=True, slots=True)
|
|
85
|
+
class RegisteredOperation:
|
|
86
|
+
definition: OperationDefinition
|
|
87
|
+
handler: Callable | None
|
|
88
|
+
variant_handlers: Mapping[str, Callable]
|
|
89
|
+
enabled_optional_variants: frozenset[str]
|
|
90
|
+
request_model_override: type[BaseModel] | None = None
|
|
91
|
+
overridden: bool = False
|
|
92
|
+
|
|
93
|
+
def select_handler(
|
|
94
|
+
self, payload: Mapping[str, Any]
|
|
95
|
+
) -> tuple[Callable | None, str | None]:
|
|
96
|
+
variant = None
|
|
97
|
+
if self.definition.request is not None:
|
|
98
|
+
variant = self.definition.request.select_variant(
|
|
99
|
+
payload, self.enabled_optional_variants
|
|
100
|
+
)
|
|
101
|
+
return self.variant_handlers.get(variant, self.handler), variant
|
|
102
|
+
|
|
103
|
+
def request_model(self, variant: str | None) -> type[BaseModel] | None:
|
|
104
|
+
if self.definition.request is None:
|
|
105
|
+
return None
|
|
106
|
+
if variant is None and self.request_model_override is not None:
|
|
107
|
+
return self.request_model_override
|
|
108
|
+
return self.definition.request.model_for_variant(variant)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@dataclass(frozen=True, slots=True)
|
|
112
|
+
class RegisteredExtension:
|
|
113
|
+
activation: ExtensionActivation
|
|
114
|
+
operations: Mapping[str, RegisteredOperation]
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def definition(self) -> ExtensionDefinition:
|
|
118
|
+
return self.activation.definition
|
|
119
|
+
|
|
120
|
+
def to_card(self) -> dict[str, Any]:
|
|
121
|
+
definition = self.definition
|
|
122
|
+
params: dict[str, Any] = {}
|
|
123
|
+
if definition.endpoint is not None:
|
|
124
|
+
params["endpoint"] = definition.endpoint
|
|
125
|
+
methods: dict[str, Any] = {}
|
|
126
|
+
configured_methods = self.activation.wire_params.get("methods", {})
|
|
127
|
+
for operation in self.operations.values():
|
|
128
|
+
spec = operation.definition
|
|
129
|
+
method: dict[str, Any] = {"method": spec.method}
|
|
130
|
+
if definition.endpoint != spec.path:
|
|
131
|
+
method["endpoint"] = spec.path
|
|
132
|
+
configured_method = configured_methods.get(spec.name, {})
|
|
133
|
+
if spec.request is not None and "request" not in configured_method:
|
|
134
|
+
method["request"] = spec.request.to_card(
|
|
135
|
+
operation.enabled_optional_variants
|
|
136
|
+
)
|
|
137
|
+
if spec.response is not None:
|
|
138
|
+
method["response"] = spec.response.to_card()
|
|
139
|
+
methods[spec.name] = method
|
|
140
|
+
if methods:
|
|
141
|
+
params["methods"] = methods
|
|
142
|
+
params = _deep_merge(params, self.activation.wire_params)
|
|
143
|
+
card = {
|
|
144
|
+
"uri": definition.uri,
|
|
145
|
+
"description": (
|
|
146
|
+
self.activation.description
|
|
147
|
+
if self.activation.description is not None
|
|
148
|
+
else definition.description
|
|
149
|
+
),
|
|
150
|
+
"params": params,
|
|
151
|
+
}
|
|
152
|
+
if self.activation.required is not None:
|
|
153
|
+
card["required"] = self.activation.required
|
|
154
|
+
return card
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class ExtensionRegistry:
|
|
158
|
+
"""Resolved extensions, handlers, routes, and generated card entries."""
|
|
159
|
+
|
|
160
|
+
def __init__(self, extensions: Iterable[RegisteredExtension]) -> None:
|
|
161
|
+
self.extensions = tuple(extensions)
|
|
162
|
+
self._by_uri = {
|
|
163
|
+
extension.definition.uri: extension for extension in self.extensions
|
|
164
|
+
}
|
|
165
|
+
if len(self._by_uri) != len(self.extensions):
|
|
166
|
+
raise ValueError("duplicate extension URI")
|
|
167
|
+
|
|
168
|
+
seen_routes: dict[tuple[str, str], tuple[str, str]] = {}
|
|
169
|
+
for extension in self.extensions:
|
|
170
|
+
for operation in extension.operations.values():
|
|
171
|
+
identity = (extension.definition.uri, operation.definition.name)
|
|
172
|
+
for method in _effective_methods(operation.definition.method):
|
|
173
|
+
route = (operation.definition.path, method)
|
|
174
|
+
previous = seen_routes.get(route)
|
|
175
|
+
if previous is not None:
|
|
176
|
+
raise ValueError(
|
|
177
|
+
f"route {route[1]} {route[0]} is shared by "
|
|
178
|
+
f"{previous} and {identity}"
|
|
179
|
+
)
|
|
180
|
+
seen_routes[route] = identity
|
|
181
|
+
self._routes = seen_routes
|
|
182
|
+
|
|
183
|
+
def reject_framework_route_collisions(
|
|
184
|
+
self, routes: Mapping[tuple[str, str], str]
|
|
185
|
+
) -> None:
|
|
186
|
+
"""Reject extension operations that would intercept framework routes."""
|
|
187
|
+
for (path, method), owner in routes.items():
|
|
188
|
+
for effective_method in _effective_methods(method):
|
|
189
|
+
operation = self._routes.get((path, effective_method))
|
|
190
|
+
if operation is not None:
|
|
191
|
+
raise ValueError(
|
|
192
|
+
f"extension operation {operation} conflicts with {owner} "
|
|
193
|
+
f"route {effective_method} {path}"
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
def extension(self, uri: str) -> RegisteredExtension | None:
|
|
197
|
+
return self._by_uri.get(uri)
|
|
198
|
+
|
|
199
|
+
def card_extensions(self) -> list[dict[str, Any]]:
|
|
200
|
+
return [extension.to_card() for extension in self.extensions]
|
|
201
|
+
|
|
202
|
+
def conformance(self) -> dict[str, Any]:
|
|
203
|
+
overrides = []
|
|
204
|
+
for extension in self.extensions:
|
|
205
|
+
for operation in extension.operations.values():
|
|
206
|
+
if operation.overridden:
|
|
207
|
+
overrides.append(
|
|
208
|
+
{
|
|
209
|
+
"uri": extension.definition.uri,
|
|
210
|
+
"operation": operation.definition.name,
|
|
211
|
+
}
|
|
212
|
+
)
|
|
213
|
+
return {"standard_operation_overrides": overrides}
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _discover_bindings(agent: Any) -> list[tuple[HandlerBinding, Callable]]:
|
|
217
|
+
discovered = []
|
|
218
|
+
for name in dir(agent):
|
|
219
|
+
if name.startswith("__"):
|
|
220
|
+
continue
|
|
221
|
+
static_member = inspect.getattr_static(agent, name)
|
|
222
|
+
binding = getattr(static_member, _HANDLER_BINDING, None)
|
|
223
|
+
if binding is not None:
|
|
224
|
+
member = getattr(agent, name)
|
|
225
|
+
discovered.append((binding, member))
|
|
226
|
+
return discovered
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _feature_for_operation(
|
|
230
|
+
definition: ExtensionDefinition, operation_name: str
|
|
231
|
+
) -> str | None:
|
|
232
|
+
for feature_name, group in definition.optional_features.items():
|
|
233
|
+
if operation_name in group.operations:
|
|
234
|
+
return feature_name
|
|
235
|
+
return None
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def build_registry(
|
|
239
|
+
agent: Any,
|
|
240
|
+
declared: Iterable[ExtensionActivation | ExtensionDefinition] = (),
|
|
241
|
+
*,
|
|
242
|
+
sdk_handlers: Mapping[tuple[str, str], Callable] | None = None,
|
|
243
|
+
request_model_overrides: Mapping[tuple[str, str], type[BaseModel]] | None = None,
|
|
244
|
+
) -> ExtensionRegistry:
|
|
245
|
+
"""Build one validated registry from declarations and decorated methods."""
|
|
246
|
+
sdk_handlers = sdk_handlers or {}
|
|
247
|
+
request_model_overrides = request_model_overrides or {}
|
|
248
|
+
activations: dict[str, ExtensionActivation] = {}
|
|
249
|
+
for declaration in declared:
|
|
250
|
+
if isinstance(declaration, ExtensionDefinition):
|
|
251
|
+
activation = ExtensionActivation(declaration)
|
|
252
|
+
elif isinstance(declaration, ExtensionActivation):
|
|
253
|
+
activation = declaration
|
|
254
|
+
else:
|
|
255
|
+
raise TypeError(
|
|
256
|
+
"extensions must contain ExtensionDefinition or ExtensionActivation"
|
|
257
|
+
)
|
|
258
|
+
_validate_reserved_definition(activation.definition)
|
|
259
|
+
uri = activation.definition.uri
|
|
260
|
+
if uri in activations:
|
|
261
|
+
raise ValueError(f"extension {uri} is enabled more than once")
|
|
262
|
+
activations[uri] = activation
|
|
263
|
+
|
|
264
|
+
operation_handlers: dict[tuple[str, str], tuple[Callable, bool]] = {}
|
|
265
|
+
variant_handlers: dict[tuple[str, str, str], Callable] = {}
|
|
266
|
+
definitions: dict[str, ExtensionDefinition] = {
|
|
267
|
+
uri: activation.definition for uri, activation in activations.items()
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
for binding, handler in _discover_bindings(agent):
|
|
271
|
+
_validate_reserved_definition(binding.extension)
|
|
272
|
+
uri = binding.extension.uri
|
|
273
|
+
existing_definition = definitions.get(uri)
|
|
274
|
+
if existing_definition is not None and existing_definition != binding.extension:
|
|
275
|
+
raise ValueError(
|
|
276
|
+
f"conflicting definitions for extension {uri}; define one shared "
|
|
277
|
+
"ExtensionDefinition and bind each operation with @extension(...)"
|
|
278
|
+
)
|
|
279
|
+
definitions[uri] = binding.extension
|
|
280
|
+
# A decorated handler is itself an implementation declaration, so it
|
|
281
|
+
# activates both standard and custom extension definitions. An explicit
|
|
282
|
+
# activation, when present, retains its configuration and metadata.
|
|
283
|
+
activations.setdefault(uri, ExtensionActivation(binding.extension))
|
|
284
|
+
operation = binding.extension.operation(binding.operation)
|
|
285
|
+
if binding.variant is not None:
|
|
286
|
+
if operation.request is None:
|
|
287
|
+
raise ValueError(f"{uri}.{operation.name} has no request variants")
|
|
288
|
+
try:
|
|
289
|
+
variant = operation.request.variant(binding.variant)
|
|
290
|
+
except KeyError as exc:
|
|
291
|
+
raise ValueError(
|
|
292
|
+
f"unknown request variant {binding.variant!r} for {uri}.{operation.name}"
|
|
293
|
+
) from exc
|
|
294
|
+
variant_owner = variant.implementation or operation.implementation
|
|
295
|
+
if variant_owner is not ImplementationOwner.RUNTIME:
|
|
296
|
+
raise ValueError(
|
|
297
|
+
f"{uri}.{operation.name}.{variant.name} is not runtime-backed"
|
|
298
|
+
)
|
|
299
|
+
key = (uri, binding.operation, binding.variant)
|
|
300
|
+
if key in variant_handlers:
|
|
301
|
+
raise ValueError(
|
|
302
|
+
f"multiple handlers for {uri}.{operation.name}.{binding.variant}"
|
|
303
|
+
)
|
|
304
|
+
variant_handlers[key] = handler
|
|
305
|
+
continue
|
|
306
|
+
|
|
307
|
+
key = (uri, binding.operation)
|
|
308
|
+
if key in operation_handlers:
|
|
309
|
+
raise ValueError(f"multiple handlers for {uri}.{operation.name}")
|
|
310
|
+
operation_handlers[key] = (
|
|
311
|
+
handler,
|
|
312
|
+
operation.implementation is ImplementationOwner.SDK,
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
registered: list[RegisteredExtension] = []
|
|
316
|
+
for uri, activation in activations.items():
|
|
317
|
+
definition = definitions[uri]
|
|
318
|
+
enabled_features = set(activation.features)
|
|
319
|
+
|
|
320
|
+
for feature_name, group in definition.optional_features.items():
|
|
321
|
+
implemented = {
|
|
322
|
+
operation_name
|
|
323
|
+
for operation_name in group.operations
|
|
324
|
+
if (uri, operation_name) in operation_handlers
|
|
325
|
+
or any(
|
|
326
|
+
variant_uri == uri and variant_operation == operation_name
|
|
327
|
+
for variant_uri, variant_operation, _ in variant_handlers
|
|
328
|
+
)
|
|
329
|
+
}
|
|
330
|
+
if implemented:
|
|
331
|
+
if group.required_together and implemented != set(group.operations):
|
|
332
|
+
missing = set(group.operations) - implemented
|
|
333
|
+
raise ValueError(
|
|
334
|
+
f"feature {uri}.{feature_name} is incomplete; missing {sorted(missing)}"
|
|
335
|
+
)
|
|
336
|
+
enabled_features.add(feature_name)
|
|
337
|
+
|
|
338
|
+
active_operations: dict[str, OperationDefinition] = dict(
|
|
339
|
+
definition.core_operations
|
|
340
|
+
)
|
|
341
|
+
for feature_name in enabled_features:
|
|
342
|
+
active_operations.update(
|
|
343
|
+
definition.optional_features[feature_name].operations
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
resolved_operations: dict[str, RegisteredOperation] = {}
|
|
347
|
+
for operation_key, operation in active_operations.items():
|
|
348
|
+
bound = operation_handlers.get((uri, operation_key))
|
|
349
|
+
sdk_handler = sdk_handlers.get((uri, operation_key))
|
|
350
|
+
if bound is not None:
|
|
351
|
+
handler, overridden = bound
|
|
352
|
+
else:
|
|
353
|
+
handler = sdk_handler
|
|
354
|
+
overridden = False
|
|
355
|
+
|
|
356
|
+
enabled_variants = set(activation.variants.get(operation_key, frozenset()))
|
|
357
|
+
per_variant: dict[str, Callable] = {}
|
|
358
|
+
if operation.request is not None and operation.request.variants:
|
|
359
|
+
for variant in operation.request.variants:
|
|
360
|
+
variant_handler = variant_handlers.get(
|
|
361
|
+
(uri, operation_key, variant.name)
|
|
362
|
+
)
|
|
363
|
+
if variant_handler is not None:
|
|
364
|
+
per_variant[variant.name] = variant_handler
|
|
365
|
+
if not variant.support_required:
|
|
366
|
+
enabled_variants.add(variant.name)
|
|
367
|
+
|
|
368
|
+
for variant in operation.request.enabled_variants(enabled_variants):
|
|
369
|
+
selected = per_variant.get(variant.name, handler)
|
|
370
|
+
if selected is not None:
|
|
371
|
+
continue
|
|
372
|
+
variant_owner = variant.implementation or operation.implementation
|
|
373
|
+
owner = (
|
|
374
|
+
"runtime"
|
|
375
|
+
if variant_owner is ImplementationOwner.RUNTIME
|
|
376
|
+
else "SDK"
|
|
377
|
+
)
|
|
378
|
+
raise ValueError(
|
|
379
|
+
f"missing {owner} handler for "
|
|
380
|
+
f"{uri}.{operation.name}.{variant.name}"
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
for variant in operation.request.enabled_variants(enabled_variants):
|
|
384
|
+
selected = per_variant.get(variant.name, handler)
|
|
385
|
+
assert selected is not None
|
|
386
|
+
_validate_handler_signature(
|
|
387
|
+
selected,
|
|
388
|
+
variant.model,
|
|
389
|
+
label=f"{uri}.{operation.name}.{variant.name}",
|
|
390
|
+
allow_request_supertype=(
|
|
391
|
+
selected is sdk_handler and not overridden
|
|
392
|
+
),
|
|
393
|
+
)
|
|
394
|
+
elif handler is None:
|
|
395
|
+
owner = (
|
|
396
|
+
"runtime"
|
|
397
|
+
if operation.implementation is ImplementationOwner.RUNTIME
|
|
398
|
+
else "SDK"
|
|
399
|
+
)
|
|
400
|
+
raise ValueError(f"missing {owner} handler for {uri}.{operation.name}")
|
|
401
|
+
else:
|
|
402
|
+
request_model = request_model_overrides.get(
|
|
403
|
+
(uri, operation_key),
|
|
404
|
+
operation.request.model if operation.request is not None else None,
|
|
405
|
+
)
|
|
406
|
+
_validate_handler_signature(
|
|
407
|
+
handler,
|
|
408
|
+
request_model,
|
|
409
|
+
label=f"{uri}.{operation.name}",
|
|
410
|
+
allow_request_supertype=handler is sdk_handler and not overridden,
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
resolved_operations[operation_key] = RegisteredOperation(
|
|
414
|
+
definition=operation,
|
|
415
|
+
handler=handler,
|
|
416
|
+
variant_handlers=per_variant,
|
|
417
|
+
enabled_optional_variants=frozenset(enabled_variants),
|
|
418
|
+
request_model_override=request_model_overrides.get(
|
|
419
|
+
(uri, operation_key)
|
|
420
|
+
),
|
|
421
|
+
overridden=overridden,
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
active_sdk_operations = {
|
|
425
|
+
name
|
|
426
|
+
for name, operation in resolved_operations.items()
|
|
427
|
+
if operation.definition.implementation is ImplementationOwner.SDK
|
|
428
|
+
}
|
|
429
|
+
overridden_sdk_operations = {
|
|
430
|
+
name
|
|
431
|
+
for name in active_sdk_operations
|
|
432
|
+
if resolved_operations[name].overridden
|
|
433
|
+
}
|
|
434
|
+
if (
|
|
435
|
+
overridden_sdk_operations
|
|
436
|
+
and overridden_sdk_operations != active_sdk_operations
|
|
437
|
+
):
|
|
438
|
+
sdk_backed = active_sdk_operations - overridden_sdk_operations
|
|
439
|
+
raise ValueError(
|
|
440
|
+
f"SDK operations for extension {uri} must be overridden together; "
|
|
441
|
+
f"overridden={sorted(overridden_sdk_operations)}, "
|
|
442
|
+
f"SDK-backed={sorted(sdk_backed)}"
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
registered.append(
|
|
446
|
+
RegisteredExtension(activation=activation, operations=resolved_operations)
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
return ExtensionRegistry(registered)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Versioned public task contracts for A2A agent run methods."""
|
|
2
|
+
|
|
3
|
+
from .v1 import (
|
|
4
|
+
AgentConfig,
|
|
5
|
+
AgentRunResult,
|
|
6
|
+
DataPart,
|
|
7
|
+
FilePart,
|
|
8
|
+
NativeTrajectory,
|
|
9
|
+
TaskError,
|
|
10
|
+
TaskOutcome,
|
|
11
|
+
TaskPart,
|
|
12
|
+
TaskProgress,
|
|
13
|
+
TaskRequest,
|
|
14
|
+
TaskResult,
|
|
15
|
+
TaskResultBuilder,
|
|
16
|
+
TaskStreamItem,
|
|
17
|
+
TextPart,
|
|
18
|
+
Usage,
|
|
19
|
+
WriteOnly,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"AgentConfig",
|
|
24
|
+
"AgentRunResult",
|
|
25
|
+
"DataPart",
|
|
26
|
+
"FilePart",
|
|
27
|
+
"NativeTrajectory",
|
|
28
|
+
"TaskError",
|
|
29
|
+
"TaskOutcome",
|
|
30
|
+
"TaskPart",
|
|
31
|
+
"TaskProgress",
|
|
32
|
+
"TaskRequest",
|
|
33
|
+
"TaskResult",
|
|
34
|
+
"TaskResultBuilder",
|
|
35
|
+
"TaskStreamItem",
|
|
36
|
+
"TextPart",
|
|
37
|
+
"Usage",
|
|
38
|
+
"WriteOnly",
|
|
39
|
+
]
|