smarta2a 0.3.0__py3-none-any.whl → 0.4.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.
- smarta2a/agent/a2a_agent.py +25 -15
- smarta2a/agent/a2a_human.py +56 -0
- smarta2a/archive/smart_mcp_client.py +47 -0
- smarta2a/archive/subscription_service.py +85 -0
- smarta2a/{server → archive}/task_service.py +17 -8
- smarta2a/client/a2a_client.py +35 -8
- smarta2a/client/mcp_client.py +3 -0
- smarta2a/history_update_strategies/rolling_window_strategy.py +16 -0
- smarta2a/model_providers/__init__.py +1 -1
- smarta2a/model_providers/base_llm_provider.py +3 -3
- smarta2a/model_providers/openai_provider.py +126 -89
- smarta2a/nats-server.conf +12 -0
- smarta2a/server/json_rpc_request_processor.py +130 -0
- smarta2a/server/nats_client.py +49 -0
- smarta2a/server/request_handler.py +667 -0
- smarta2a/server/send_task_handler.py +174 -0
- smarta2a/server/server.py +124 -726
- smarta2a/server/state_manager.py +173 -19
- smarta2a/server/webhook_request_processor.py +112 -0
- smarta2a/state_stores/base_state_store.py +3 -3
- smarta2a/state_stores/inmemory_state_store.py +21 -7
- smarta2a/utils/agent_discovery_manager.py +121 -0
- smarta2a/utils/prompt_helpers.py +1 -1
- smarta2a/utils/tools_manager.py +108 -0
- smarta2a/utils/types.py +18 -3
- smarta2a-0.4.0.dist-info/METADATA +402 -0
- smarta2a-0.4.0.dist-info/RECORD +41 -0
- smarta2a-0.4.0.dist-info/licenses/LICENSE +35 -0
- smarta2a/client/tools_manager.py +0 -62
- smarta2a/examples/__init__.py +0 -0
- smarta2a/examples/echo_server/__init__.py +0 -0
- smarta2a/examples/echo_server/curl.txt +0 -1
- smarta2a/examples/echo_server/main.py +0 -39
- smarta2a/examples/openai_delegator_agent/__init__.py +0 -0
- smarta2a/examples/openai_delegator_agent/main.py +0 -41
- smarta2a/examples/openai_weather_agent/__init__.py +0 -0
- smarta2a/examples/openai_weather_agent/main.py +0 -32
- smarta2a/server/subscription_service.py +0 -109
- smarta2a-0.3.0.dist-info/METADATA +0 -103
- smarta2a-0.3.0.dist-info/RECORD +0 -40
- smarta2a-0.3.0.dist-info/licenses/LICENSE +0 -21
- {smarta2a-0.3.0.dist-info → smarta2a-0.4.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,174 @@
|
|
1
|
+
# Library imports
|
2
|
+
from typing import Optional
|
3
|
+
from uuid import uuid4
|
4
|
+
import json
|
5
|
+
from pydantic import ValidationError
|
6
|
+
|
7
|
+
# Local imports
|
8
|
+
from smarta2a.utils.types import (
|
9
|
+
JSONRPCRequest,
|
10
|
+
SendTaskRequest,
|
11
|
+
SendTaskResponse,
|
12
|
+
StateData,
|
13
|
+
Task,
|
14
|
+
TaskStatus,
|
15
|
+
TaskState,
|
16
|
+
Message,
|
17
|
+
JSONRPCError,
|
18
|
+
InvalidRequestError,
|
19
|
+
JSONParseError,
|
20
|
+
InternalError,
|
21
|
+
MethodNotFoundError
|
22
|
+
)
|
23
|
+
|
24
|
+
class SendTaskHandler:
|
25
|
+
|
26
|
+
@classmethod
|
27
|
+
async def _handle_send_task(self, request_data: JSONRPCRequest, state_data: Optional[StateData] = None) -> SendTaskResponse:
|
28
|
+
try:
|
29
|
+
# Validate request format
|
30
|
+
request = SendTaskRequest.model_validate(request_data.model_dump())
|
31
|
+
handler = self.registry.get_handler("tasks/send")
|
32
|
+
|
33
|
+
if not handler:
|
34
|
+
return SendTaskResponse(
|
35
|
+
id=request.id,
|
36
|
+
error=MethodNotFoundError()
|
37
|
+
)
|
38
|
+
|
39
|
+
# Extract parameters from request
|
40
|
+
task_id = request.params.id
|
41
|
+
session_id = request.params.sessionId or str(uuid4())
|
42
|
+
raw = request.params.message
|
43
|
+
user_message = Message.model_validate(raw)
|
44
|
+
request_metadata = request.params.metadata or {}
|
45
|
+
|
46
|
+
if state_data:
|
47
|
+
task_history = state_data.task.history.copy() or []
|
48
|
+
context_history = state_data.context_history.copy() or []
|
49
|
+
metadata = state_data.task.metadata or {}
|
50
|
+
|
51
|
+
# Call handler with state data
|
52
|
+
raw_result = await handler(request, state_data)
|
53
|
+
|
54
|
+
# Handle direct SendTaskResponse returns
|
55
|
+
if isinstance(raw_result, SendTaskResponse):
|
56
|
+
return raw_result
|
57
|
+
|
58
|
+
# Build task with updated history (before agent response)
|
59
|
+
task = self.task_builder.build(
|
60
|
+
content=raw_result,
|
61
|
+
task_id=task_id,
|
62
|
+
session_id=session_id,
|
63
|
+
metadata=metadata,
|
64
|
+
history=task_history
|
65
|
+
)
|
66
|
+
|
67
|
+
# Process messages through strategy
|
68
|
+
messages = []
|
69
|
+
if task.artifacts:
|
70
|
+
agent_parts = [p for a in task.artifacts for p in a.parts]
|
71
|
+
agent_message = Message(
|
72
|
+
role="agent",
|
73
|
+
parts=agent_parts,
|
74
|
+
metadata=task.metadata
|
75
|
+
)
|
76
|
+
messages.append(agent_message)
|
77
|
+
|
78
|
+
# Update Task history with a simple append
|
79
|
+
task_history.extend(messages)
|
80
|
+
|
81
|
+
# Update context history with a strategy - this is the history that will be passed to an LLM call
|
82
|
+
history_strategy = self.state_mgr.get_history_strategy()
|
83
|
+
context_history = history_strategy.update_history(
|
84
|
+
existing_history=context_history,
|
85
|
+
new_messages=messages
|
86
|
+
)
|
87
|
+
|
88
|
+
# Update task with final state
|
89
|
+
task.history = task_history
|
90
|
+
|
91
|
+
# State store update (if enabled)
|
92
|
+
if self.state_mgr:
|
93
|
+
state_store = self.state_mgr.get_store()
|
94
|
+
state_store.update_state(
|
95
|
+
task_id=task_id,
|
96
|
+
state_data=StateData(
|
97
|
+
task_id=task_id,
|
98
|
+
task=task,
|
99
|
+
context_history=context_history,
|
100
|
+
metadata=metadata # Use merged metadata
|
101
|
+
)
|
102
|
+
)
|
103
|
+
|
104
|
+
else:
|
105
|
+
# There is no state manager, so we need to build a task from scratch
|
106
|
+
task = Task(
|
107
|
+
id=task_id,
|
108
|
+
sessionId=session_id,
|
109
|
+
status=TaskStatus(state=TaskState.WORKING),
|
110
|
+
history=[user_message],
|
111
|
+
metadata=request_metadata
|
112
|
+
)
|
113
|
+
task_history = task.history.copy()
|
114
|
+
metadata = request_metadata.copy()
|
115
|
+
|
116
|
+
# Call handler without state data
|
117
|
+
raw_result = await handler(request)
|
118
|
+
|
119
|
+
# Handle direct SendTaskResponse returns
|
120
|
+
if isinstance(raw_result, SendTaskResponse):
|
121
|
+
return raw_result
|
122
|
+
|
123
|
+
# Build task with updated history (before agent response)
|
124
|
+
task = self.task_builder.build(
|
125
|
+
content=raw_result,
|
126
|
+
task_id=task_id,
|
127
|
+
session_id=session_id,
|
128
|
+
metadata=metadata,
|
129
|
+
history=task_history
|
130
|
+
)
|
131
|
+
|
132
|
+
# Process messages through strategy
|
133
|
+
messages = []
|
134
|
+
if task.artifacts:
|
135
|
+
agent_parts = [p for a in task.artifacts for p in a.parts]
|
136
|
+
agent_message = Message(
|
137
|
+
role="agent",
|
138
|
+
parts=agent_parts,
|
139
|
+
metadata=task.metadata
|
140
|
+
)
|
141
|
+
messages.append(agent_message)
|
142
|
+
|
143
|
+
# Update Task history with a simple append
|
144
|
+
task_history.extend(messages)
|
145
|
+
|
146
|
+
# Update task with final state
|
147
|
+
task.history = task_history
|
148
|
+
|
149
|
+
|
150
|
+
return SendTaskResponse(
|
151
|
+
id=request.id,
|
152
|
+
result=task
|
153
|
+
)
|
154
|
+
except ValidationError as e:
|
155
|
+
return SendTaskResponse(
|
156
|
+
id=request_data.id,
|
157
|
+
error=InvalidRequestError(data=e.errors())
|
158
|
+
)
|
159
|
+
except json.JSONDecodeError as e:
|
160
|
+
return SendTaskResponse(
|
161
|
+
id=request_data.id,
|
162
|
+
error=JSONParseError(data=str(e))
|
163
|
+
)
|
164
|
+
except Exception as e:
|
165
|
+
# Handle case where handler returns SendTaskResponse with error
|
166
|
+
if isinstance(e, JSONRPCError):
|
167
|
+
return SendTaskResponse(
|
168
|
+
id=request.id,
|
169
|
+
error=e
|
170
|
+
)
|
171
|
+
return SendTaskResponse(
|
172
|
+
id=request.id,
|
173
|
+
error=InternalError(data=str(e))
|
174
|
+
)
|