smarta2a 0.4.17__py3-none-any.whl → 0.4.19__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.
- smarta2a/client/a2a_client.py +0 -21
- smarta2a/model_providers/openai_provider.py +3 -1
- smarta2a/server/nats_client.py +1 -4
- smarta2a/server/request_handler.py +2 -7
- smarta2a/server/server.py +0 -2
- smarta2a/server/state_manager.py +13 -6
- smarta2a/server/webhook_request_processor.py +9 -38
- smarta2a/utils/tools_manager.py +1 -14
- {smarta2a-0.4.17.dist-info → smarta2a-0.4.19.dist-info}/METADATA +1 -1
- {smarta2a-0.4.17.dist-info → smarta2a-0.4.19.dist-info}/RECORD +12 -12
- {smarta2a-0.4.17.dist-info → smarta2a-0.4.19.dist-info}/WHEEL +0 -0
- {smarta2a-0.4.17.dist-info → smarta2a-0.4.19.dist-info}/licenses/LICENSE +0 -0
smarta2a/client/a2a_client.py
CHANGED
@@ -54,15 +54,6 @@ class A2AClient:
|
|
54
54
|
metadata: dict[str, Any] | None = None,
|
55
55
|
):
|
56
56
|
"""Send a task to another Agent."""
|
57
|
-
|
58
|
-
# Auto-create PushNotificationConfig if not provided and we have a URL
|
59
|
-
if push_notification is None and self.url:
|
60
|
-
push_notification = PushNotificationConfig(
|
61
|
-
url=f"{self.url}/webhook",
|
62
|
-
token=None,
|
63
|
-
authentication=None
|
64
|
-
)
|
65
|
-
|
66
57
|
params = TaskRequestBuilder.build_send_task_request(
|
67
58
|
id=id,
|
68
59
|
role=role,
|
@@ -93,15 +84,6 @@ class A2AClient:
|
|
93
84
|
metadata: dict[str, Any] | None = None,
|
94
85
|
):
|
95
86
|
"""Send to another Agent and receive a stream of responses."""
|
96
|
-
|
97
|
-
# Auto-create PushNotificationConfig if not provided and we have a URL
|
98
|
-
if push_notification is None and self.url:
|
99
|
-
push_notification = PushNotificationConfig(
|
100
|
-
url=f"{self.url}/webhook",
|
101
|
-
token=None,
|
102
|
-
authentication=None
|
103
|
-
)
|
104
|
-
|
105
87
|
params = TaskRequestBuilder.build_send_task_request(
|
106
88
|
id=id,
|
107
89
|
role=role,
|
@@ -207,9 +189,6 @@ class A2AClient:
|
|
207
189
|
webhook_url, json=request.model_dump(), timeout=30
|
208
190
|
)
|
209
191
|
response.raise_for_status()
|
210
|
-
print("--- response from webhook ---")
|
211
|
-
print(response.json())
|
212
|
-
print("--- end of response from webhook ---")
|
213
192
|
return response.json()
|
214
193
|
except httpx.HTTPStatusError as e:
|
215
194
|
raise A2AClientHTTPError(e.response.status_code, str(e)) from e
|
@@ -193,10 +193,12 @@ class OpenAIProvider(BaseLLMProvider):
|
|
193
193
|
|
194
194
|
# Call the actual tool
|
195
195
|
try:
|
196
|
+
|
196
197
|
override_args = {
|
197
198
|
'id': state.task_id,
|
198
199
|
'sessionId': state.task.sessionId,
|
199
|
-
'metadata': state.task.metadata
|
200
|
+
'metadata': state.task.metadata,
|
201
|
+
'push_notification': state.push_notification_config
|
200
202
|
}
|
201
203
|
|
202
204
|
tool_result = await self.tools_manager.call_tool(fn_name, fn_args, override_args)
|
smarta2a/server/nats_client.py
CHANGED
@@ -19,10 +19,8 @@ class NATSClient:
|
|
19
19
|
# Use the current running loop by default
|
20
20
|
await self.nats.connect(self.server_url)
|
21
21
|
self._connected = True
|
22
|
-
print(f"Connected to NATS at {self.server_url}")
|
23
22
|
except Exception as e:
|
24
|
-
|
25
|
-
raise
|
23
|
+
pass
|
26
24
|
|
27
25
|
async def publish(self, subject: str, payload: Dict[str, Any]) -> None:
|
28
26
|
"""Publishes a JSON-encoded message to a NATS subject, auto-connecting if needed."""
|
@@ -42,7 +40,6 @@ class NATSClient:
|
|
42
40
|
if self._connected:
|
43
41
|
await self.nats.close()
|
44
42
|
self._connected = False
|
45
|
-
print("NATS connection closed")
|
46
43
|
|
47
44
|
@property
|
48
45
|
def is_connected(self) -> bool:
|
@@ -157,13 +157,9 @@ class RequestHandler:
|
|
157
157
|
# If push_notification_config is set send the task to the push notification url
|
158
158
|
if push_notification_config and forward_to_webhook:
|
159
159
|
try:
|
160
|
-
print("call to send_to_webhook")
|
161
|
-
print(push_notification_config.url)
|
162
|
-
print(task.model_dump())
|
163
|
-
print("--- end ---")
|
164
160
|
self.a2a_aclient.send_to_webhook(webhook_url=push_notification_config.url,id=task_id,task=task.model_dump())
|
165
161
|
except Exception as e:
|
166
|
-
|
162
|
+
pass
|
167
163
|
|
168
164
|
|
169
165
|
# Send the task back to the client
|
@@ -296,13 +292,12 @@ class RequestHandler:
|
|
296
292
|
context_stream_history = new_context_history
|
297
293
|
stream_metadata = new_metadata
|
298
294
|
|
299
|
-
# TODO: If push_notification_config is set, send the task to the push notification url
|
300
295
|
# If push_notification_config is set send the task to the push notification url
|
301
296
|
if push_notification_config and forward_to_webhook:
|
302
297
|
try:
|
303
298
|
self.a2a_aclient.send_to_webhook(webhook_url=push_notification_config.url,id=task_id,task=task)
|
304
299
|
except Exception as e:
|
305
|
-
|
300
|
+
pass
|
306
301
|
|
307
302
|
|
308
303
|
elif isinstance(item, TaskStatusUpdateEvent):
|
smarta2a/server/server.py
CHANGED
@@ -37,7 +37,6 @@ class SmartA2A:
|
|
37
37
|
name: str,
|
38
38
|
agent_card: Optional[AgentCard] = None,
|
39
39
|
state_manager: Optional[StateManager] = None,
|
40
|
-
has_frontend: bool = False,
|
41
40
|
**fastapi_kwargs
|
42
41
|
):
|
43
42
|
self.name = name
|
@@ -46,7 +45,6 @@ class SmartA2A:
|
|
46
45
|
self.state_mgr = state_manager
|
47
46
|
self.app = FastAPI(title=name, **fastapi_kwargs)
|
48
47
|
self.router = APIRouter()
|
49
|
-
self.has_frontend = has_frontend
|
50
48
|
self._setup_cors()
|
51
49
|
self._setup_routes()
|
52
50
|
self.server_config = {
|
smarta2a/server/state_manager.py
CHANGED
@@ -10,11 +10,12 @@ from smarta2a.utils.types import Message, StateData, Task, TaskStatus, TaskState
|
|
10
10
|
from smarta2a.server.nats_client import NATSClient
|
11
11
|
|
12
12
|
class StateManager:
|
13
|
-
def __init__(self, state_store: BaseStateStore, file_store: BaseFileStore, history_strategy: HistoryUpdateStrategy, nats_server_url: Optional[str] = "nats://localhost:4222"):
|
13
|
+
def __init__(self, state_store: BaseStateStore, file_store: BaseFileStore, history_strategy: HistoryUpdateStrategy, nats_server_url: Optional[str] = "nats://localhost:4222", push_notification_config: Optional[PushNotificationConfig] = None):
|
14
14
|
self.state_store = state_store
|
15
15
|
self.file_store = file_store
|
16
16
|
self.strategy = history_strategy
|
17
17
|
self.nats_client = NATSClient(server_url=nats_server_url)
|
18
|
+
self.push_notification_config = push_notification_config
|
18
19
|
|
19
20
|
async def load(self):
|
20
21
|
await self.nats_client.connect()
|
@@ -40,11 +41,15 @@ class StateManager:
|
|
40
41
|
history=[],
|
41
42
|
metadata={}
|
42
43
|
)
|
44
|
+
|
45
|
+
# Use self.push_notification_config if push_notification_config is None
|
46
|
+
notification_config = push_notification_config if push_notification_config is not None else self.push_notification_config
|
47
|
+
|
43
48
|
state = StateData(
|
44
49
|
task_id=task_id,
|
45
50
|
task=initial_task,
|
46
51
|
context_history=[],
|
47
|
-
push_notification_config=
|
52
|
+
push_notification_config=notification_config
|
48
53
|
)
|
49
54
|
self.state_store.initialize_state(state)
|
50
55
|
return state
|
@@ -82,7 +87,7 @@ class StateManager:
|
|
82
87
|
|
83
88
|
return latest_state
|
84
89
|
|
85
|
-
def get_and_update_state_from_webhook(self, task_id: str, result: Task) -> StateData:
|
90
|
+
async def get_and_update_state_from_webhook(self, task_id: str, result: Task) -> StateData:
|
86
91
|
"""
|
87
92
|
Update existing state with webhook result data, including:
|
88
93
|
- Merges task history from result
|
@@ -141,6 +146,11 @@ class StateManager:
|
|
141
146
|
# Update task status if provided
|
142
147
|
if result.status:
|
143
148
|
updated_state.task.status = result.status
|
149
|
+
|
150
|
+
# Process files before persistence
|
151
|
+
await self._process_file_parts(updated_state)
|
152
|
+
|
153
|
+
await self.update_state(updated_state)
|
144
154
|
|
145
155
|
return updated_state
|
146
156
|
|
@@ -152,9 +162,6 @@ class StateManager:
|
|
152
162
|
|
153
163
|
# Publish update through NATS client
|
154
164
|
payload = self._prepare_update_payload(state_data)
|
155
|
-
print("--- NATS payload ---")
|
156
|
-
print(payload)
|
157
|
-
print("--- NATS payload end ---")
|
158
165
|
await self.nats_client.publish("state.updates", payload)
|
159
166
|
|
160
167
|
def get_store(self) -> Optional[BaseStateStore]:
|
@@ -15,9 +15,6 @@ class WebhookRequestProcessor:
|
|
15
15
|
async def process_request(self, request: WebhookRequest) -> WebhookResponse:
|
16
16
|
if self.state_manager:
|
17
17
|
state_data = self.state_manager.get_and_update_state_from_webhook(request.id, request.result)
|
18
|
-
print("--- state_data in webhook_request_processor.py ---")
|
19
|
-
print(state_data)
|
20
|
-
print("--- end of state_data in webhook_request_processor.py ---")
|
21
18
|
return await self._handle_webhook(request, state_data)
|
22
19
|
else:
|
23
20
|
return await self._handle_webhook(request)
|
@@ -37,29 +34,6 @@ class WebhookRequestProcessor:
|
|
37
34
|
context_history=[],
|
38
35
|
push_notification_config=None
|
39
36
|
)
|
40
|
-
else:
|
41
|
-
existing_task = state_data.task
|
42
|
-
|
43
|
-
# Overwrite artifacts
|
44
|
-
existing_task.artifacts = incoming_task.artifacts.copy() if incoming_task.artifacts else []
|
45
|
-
|
46
|
-
# Merge metadata
|
47
|
-
existing_task.metadata = {**(existing_task.metadata or {}), **(incoming_task.metadata or {})}
|
48
|
-
|
49
|
-
# Build messages from artifact parts (role="agent" as in handle_send_task)
|
50
|
-
all_parts = [part for artifact in incoming_task.artifacts for part in artifact.parts] if incoming_task.artifacts else []
|
51
|
-
new_messages = [Message(role="agent", parts=all_parts, metadata=incoming_task.metadata)]
|
52
|
-
|
53
|
-
# Update context history using strategy
|
54
|
-
history_strategy = self.state_manager.get_history_strategy()
|
55
|
-
state_data.context_history = history_strategy.update_history(
|
56
|
-
existing_history=state_data.context_history,
|
57
|
-
new_messages=new_messages
|
58
|
-
)
|
59
|
-
|
60
|
-
# Persist state
|
61
|
-
print("call to update state - before webhook function")
|
62
|
-
await self.state_manager.update_state(state_data)
|
63
37
|
|
64
38
|
# --- Step 2: Call Webhook Function ---
|
65
39
|
webhook_response = await self.webhook_fn(request, state_data) if state_data else await self.webhook_fn(request)
|
@@ -80,20 +54,17 @@ class WebhookRequestProcessor:
|
|
80
54
|
updated_messages = [Message(role="agent", parts=updated_parts, metadata=updated_task.metadata)]
|
81
55
|
|
82
56
|
# Update context history again
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
57
|
+
if self.state_manager:
|
58
|
+
history_strategy = self.state_manager.get_history_strategy()
|
59
|
+
state_data.context_history = history_strategy.update_history(
|
60
|
+
existing_history=state_data.context_history,
|
61
|
+
new_messages=updated_messages
|
62
|
+
)
|
63
|
+
await self.state_manager.update_state(state_data)
|
90
64
|
|
91
65
|
# --- Step 4: Push Notification ---
|
92
|
-
push_url =
|
93
|
-
|
94
|
-
if state_data and state_data.push_notification_config
|
95
|
-
else None
|
96
|
-
)
|
66
|
+
push_url = state_data.push_notification_config.url if state_data and state_data.push_notification_config else None
|
67
|
+
|
97
68
|
if push_url:
|
98
69
|
try:
|
99
70
|
self.a2a_aclient.send_to_webhook(
|
smarta2a/utils/tools_manager.py
CHANGED
@@ -91,25 +91,12 @@ class ToolsManager:
|
|
91
91
|
client = self.get_client(tool_key)
|
92
92
|
tool_name = self._get_tool_name(tool_key)
|
93
93
|
new_args = self._replace_with_override_args(args, override_args)
|
94
|
-
print("--- new_args ---")
|
95
|
-
print(new_args)
|
96
|
-
print("--- end of new_args ---")
|
97
|
-
print("--- tool_name ---")
|
98
|
-
print(tool_name)
|
99
|
-
print("--- end of tool_name ---")
|
100
94
|
result = await client.call_tool(tool_name, new_args)
|
101
|
-
|
102
|
-
print(result)
|
103
|
-
print("--- end of result ---")
|
95
|
+
|
104
96
|
return result
|
105
97
|
|
106
98
|
except Exception as e:
|
107
99
|
# This will catch ANY error in the body above
|
108
|
-
print("--- EXCEPTION CAUGHT ---")
|
109
|
-
print(f"Error Type: {type(e).__name__}")
|
110
|
-
print(f"Error Message: {str(e)}")
|
111
|
-
print("--- END OF EXCEPTION DETAILS ---")
|
112
|
-
|
113
100
|
raise
|
114
101
|
|
115
102
|
def _get_tool_name(self, tool_key: str) -> str:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: smarta2a
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.19
|
4
4
|
Summary: a Python framework that helps you build servers and AI agents that communicate using the A2A protocol
|
5
5
|
Project-URL: Homepage, https://github.com/siddharthsma/smarta2a
|
6
6
|
Project-URL: Bug Tracker, https://github.com/siddharthsma/smarta2a/issues
|
@@ -6,7 +6,7 @@ smarta2a/archive/smart_mcp_client.py,sha256=0s2OWFKWSv-_UF7rb9fOrsh1OIYsYOsGukkX
|
|
6
6
|
smarta2a/archive/subscription_service.py,sha256=vftmZD94HbdjPFa_1UBvsBm-WkW-s3ZCVq60fF7OCgA,4109
|
7
7
|
smarta2a/archive/task_service.py,sha256=ptf-oMHy98Rw4XSxyK1-lpqc1JtkCkEEHTmwAaunet4,8199
|
8
8
|
smarta2a/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
-
smarta2a/client/a2a_client.py,sha256=
|
9
|
+
smarta2a/client/a2a_client.py,sha256=apDkKFtq61T79LpkbkzVTKWA0mSjR_eTNdGPUYozyvk,12100
|
10
10
|
smarta2a/client/mcp_client.py,sha256=JeXhBqxM9TYAArpExLRtEr3lZeQZMcnTmGFl6XKsdu8,3797
|
11
11
|
smarta2a/file_stores/base_file_store.py,sha256=fcwFIOoFjLQiIKb8lIRVujnV6udyuI9Dq8cEc2ldmIQ,591
|
12
12
|
smarta2a/file_stores/local_file_store.py,sha256=4GLDrsKxSoLWn2Oha4OD-P2r5vBpfV-8ePvZ5bhP1e8,2616
|
@@ -16,16 +16,16 @@ smarta2a/history_update_strategies/history_update_strategy.py,sha256=n2sfIGu8ztK
|
|
16
16
|
smarta2a/history_update_strategies/rolling_window_strategy.py,sha256=7Ch042JWt4TM_r1-sFKlSIxHj8VX1P3ZoqjCvIdeSqA,540
|
17
17
|
smarta2a/model_providers/__init__.py,sha256=hJj0w00JjqTiBgJmHmOWwL6MU_hwmro9xTiX3XYf6ts,148
|
18
18
|
smarta2a/model_providers/base_llm_provider.py,sha256=iQUqjnypl0f2M929iU0WhHoxAE4ek-NUFJPbEnNQ8-4,412
|
19
|
-
smarta2a/model_providers/openai_provider.py,sha256=
|
19
|
+
smarta2a/model_providers/openai_provider.py,sha256=cqAAhoImHJtBVOGeIERphXqiNlq6MSe_p3-3gImhAeM,12221
|
20
20
|
smarta2a/server/__init__.py,sha256=f2X454Ll4vJc02V4JLJHTN-h8u0TBm4d_FkiO4t686U,53
|
21
21
|
smarta2a/server/handler_registry.py,sha256=OVRG5dTvxB7qUNXgsqWxVNxIyRljUShSYxb1gtbi5XM,820
|
22
22
|
smarta2a/server/json_rpc_request_processor.py,sha256=qRB3sfj_n9ImkIOCdaUKMsDmKcO7CiMhaZ4VdQS7Mb4,6993
|
23
|
-
smarta2a/server/nats_client.py,sha256=
|
24
|
-
smarta2a/server/request_handler.py,sha256=
|
23
|
+
smarta2a/server/nats_client.py,sha256=K97e8awvAxsqgs3BxsTZU_mB3JPPZ0yjLX1LnZZjfXE,1450
|
24
|
+
smarta2a/server/request_handler.py,sha256=IuKY9L3WYt-G5u55Qz2eq2OORb2bSb140HGIGGvHxQI,26178
|
25
25
|
smarta2a/server/send_task_handler.py,sha256=fiBeCCHCu9c2H4EJOUc0t3EZgpHVFJy4B_6qZOC140s,6336
|
26
|
-
smarta2a/server/server.py,sha256=
|
27
|
-
smarta2a/server/state_manager.py,sha256=
|
28
|
-
smarta2a/server/webhook_request_processor.py,sha256=
|
26
|
+
smarta2a/server/server.py,sha256=E58tvOjAvHf_gYjST76sPEC5piaNyrHePa9k-fSadZA,6797
|
27
|
+
smarta2a/server/state_manager.py,sha256=jFxf9cDxLqjIo87tv_Ynh2dH1vCTFLrVSLPuVg6YWnA,8063
|
28
|
+
smarta2a/server/webhook_request_processor.py,sha256=eD8APJ6tgb72TMxXCviQG4p77mfSPK6Iob7wiV7JpQU,4077
|
29
29
|
smarta2a/state_stores/__init__.py,sha256=vafxAqpwvag_cYFH2XKGk3DPmJIWJr4Ioey30yLFkVQ,220
|
30
30
|
smarta2a/state_stores/base_state_store.py,sha256=_3LInM-qepKwwdypJTDNs9-DozBNrKVycwPwUm7bYdU,512
|
31
31
|
smarta2a/state_stores/inmemory_state_store.py,sha256=nEBBUiiqhEluP2MYJjFUImcjIwLJEvL8BWwMbLCb8Fw,1268
|
@@ -34,9 +34,9 @@ smarta2a/utils/agent_discovery_manager.py,sha256=6KpRSQH_EDUOZbF4wFRsZneZGIPLXFP
|
|
34
34
|
smarta2a/utils/prompt_helpers.py,sha256=M3UUjFQEspEAnNm54Dip0-D7mMFFZLrP_s_89ZPe6fs,1438
|
35
35
|
smarta2a/utils/task_builder.py,sha256=wqSyfVHNTaXuGESu09dhlaDi7D007gcN3-8tH-nPQ40,5159
|
36
36
|
smarta2a/utils/task_request_builder.py,sha256=6cOGOqj2Rg43xWM03GRJQzlIZHBptsMCJRp7oD-TDAQ,3362
|
37
|
-
smarta2a/utils/tools_manager.py,sha256=
|
37
|
+
smarta2a/utils/tools_manager.py,sha256=oR5cbwzPZ36hQAsWAgb-c6wFv5BthmCPraD7DSv-Bv8,4332
|
38
38
|
smarta2a/utils/types.py,sha256=kzA6Vv5xXfu1sJuxhEXrglI9e9S6eZVIljMnsrQVyN0,13650
|
39
|
-
smarta2a-0.4.
|
40
|
-
smarta2a-0.4.
|
41
|
-
smarta2a-0.4.
|
42
|
-
smarta2a-0.4.
|
39
|
+
smarta2a-0.4.19.dist-info/METADATA,sha256=JZr1tVu5pJsSzm6nUoQvTTU6IwN6ydTSZlVov-Mz38o,13051
|
40
|
+
smarta2a-0.4.19.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
41
|
+
smarta2a-0.4.19.dist-info/licenses/LICENSE,sha256=lDbqrxVnzDMY5KJ8JS1WhvkWE8TJaw-O-CHDy-ecsJA,2095
|
42
|
+
smarta2a-0.4.19.dist-info/RECORD,,
|
File without changes
|
File without changes
|