smarta2a 0.1.0__py3-none-any.whl → 0.2.1__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.
- {fasta2a → smarta2a}/__init__.py +3 -2
- {fasta2a → smarta2a}/server.py +119 -2
- {smarta2a-0.1.0.dist-info → smarta2a-0.2.1.dist-info}/METADATA +9 -9
- smarta2a-0.2.1.dist-info/RECORD +7 -0
- smarta2a-0.1.0.dist-info/RECORD +0 -7
- {fasta2a → smarta2a}/types.py +0 -0
- {smarta2a-0.1.0.dist-info → smarta2a-0.2.1.dist-info}/WHEEL +0 -0
- {smarta2a-0.1.0.dist-info → smarta2a-0.2.1.dist-info}/licenses/LICENSE +0 -0
{fasta2a → smarta2a}/__init__.py
RENAMED
{fasta2a → smarta2a}/server.py
RENAMED
@@ -48,9 +48,14 @@ from .types import (
|
|
48
48
|
A2AStatus,
|
49
49
|
A2AStreamResponse,
|
50
50
|
TaskSendParams,
|
51
|
+
SetTaskPushNotificationRequest,
|
52
|
+
GetTaskPushNotificationRequest,
|
53
|
+
SetTaskPushNotificationResponse,
|
54
|
+
GetTaskPushNotificationResponse,
|
55
|
+
TaskPushNotificationConfig,
|
51
56
|
)
|
52
57
|
|
53
|
-
class
|
58
|
+
class SmartA2A:
|
54
59
|
def __init__(self, name: str, **fastapi_kwargs):
|
55
60
|
self.name = name
|
56
61
|
self.handlers: Dict[str, Callable] = {}
|
@@ -96,7 +101,7 @@ class FastA2A:
|
|
96
101
|
if method in self._registered_decorators:
|
97
102
|
raise RuntimeError(
|
98
103
|
f"@{handler_name} decorator for method '{method}' "
|
99
|
-
f"can only be used once per
|
104
|
+
f"can only be used once per SmartA2A instance"
|
100
105
|
)
|
101
106
|
|
102
107
|
if handler_type == "handler":
|
@@ -129,6 +134,18 @@ class FastA2A:
|
|
129
134
|
self._register_handler("tasks/cancel", func, "task_cancel", "handler")
|
130
135
|
return func
|
131
136
|
return decorator
|
137
|
+
|
138
|
+
def set_notification(self):
|
139
|
+
def decorator(func: Callable[[SetTaskPushNotificationRequest], None]) -> Callable:
|
140
|
+
self._register_handler("tasks/pushNotification/set", func, "set_notification", "handler")
|
141
|
+
return func
|
142
|
+
return decorator
|
143
|
+
|
144
|
+
def get_notification(self):
|
145
|
+
def decorator(func: Callable[[GetTaskPushNotificationRequest], Union[TaskPushNotificationConfig, GetTaskPushNotificationResponse]]):
|
146
|
+
self._register_handler("tasks/pushNotification/get", func, "get_notification", "handler")
|
147
|
+
return func
|
148
|
+
return decorator
|
132
149
|
|
133
150
|
async def process_request(self, request_data: dict) -> JSONRPCResponse:
|
134
151
|
try:
|
@@ -141,6 +158,10 @@ class FastA2A:
|
|
141
158
|
return self._handle_get_task(request_data)
|
142
159
|
elif method == "tasks/cancel":
|
143
160
|
return self._handle_cancel_task(request_data)
|
161
|
+
elif method == "tasks/pushNotification/set":
|
162
|
+
return self._handle_set_notification(request_data)
|
163
|
+
elif method == "tasks/pushNotification/get":
|
164
|
+
return self._handle_get_notification(request_data)
|
144
165
|
else:
|
145
166
|
return self._error_response(
|
146
167
|
request_data.get("id"),
|
@@ -422,6 +443,102 @@ class FastA2A:
|
|
422
443
|
error=InternalError(data=str(e))
|
423
444
|
)
|
424
445
|
|
446
|
+
def _handle_set_notification(self, request_data: dict) -> SetTaskPushNotificationResponse:
|
447
|
+
try:
|
448
|
+
request = SetTaskPushNotificationRequest.model_validate(request_data)
|
449
|
+
handler = self.handlers.get("tasks/pushNotification/set")
|
450
|
+
|
451
|
+
if not handler:
|
452
|
+
return SetTaskPushNotificationResponse(
|
453
|
+
id=request.id,
|
454
|
+
error=MethodNotFoundError()
|
455
|
+
)
|
456
|
+
|
457
|
+
try:
|
458
|
+
# Execute handler (may or may not return something)
|
459
|
+
raw_result = handler(request)
|
460
|
+
|
461
|
+
# If handler returns nothing - build success response from request params
|
462
|
+
if raw_result is None:
|
463
|
+
return SetTaskPushNotificationResponse(
|
464
|
+
id=request.id,
|
465
|
+
result=request.params
|
466
|
+
)
|
467
|
+
|
468
|
+
# If handler returns a full response object
|
469
|
+
if isinstance(raw_result, SetTaskPushNotificationResponse):
|
470
|
+
return raw_result
|
471
|
+
|
472
|
+
|
473
|
+
except Exception as e:
|
474
|
+
if isinstance(e, JSONRPCError):
|
475
|
+
return SetTaskPushNotificationResponse(
|
476
|
+
id=request.id,
|
477
|
+
error=e
|
478
|
+
)
|
479
|
+
return SetTaskPushNotificationResponse(
|
480
|
+
id=request.id,
|
481
|
+
error=InternalError(data=str(e))
|
482
|
+
)
|
483
|
+
|
484
|
+
except ValidationError as e:
|
485
|
+
return SetTaskPushNotificationResponse(
|
486
|
+
id=request_data.get("id"),
|
487
|
+
error=InvalidRequestError(data=e.errors())
|
488
|
+
)
|
489
|
+
|
490
|
+
|
491
|
+
def _handle_get_notification(self, request_data: dict) -> GetTaskPushNotificationResponse:
|
492
|
+
try:
|
493
|
+
request = GetTaskPushNotificationRequest.model_validate(request_data)
|
494
|
+
handler = self.handlers.get("tasks/pushNotification/get")
|
495
|
+
|
496
|
+
if not handler:
|
497
|
+
return GetTaskPushNotificationResponse(
|
498
|
+
id=request.id,
|
499
|
+
error=MethodNotFoundError()
|
500
|
+
)
|
501
|
+
|
502
|
+
try:
|
503
|
+
raw_result = handler(request)
|
504
|
+
|
505
|
+
if isinstance(raw_result, GetTaskPushNotificationResponse):
|
506
|
+
return raw_result
|
507
|
+
else:
|
508
|
+
# Validate raw_result as TaskPushNotificationConfig
|
509
|
+
config = TaskPushNotificationConfig.model_validate(raw_result)
|
510
|
+
return GetTaskPushNotificationResponse(
|
511
|
+
id=request.id,
|
512
|
+
result=config
|
513
|
+
)
|
514
|
+
except ValidationError as e:
|
515
|
+
return GetTaskPushNotificationResponse(
|
516
|
+
id=request.id,
|
517
|
+
error=InvalidParamsError(data=e.errors())
|
518
|
+
)
|
519
|
+
except Exception as e:
|
520
|
+
if isinstance(e, JSONRPCError):
|
521
|
+
return GetTaskPushNotificationResponse(
|
522
|
+
id=request.id,
|
523
|
+
error=e
|
524
|
+
)
|
525
|
+
return GetTaskPushNotificationResponse(
|
526
|
+
id=request.id,
|
527
|
+
error=InternalError(data=str(e))
|
528
|
+
)
|
529
|
+
|
530
|
+
except ValidationError as e:
|
531
|
+
return GetTaskPushNotificationResponse(
|
532
|
+
id=request_data.get("id"),
|
533
|
+
error=InvalidRequestError(data=e.errors())
|
534
|
+
)
|
535
|
+
except json.JSONDecodeError as e:
|
536
|
+
return GetTaskPushNotificationResponse(
|
537
|
+
id=request_data.get("id"),
|
538
|
+
error=JSONParseError(data=str(e))
|
539
|
+
)
|
540
|
+
|
541
|
+
|
425
542
|
def _normalize_artifacts(self, content: Any) -> List[Artifact]:
|
426
543
|
"""Handle both A2AResponse content and regular returns"""
|
427
544
|
if isinstance(content, Artifact):
|
@@ -1,9 +1,9 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: smarta2a
|
3
|
-
Version: 0.1
|
3
|
+
Version: 0.2.1
|
4
4
|
Summary: A Python package for creating servers and clients following Google's Agent2Agent protocol
|
5
|
-
Project-URL: Homepage, https://github.com/siddharthsma/
|
6
|
-
Project-URL: Bug Tracker, https://github.com/siddharthsma/
|
5
|
+
Project-URL: Homepage, https://github.com/siddharthsma/smarta2a
|
6
|
+
Project-URL: Bug Tracker, https://github.com/siddharthsma/smarta2a/issues
|
7
7
|
Author-email: Siddharth Ambegaonkar <siddharthsma@gmail.com>
|
8
8
|
License-File: LICENSE
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
@@ -16,7 +16,7 @@ Requires-Dist: sse-starlette
|
|
16
16
|
Requires-Dist: uvicorn
|
17
17
|
Description-Content-Type: text/markdown
|
18
18
|
|
19
|
-
#
|
19
|
+
# SmartA2A
|
20
20
|
|
21
21
|
A Python package for creating a server following Google's Agent2Agent protocol
|
22
22
|
|
@@ -39,15 +39,15 @@ A Python package for creating a server following Google's Agent2Agent protocol
|
|
39
39
|
## Installation
|
40
40
|
|
41
41
|
```bash
|
42
|
-
pip install
|
42
|
+
pip install smarta2a
|
43
43
|
```
|
44
44
|
|
45
45
|
## Simple Echo Server Implementation
|
46
46
|
|
47
47
|
```python
|
48
|
-
from
|
48
|
+
from smarta2a import SmartA2A
|
49
49
|
|
50
|
-
app =
|
50
|
+
app = SmartA2A("EchoServer")
|
51
51
|
|
52
52
|
@app.on_send_task()
|
53
53
|
def handle_task(request):
|
@@ -81,8 +81,8 @@ To set up the development environment:
|
|
81
81
|
|
82
82
|
```bash
|
83
83
|
# Clone the repository
|
84
|
-
git clone https://github.com/siddharthsma/
|
85
|
-
cd
|
84
|
+
git clone https://github.com/siddharthsma/smarta2a.git
|
85
|
+
cd smarta2a
|
86
86
|
|
87
87
|
# Create and activate virtual environment
|
88
88
|
python -m venv venv
|
@@ -0,0 +1,7 @@
|
|
1
|
+
smarta2a/__init__.py,sha256=f_RqeaAHiBXO0O8n2kR8EBLGM3ezNwmR-CV-xHeOHLM,182
|
2
|
+
smarta2a/server.py,sha256=lFUlAz4TEeEXCs2bgJmMTN7JpZTwYEKXyt4KWEQwS6U,30915
|
3
|
+
smarta2a/types.py,sha256=_UuFtOsnHIIqfQ2m_FiIBBp141iYmhpPGgxE0jmHSHg,10807
|
4
|
+
smarta2a-0.2.1.dist-info/METADATA,sha256=H4os9rBnBzByJI1FWr7vYW2w8Or8PInU7XtmwsHCIcY,2478
|
5
|
+
smarta2a-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
6
|
+
smarta2a-0.2.1.dist-info/licenses/LICENSE,sha256=ECMEVHuFkvpEmH-_A9HSxs_UnnsUqpCkiAYNHPCf2z0,1078
|
7
|
+
smarta2a-0.2.1.dist-info/RECORD,,
|
smarta2a-0.1.0.dist-info/RECORD
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
fasta2a/__init__.py,sha256=lW8fJ0XHZJVZC4Oy18UxJjxtxuSco878tV6wAKiCzw0,150
|
2
|
-
fasta2a/server.py,sha256=Ge0eh6Go8P9LUmQwmFysTx2YSvRoWk3UIkVh7o-mAHU,26115
|
3
|
-
fasta2a/types.py,sha256=_UuFtOsnHIIqfQ2m_FiIBBp141iYmhpPGgxE0jmHSHg,10807
|
4
|
-
smarta2a-0.1.0.dist-info/METADATA,sha256=a8EA5KXN0YIwnkpoLSOJMh2gi8Vpn0XLes6lWvlYa0Y,2469
|
5
|
-
smarta2a-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
6
|
-
smarta2a-0.1.0.dist-info/licenses/LICENSE,sha256=ECMEVHuFkvpEmH-_A9HSxs_UnnsUqpCkiAYNHPCf2z0,1078
|
7
|
-
smarta2a-0.1.0.dist-info/RECORD,,
|
{fasta2a → smarta2a}/types.py
RENAMED
File without changes
|
File without changes
|
File without changes
|