a2a-handler 0.1.20__tar.gz → 0.1.22__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.
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/PKG-INFO +6 -4
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/README.md +3 -1
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/pyproject.toml +3 -3
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/cli/__init__.py +139 -5
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/cli/_helpers.py +102 -3
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/cli/card.py +9 -2
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/cli/message.py +285 -14
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/cli/schema.py +3 -4
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/cli/server.py +2 -2
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/cli/task.py +4 -1
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/common/logging.py +35 -13
- a2a_handler-0.1.22/src/a2a_handler/common/output.py +113 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/server/__init__.py +1 -1
- a2a_handler-0.1.22/src/a2a_handler/server/agent.py +133 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/server/card.py +58 -3
- a2a_handler-0.1.22/src/a2a_handler/server/tools/__init__.py +23 -0
- a2a_handler-0.1.22/src/a2a_handler/server/tools/a2a_docs.py +140 -0
- a2a_handler-0.1.22/src/a2a_handler/server/tools/handler_docs.py +44 -0
- a2a_handler-0.1.22/src/a2a_handler/server/tools/source.py +109 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/servers.py +35 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/service.py +3 -1
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/app.py +48 -10
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/app.tcss +154 -12
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/components/artifacts.py +6 -19
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/components/card.py +6 -4
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/components/input.py +29 -1
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/components/messages.py +188 -19
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/components/tasks.py +99 -32
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/server/tab.py +199 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/server/views.py +13 -4
- a2a_handler-0.1.20/src/a2a_handler/common/output.py +0 -66
- a2a_handler-0.1.20/src/a2a_handler/server/agent.py +0 -76
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/LICENSE +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/__init__.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/auth.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/cli/mcp.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/cli/session.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/common/__init__.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/common/config.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/common/dotenv.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/common/input_validation.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/mcp/__init__.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/mcp/server.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/server/app.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/server/ollama.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/session.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/__init__.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/commands/__init__.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/commands/palette.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/commands/screens.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/components/__init__.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/components/auth.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/components/headers.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/components/logs.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/server/__init__.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/server/save.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/server/session.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/server/tabs.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/server/types.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/tui/server/workspace.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/validation.py +0 -0
- {a2a_handler-0.1.20 → a2a_handler-0.1.22}/src/a2a_handler/webhook.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: a2a-handler
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.22
|
|
4
4
|
Summary: An A2A Protocol client TUI and CLI.
|
|
5
5
|
Keywords: a2a,a2a-protocol,agent,agent-to-agent,ai,cli,tui
|
|
6
6
|
Author: Al Duncanson
|
|
@@ -20,7 +20,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
20
20
|
Classifier: Typing :: Typed
|
|
21
21
|
Requires-Dist: a2a-sdk>=0.3.24,<1.0.0
|
|
22
22
|
Requires-Dist: click>=8.0.0
|
|
23
|
-
Requires-Dist: google-adk>=
|
|
23
|
+
Requires-Dist: google-adk>=2.0.0
|
|
24
24
|
Requires-Dist: httpx>=0.27.0
|
|
25
25
|
Requires-Dist: litellm>=1.0.0
|
|
26
26
|
Requires-Dist: python-dotenv>=1.0.0
|
|
@@ -28,7 +28,7 @@ Requires-Dist: rich>=13.0.0
|
|
|
28
28
|
Requires-Dist: textual>=0.47.0
|
|
29
29
|
Requires-Dist: uvicorn>=0.30.0
|
|
30
30
|
Requires-Dist: textual-serve>=1.1.0
|
|
31
|
-
Requires-Dist: mcp[cli]>=1.
|
|
31
|
+
Requires-Dist: mcp[cli]>=1.27.1
|
|
32
32
|
Requires-Dist: truststore>=0.9.0
|
|
33
33
|
Requires-Dist: platformdirs>=4.0.0
|
|
34
34
|
Requires-Python: >=3.11
|
|
@@ -75,7 +75,9 @@ handler tui # launch the interactive TUI
|
|
|
75
75
|
handler message send URL "hello" # send a message from the CLI
|
|
76
76
|
handler card get URL # fetch an agent card
|
|
77
77
|
handler mcp # start the MCP server
|
|
78
|
-
handler server run agent # run the bundled
|
|
78
|
+
handler server run agent # run the bundled embedded agent
|
|
79
|
+
handler docs # open the hosted documentation
|
|
80
|
+
handler update # upgrade Handler to the latest release
|
|
79
81
|
```
|
|
80
82
|
|
|
81
83
|
## Run Without Installing
|
|
@@ -34,7 +34,9 @@ handler tui # launch the interactive TUI
|
|
|
34
34
|
handler message send URL "hello" # send a message from the CLI
|
|
35
35
|
handler card get URL # fetch an agent card
|
|
36
36
|
handler mcp # start the MCP server
|
|
37
|
-
handler server run agent # run the bundled
|
|
37
|
+
handler server run agent # run the bundled embedded agent
|
|
38
|
+
handler docs # open the hosted documentation
|
|
39
|
+
handler update # upgrade Handler to the latest release
|
|
38
40
|
```
|
|
39
41
|
|
|
40
42
|
## Run Without Installing
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "a2a-handler"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.22"
|
|
4
4
|
description = "An A2A Protocol client TUI and CLI."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -34,7 +34,7 @@ classifiers = [
|
|
|
34
34
|
dependencies = [
|
|
35
35
|
"a2a-sdk>=0.3.24,<1.0.0",
|
|
36
36
|
"click>=8.0.0",
|
|
37
|
-
"google-adk>=
|
|
37
|
+
"google-adk>=2.0.0",
|
|
38
38
|
"httpx>=0.27.0",
|
|
39
39
|
"litellm>=1.0.0",
|
|
40
40
|
"python-dotenv>=1.0.0",
|
|
@@ -42,7 +42,7 @@ dependencies = [
|
|
|
42
42
|
"textual>=0.47.0",
|
|
43
43
|
"uvicorn>=0.30.0",
|
|
44
44
|
"textual-serve>=1.1.0",
|
|
45
|
-
"mcp[cli]>=1.
|
|
45
|
+
"mcp[cli]>=1.27.1",
|
|
46
46
|
"truststore>=0.9.0",
|
|
47
47
|
"platformdirs>=4.0.0",
|
|
48
48
|
]
|
|
@@ -19,6 +19,11 @@ truststore.inject_into_ssl()
|
|
|
19
19
|
|
|
20
20
|
import logging
|
|
21
21
|
import os
|
|
22
|
+
import shutil
|
|
23
|
+
import subprocess
|
|
24
|
+
import webbrowser
|
|
25
|
+
from collections.abc import Sequence
|
|
26
|
+
from typing import Any
|
|
22
27
|
|
|
23
28
|
logging.getLogger().setLevel(logging.WARNING)
|
|
24
29
|
|
|
@@ -30,6 +35,7 @@ from a2a_handler.common.dotenv import load_runtime_dotenv
|
|
|
30
35
|
from a2a_handler.common.output import OutputFormat
|
|
31
36
|
from a2a_handler.tui import HandlerTUI
|
|
32
37
|
|
|
38
|
+
from ._helpers import configure_http_timeouts
|
|
33
39
|
from .card import card
|
|
34
40
|
from .mcp import mcp
|
|
35
41
|
from .message import message
|
|
@@ -40,24 +46,81 @@ from .task import task
|
|
|
40
46
|
|
|
41
47
|
log = get_logger(__name__)
|
|
42
48
|
|
|
49
|
+
DOCS_URL = "https://handler.alduncanson.com/"
|
|
50
|
+
PACKAGE_NAME = "a2a-handler"
|
|
43
51
|
|
|
44
|
-
|
|
52
|
+
|
|
53
|
+
class RuntimeDotenvGroup(click.Group):
|
|
54
|
+
"""Click group that loads workspace .env before option envvars resolve."""
|
|
55
|
+
|
|
56
|
+
def main(
|
|
57
|
+
self,
|
|
58
|
+
args: Sequence[str] | None = None,
|
|
59
|
+
prog_name: str | None = None,
|
|
60
|
+
complete_var: str | None = None,
|
|
61
|
+
standalone_mode: bool = True,
|
|
62
|
+
windows_expand_args: bool = True,
|
|
63
|
+
**extra: Any,
|
|
64
|
+
) -> Any:
|
|
65
|
+
"""Load runtime dotenv before Click parses envvar-backed options."""
|
|
66
|
+
load_runtime_dotenv()
|
|
67
|
+
return super().main(
|
|
68
|
+
args=args,
|
|
69
|
+
prog_name=prog_name,
|
|
70
|
+
complete_var=complete_var,
|
|
71
|
+
standalone_mode=standalone_mode,
|
|
72
|
+
windows_expand_args=windows_expand_args,
|
|
73
|
+
**extra,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@click.group(cls=RuntimeDotenvGroup)
|
|
45
78
|
@click.version_option(version=__version__, prog_name="handler")
|
|
46
79
|
@click.option("--verbose", "-v", is_flag=True, help="Enable verbose logging")
|
|
47
80
|
@click.option("--debug", "-d", is_flag=True, help="Enable debug logging")
|
|
48
81
|
@click.option(
|
|
49
82
|
"--output",
|
|
50
83
|
"output_format",
|
|
51
|
-
type=click.Choice(["json", "ndjson"]),
|
|
52
|
-
default="
|
|
84
|
+
type=click.Choice(["text", "json", "ndjson"]),
|
|
85
|
+
default="text",
|
|
53
86
|
show_default=True,
|
|
54
|
-
help="Output format",
|
|
87
|
+
help="Output format (use json/ndjson for structured output)",
|
|
55
88
|
)
|
|
56
89
|
@click.option(
|
|
57
90
|
"--quiet",
|
|
58
91
|
is_flag=True,
|
|
59
92
|
help="Suppress non-error output",
|
|
60
93
|
)
|
|
94
|
+
@click.option(
|
|
95
|
+
"--connect-timeout",
|
|
96
|
+
envvar="HANDLER_CONNECT_TIMEOUT",
|
|
97
|
+
metavar="SECONDS|none",
|
|
98
|
+
help="HTTP connect timeout in seconds (env: HANDLER_CONNECT_TIMEOUT)",
|
|
99
|
+
)
|
|
100
|
+
@click.option(
|
|
101
|
+
"--read-timeout",
|
|
102
|
+
envvar="HANDLER_READ_TIMEOUT",
|
|
103
|
+
metavar="SECONDS|none",
|
|
104
|
+
help="HTTP read timeout for non-streaming calls (env: HANDLER_READ_TIMEOUT)",
|
|
105
|
+
)
|
|
106
|
+
@click.option(
|
|
107
|
+
"--write-timeout",
|
|
108
|
+
envvar="HANDLER_WRITE_TIMEOUT",
|
|
109
|
+
metavar="SECONDS|none",
|
|
110
|
+
help="HTTP write timeout in seconds (env: HANDLER_WRITE_TIMEOUT)",
|
|
111
|
+
)
|
|
112
|
+
@click.option(
|
|
113
|
+
"--pool-timeout",
|
|
114
|
+
envvar="HANDLER_POOL_TIMEOUT",
|
|
115
|
+
metavar="SECONDS|none",
|
|
116
|
+
help="HTTP connection pool timeout in seconds (env: HANDLER_POOL_TIMEOUT)",
|
|
117
|
+
)
|
|
118
|
+
@click.option(
|
|
119
|
+
"--stream-read-timeout",
|
|
120
|
+
envvar="HANDLER_STREAM_READ_TIMEOUT",
|
|
121
|
+
metavar="SECONDS|none",
|
|
122
|
+
help="HTTP read timeout for streaming calls; default is none (env: HANDLER_STREAM_READ_TIMEOUT)",
|
|
123
|
+
)
|
|
61
124
|
@click.pass_context
|
|
62
125
|
def cli(
|
|
63
126
|
ctx: click.Context,
|
|
@@ -65,13 +128,24 @@ def cli(
|
|
|
65
128
|
debug: bool,
|
|
66
129
|
output_format: OutputFormat,
|
|
67
130
|
quiet: bool,
|
|
131
|
+
connect_timeout: str | None,
|
|
132
|
+
read_timeout: str | None,
|
|
133
|
+
write_timeout: str | None,
|
|
134
|
+
pool_timeout: str | None,
|
|
135
|
+
stream_read_timeout: str | None,
|
|
68
136
|
) -> None:
|
|
69
137
|
"""Handler - A2A protocol client CLI."""
|
|
70
|
-
load_runtime_dotenv()
|
|
71
138
|
ctx.ensure_object(dict)
|
|
72
139
|
ctx.obj["output_format"] = output_format
|
|
73
140
|
ctx.obj["quiet"] = quiet
|
|
74
141
|
configure_output(output_format=output_format, quiet=quiet)
|
|
142
|
+
configure_http_timeouts(
|
|
143
|
+
connect_timeout=connect_timeout,
|
|
144
|
+
read_timeout=read_timeout,
|
|
145
|
+
write_timeout=write_timeout,
|
|
146
|
+
pool_timeout=pool_timeout,
|
|
147
|
+
stream_read_timeout=stream_read_timeout,
|
|
148
|
+
)
|
|
75
149
|
|
|
76
150
|
if debug:
|
|
77
151
|
setup_logging(level="DEBUG")
|
|
@@ -103,6 +177,66 @@ def version() -> None:
|
|
|
103
177
|
output.json({"version": __version__})
|
|
104
178
|
|
|
105
179
|
|
|
180
|
+
@cli.command()
|
|
181
|
+
def docs() -> None:
|
|
182
|
+
"""Open the Handler documentation in your browser.
|
|
183
|
+
|
|
184
|
+
\b
|
|
185
|
+
Examples:
|
|
186
|
+
$ handler docs
|
|
187
|
+
"""
|
|
188
|
+
opened = webbrowser.open(DOCS_URL)
|
|
189
|
+
output = Output()
|
|
190
|
+
output.json({"url": DOCS_URL, "opened": opened})
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def _upgrade_command() -> list[str] | None:
|
|
194
|
+
"""Return the preferred package manager command for upgrading Handler."""
|
|
195
|
+
if shutil.which("uv"):
|
|
196
|
+
return ["uv", "tool", "upgrade", PACKAGE_NAME]
|
|
197
|
+
if shutil.which("pipx"):
|
|
198
|
+
return ["pipx", "upgrade", PACKAGE_NAME]
|
|
199
|
+
return None
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@cli.command()
|
|
203
|
+
def update() -> None:
|
|
204
|
+
"""Update Handler to the latest published version.
|
|
205
|
+
|
|
206
|
+
\b
|
|
207
|
+
Examples:
|
|
208
|
+
$ handler update
|
|
209
|
+
$ handler upgrade
|
|
210
|
+
"""
|
|
211
|
+
output = Output()
|
|
212
|
+
command = _upgrade_command()
|
|
213
|
+
if command is None:
|
|
214
|
+
output.error(
|
|
215
|
+
code="installer_not_found",
|
|
216
|
+
message="Could not find uv or pipx to update Handler.",
|
|
217
|
+
suggestion=(
|
|
218
|
+
"Install uv or pipx, then run `uv tool upgrade a2a-handler` "
|
|
219
|
+
"or `pipx upgrade a2a-handler`."
|
|
220
|
+
),
|
|
221
|
+
)
|
|
222
|
+
raise SystemExit(1)
|
|
223
|
+
|
|
224
|
+
result = subprocess.run(command, check=False)
|
|
225
|
+
if result.returncode != 0:
|
|
226
|
+
output.error(
|
|
227
|
+
code="update_failed",
|
|
228
|
+
message="Handler update command failed.",
|
|
229
|
+
details={
|
|
230
|
+
"command": command,
|
|
231
|
+
"returncode": result.returncode,
|
|
232
|
+
},
|
|
233
|
+
)
|
|
234
|
+
raise SystemExit(result.returncode)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
cli.add_command(update, name="upgrade")
|
|
238
|
+
|
|
239
|
+
|
|
106
240
|
@cli.command()
|
|
107
241
|
@click.option(
|
|
108
242
|
"--bearer-env", "-b", help="Env var containing bearer token for agent auth"
|
|
@@ -27,6 +27,13 @@ from a2a_handler.servers import (
|
|
|
27
27
|
)
|
|
28
28
|
|
|
29
29
|
TIMEOUT = 120
|
|
30
|
+
_TIMEOUT_NONE_VALUES = {"none", "null", "off", "disabled"}
|
|
31
|
+
|
|
32
|
+
_connect_timeout: float | None = float(TIMEOUT)
|
|
33
|
+
_read_timeout: float | None = float(TIMEOUT)
|
|
34
|
+
_write_timeout: float | None = float(TIMEOUT)
|
|
35
|
+
_pool_timeout: float | None = float(TIMEOUT)
|
|
36
|
+
_stream_read_timeout: float | None = None
|
|
30
37
|
log = get_logger(__name__)
|
|
31
38
|
|
|
32
39
|
|
|
@@ -39,17 +46,109 @@ class AgentSelection:
|
|
|
39
46
|
|
|
40
47
|
|
|
41
48
|
def build_http_client(
|
|
42
|
-
timeout: int =
|
|
49
|
+
timeout: int | float | httpx.Timeout | None = None,
|
|
43
50
|
credentials: AuthCredentials | None = None,
|
|
44
51
|
) -> httpx.AsyncClient:
|
|
45
52
|
"""Build an HTTP client with the specified timeout."""
|
|
53
|
+
effective_timeout = timeout if timeout is not None else _standard_timeout()
|
|
46
54
|
if credentials and credentials.auth_type == AuthType.MTLS:
|
|
47
55
|
return httpx.AsyncClient(
|
|
48
|
-
timeout=
|
|
56
|
+
timeout=effective_timeout,
|
|
49
57
|
verify=credentials.build_ssl_context(),
|
|
50
58
|
trust_env=False,
|
|
51
59
|
)
|
|
52
|
-
return httpx.AsyncClient(timeout=
|
|
60
|
+
return httpx.AsyncClient(timeout=effective_timeout, trust_env=False)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def build_streaming_http_client(
|
|
64
|
+
credentials: AuthCredentials | None = None,
|
|
65
|
+
) -> httpx.AsyncClient:
|
|
66
|
+
"""Build an HTTP client for long-lived streaming responses.
|
|
67
|
+
|
|
68
|
+
Streaming keeps the usual finite connect/write/pool timeouts but disables
|
|
69
|
+
the read timeout so an active long-running A2A task is not aborted just
|
|
70
|
+
because the server has no SSE event ready for a while.
|
|
71
|
+
"""
|
|
72
|
+
return build_http_client(
|
|
73
|
+
timeout=httpx.Timeout(
|
|
74
|
+
connect=_connect_timeout,
|
|
75
|
+
read=_stream_read_timeout,
|
|
76
|
+
write=_write_timeout,
|
|
77
|
+
pool=_pool_timeout,
|
|
78
|
+
),
|
|
79
|
+
credentials=credentials,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def configure_http_timeouts(
|
|
84
|
+
*,
|
|
85
|
+
connect_timeout: str | int | float | None = None,
|
|
86
|
+
read_timeout: str | int | float | None = None,
|
|
87
|
+
write_timeout: str | int | float | None = None,
|
|
88
|
+
pool_timeout: str | int | float | None = None,
|
|
89
|
+
stream_read_timeout: str | int | float | None = None,
|
|
90
|
+
) -> None:
|
|
91
|
+
"""Configure default CLI HTTP timeouts.
|
|
92
|
+
|
|
93
|
+
Passing no values resets the defaults. String values may be seconds or
|
|
94
|
+
``none`` to disable that timeout.
|
|
95
|
+
"""
|
|
96
|
+
global _connect_timeout, _read_timeout, _write_timeout, _pool_timeout
|
|
97
|
+
global _stream_read_timeout
|
|
98
|
+
|
|
99
|
+
_connect_timeout = _parse_timeout_option(
|
|
100
|
+
connect_timeout, "connect-timeout", float(TIMEOUT)
|
|
101
|
+
)
|
|
102
|
+
_read_timeout = _parse_timeout_option(read_timeout, "read-timeout", float(TIMEOUT))
|
|
103
|
+
_write_timeout = _parse_timeout_option(
|
|
104
|
+
write_timeout, "write-timeout", float(TIMEOUT)
|
|
105
|
+
)
|
|
106
|
+
_pool_timeout = _parse_timeout_option(pool_timeout, "pool-timeout", float(TIMEOUT))
|
|
107
|
+
_stream_read_timeout = _parse_timeout_option(
|
|
108
|
+
stream_read_timeout, "stream-read-timeout", None
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _standard_timeout() -> httpx.Timeout:
|
|
113
|
+
"""Return the configured timeout for regular request/response calls."""
|
|
114
|
+
return httpx.Timeout(
|
|
115
|
+
connect=_connect_timeout,
|
|
116
|
+
read=_read_timeout,
|
|
117
|
+
write=_write_timeout,
|
|
118
|
+
pool=_pool_timeout,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _parse_timeout_option(
|
|
123
|
+
value: str | int | float | None,
|
|
124
|
+
field_name: str,
|
|
125
|
+
default: float | None,
|
|
126
|
+
) -> float | None:
|
|
127
|
+
"""Parse a CLI/env timeout value."""
|
|
128
|
+
if value is None:
|
|
129
|
+
return default
|
|
130
|
+
if isinstance(value, str):
|
|
131
|
+
normalized = value.strip().lower()
|
|
132
|
+
if not normalized:
|
|
133
|
+
return default
|
|
134
|
+
if normalized in _TIMEOUT_NONE_VALUES:
|
|
135
|
+
return None
|
|
136
|
+
try:
|
|
137
|
+
parsed = float(normalized)
|
|
138
|
+
except ValueError as exc:
|
|
139
|
+
raise click.BadParameter(
|
|
140
|
+
"must be a number of seconds or 'none'",
|
|
141
|
+
param_hint=f"--{field_name}",
|
|
142
|
+
) from exc
|
|
143
|
+
else:
|
|
144
|
+
parsed = float(value)
|
|
145
|
+
|
|
146
|
+
if parsed < 0:
|
|
147
|
+
raise click.BadParameter(
|
|
148
|
+
"must be greater than or equal to 0",
|
|
149
|
+
param_hint=f"--{field_name}",
|
|
150
|
+
)
|
|
151
|
+
return parsed
|
|
53
152
|
|
|
54
153
|
|
|
55
154
|
def handle_client_error(e: Exception, agent_url: str, output: Output | None) -> None:
|
|
@@ -11,8 +11,8 @@ from a2a_handler.common.input_validation import InputValidationError, validate_a
|
|
|
11
11
|
from a2a_handler.service import A2AService
|
|
12
12
|
from a2a_handler.validation import (
|
|
13
13
|
ValidationResult,
|
|
14
|
+
ValidationSource,
|
|
14
15
|
validate_agent_card_from_file,
|
|
15
|
-
validate_agent_card_from_url,
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
from ._helpers import (
|
|
@@ -155,7 +155,14 @@ def card_validate(
|
|
|
155
155
|
|
|
156
156
|
async def do_validate() -> None:
|
|
157
157
|
async with build_http_client(credentials=credentials) as http_client:
|
|
158
|
-
|
|
158
|
+
service = A2AService(http_client, resolved_url, credentials=credentials)
|
|
159
|
+
agent_card = await service.get_card()
|
|
160
|
+
result = ValidationResult(
|
|
161
|
+
valid=True,
|
|
162
|
+
source=resolved_url,
|
|
163
|
+
source_type=ValidationSource.URL,
|
|
164
|
+
agent_card=agent_card,
|
|
165
|
+
)
|
|
159
166
|
|
|
160
167
|
_format_validation_result(result, output)
|
|
161
168
|
|