jaf-py 2.5.9__py3-none-any.whl → 2.5.11__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.
- jaf/__init__.py +154 -57
- jaf/a2a/__init__.py +42 -21
- jaf/a2a/agent.py +79 -126
- jaf/a2a/agent_card.py +87 -78
- jaf/a2a/client.py +30 -66
- jaf/a2a/examples/client_example.py +12 -12
- jaf/a2a/examples/integration_example.py +38 -47
- jaf/a2a/examples/server_example.py +56 -53
- jaf/a2a/memory/__init__.py +0 -4
- jaf/a2a/memory/cleanup.py +28 -21
- jaf/a2a/memory/factory.py +155 -133
- jaf/a2a/memory/providers/composite.py +21 -26
- jaf/a2a/memory/providers/in_memory.py +89 -83
- jaf/a2a/memory/providers/postgres.py +117 -115
- jaf/a2a/memory/providers/redis.py +128 -121
- jaf/a2a/memory/serialization.py +77 -87
- jaf/a2a/memory/tests/run_comprehensive_tests.py +112 -83
- jaf/a2a/memory/tests/test_cleanup.py +211 -94
- jaf/a2a/memory/tests/test_serialization.py +73 -68
- jaf/a2a/memory/tests/test_stress_concurrency.py +186 -133
- jaf/a2a/memory/tests/test_task_lifecycle.py +138 -120
- jaf/a2a/memory/types.py +91 -53
- jaf/a2a/protocol.py +95 -125
- jaf/a2a/server.py +90 -118
- jaf/a2a/standalone_client.py +30 -43
- jaf/a2a/tests/__init__.py +16 -33
- jaf/a2a/tests/run_tests.py +17 -53
- jaf/a2a/tests/test_agent.py +40 -140
- jaf/a2a/tests/test_client.py +54 -117
- jaf/a2a/tests/test_integration.py +28 -82
- jaf/a2a/tests/test_protocol.py +54 -139
- jaf/a2a/tests/test_types.py +50 -136
- jaf/a2a/types.py +58 -34
- jaf/cli.py +21 -41
- jaf/core/__init__.py +7 -1
- jaf/core/agent_tool.py +93 -72
- jaf/core/analytics.py +257 -207
- jaf/core/checkpoint.py +223 -0
- jaf/core/composition.py +249 -235
- jaf/core/engine.py +817 -519
- jaf/core/errors.py +55 -42
- jaf/core/guardrails.py +276 -202
- jaf/core/handoff.py +47 -31
- jaf/core/parallel_agents.py +69 -75
- jaf/core/performance.py +75 -73
- jaf/core/proxy.py +43 -44
- jaf/core/proxy_helpers.py +24 -27
- jaf/core/regeneration.py +220 -129
- jaf/core/state.py +68 -66
- jaf/core/streaming.py +115 -108
- jaf/core/tool_results.py +111 -101
- jaf/core/tools.py +114 -116
- jaf/core/tracing.py +269 -210
- jaf/core/types.py +371 -151
- jaf/core/workflows.py +209 -168
- jaf/exceptions.py +46 -38
- jaf/memory/__init__.py +1 -6
- jaf/memory/approval_storage.py +54 -77
- jaf/memory/factory.py +4 -4
- jaf/memory/providers/in_memory.py +216 -180
- jaf/memory/providers/postgres.py +216 -146
- jaf/memory/providers/redis.py +173 -116
- jaf/memory/types.py +70 -51
- jaf/memory/utils.py +36 -34
- jaf/plugins/__init__.py +12 -12
- jaf/plugins/base.py +105 -96
- jaf/policies/__init__.py +0 -1
- jaf/policies/handoff.py +37 -46
- jaf/policies/validation.py +76 -52
- jaf/providers/__init__.py +6 -3
- jaf/providers/mcp.py +97 -51
- jaf/providers/model.py +361 -280
- jaf/server/__init__.py +1 -1
- jaf/server/main.py +7 -11
- jaf/server/server.py +514 -359
- jaf/server/types.py +208 -52
- jaf/utils/__init__.py +17 -18
- jaf/utils/attachments.py +111 -116
- jaf/utils/document_processor.py +175 -174
- jaf/visualization/__init__.py +1 -1
- jaf/visualization/example.py +111 -110
- jaf/visualization/functional_core.py +46 -71
- jaf/visualization/graphviz.py +154 -189
- jaf/visualization/imperative_shell.py +7 -16
- jaf/visualization/types.py +8 -4
- {jaf_py-2.5.9.dist-info → jaf_py-2.5.11.dist-info}/METADATA +2 -2
- jaf_py-2.5.11.dist-info/RECORD +97 -0
- jaf_py-2.5.9.dist-info/RECORD +0 -96
- {jaf_py-2.5.9.dist-info → jaf_py-2.5.11.dist-info}/WHEEL +0 -0
- {jaf_py-2.5.9.dist-info → jaf_py-2.5.11.dist-info}/entry_points.txt +0 -0
- {jaf_py-2.5.9.dist-info → jaf_py-2.5.11.dist-info}/licenses/LICENSE +0 -0
- {jaf_py-2.5.9.dist-info → jaf_py-2.5.11.dist-info}/top_level.txt +0 -0
jaf/a2a/tests/test_client.py
CHANGED
|
@@ -44,10 +44,7 @@ class TestClientCreation:
|
|
|
44
44
|
|
|
45
45
|
def test_create_a2a_client_with_config(self):
|
|
46
46
|
"""Test client creation with custom configuration"""
|
|
47
|
-
config = {
|
|
48
|
-
"timeout": 60000,
|
|
49
|
-
"custom_field": "value"
|
|
50
|
-
}
|
|
47
|
+
config = {"timeout": 60000, "custom_field": "value"}
|
|
51
48
|
|
|
52
49
|
client = create_a2a_client("http://example.com/", config)
|
|
53
50
|
|
|
@@ -69,11 +66,7 @@ class TestRequestCreation:
|
|
|
69
66
|
|
|
70
67
|
def test_create_message_request(self):
|
|
71
68
|
"""Test creating message requests"""
|
|
72
|
-
request = create_message_request(
|
|
73
|
-
"Hello, world!",
|
|
74
|
-
"session_123",
|
|
75
|
-
{"model": "gpt-4"}
|
|
76
|
-
)
|
|
69
|
+
request = create_message_request("Hello, world!", "session_123", {"model": "gpt-4"})
|
|
77
70
|
|
|
78
71
|
assert request["jsonrpc"] == "2.0"
|
|
79
72
|
assert request["method"] == "message/send"
|
|
@@ -93,10 +86,7 @@ class TestRequestCreation:
|
|
|
93
86
|
|
|
94
87
|
def test_create_message_request_no_config(self):
|
|
95
88
|
"""Test creating message request without configuration"""
|
|
96
|
-
request = create_message_request(
|
|
97
|
-
"Test message",
|
|
98
|
-
"session_456"
|
|
99
|
-
)
|
|
89
|
+
request = create_message_request("Test message", "session_456")
|
|
100
90
|
|
|
101
91
|
assert request["jsonrpc"] == "2.0"
|
|
102
92
|
assert request["method"] == "message/send"
|
|
@@ -106,9 +96,7 @@ class TestRequestCreation:
|
|
|
106
96
|
def test_create_streaming_message_request(self):
|
|
107
97
|
"""Test creating streaming message requests"""
|
|
108
98
|
request = create_streaming_message_request(
|
|
109
|
-
"Stream this message",
|
|
110
|
-
"session_789",
|
|
111
|
-
{"temperature": 0.8}
|
|
99
|
+
"Stream this message", "session_789", {"temperature": 0.8}
|
|
112
100
|
)
|
|
113
101
|
|
|
114
102
|
assert request["jsonrpc"] == "2.0"
|
|
@@ -128,7 +116,7 @@ class TestHTTPRequests:
|
|
|
128
116
|
"""Test HTTP request functions"""
|
|
129
117
|
|
|
130
118
|
@pytest.mark.asyncio
|
|
131
|
-
@patch(
|
|
119
|
+
@patch("jaf.a2a.client.httpx.AsyncClient")
|
|
132
120
|
async def test_send_http_request_success(self, mock_client_class):
|
|
133
121
|
"""Test successful HTTP request"""
|
|
134
122
|
# Mock response
|
|
@@ -148,20 +136,17 @@ class TestHTTPRequests:
|
|
|
148
136
|
|
|
149
137
|
# Await the mock response if it's a coroutine
|
|
150
138
|
expected_result = {"result": "success"}
|
|
151
|
-
if hasattr(result,
|
|
139
|
+
if hasattr(result, "__await__"):
|
|
152
140
|
result = await result
|
|
153
141
|
assert result == expected_result
|
|
154
142
|
mock_client.post.assert_called_once_with(
|
|
155
143
|
url,
|
|
156
144
|
json=body,
|
|
157
|
-
headers={
|
|
158
|
-
"Content-Type": "application/json",
|
|
159
|
-
"Accept": "application/json"
|
|
160
|
-
}
|
|
145
|
+
headers={"Content-Type": "application/json", "Accept": "application/json"},
|
|
161
146
|
)
|
|
162
147
|
|
|
163
148
|
@pytest.mark.asyncio
|
|
164
|
-
@patch(
|
|
149
|
+
@patch("jaf.a2a.client.httpx.AsyncClient")
|
|
165
150
|
async def test_send_http_request_http_error(self, mock_client_class):
|
|
166
151
|
"""Test HTTP request with error status"""
|
|
167
152
|
# Mock error response
|
|
@@ -181,7 +166,7 @@ class TestHTTPRequests:
|
|
|
181
166
|
assert "HTTP 404: Not Found" in str(exc_info.value)
|
|
182
167
|
|
|
183
168
|
@pytest.mark.asyncio
|
|
184
|
-
@patch(
|
|
169
|
+
@patch("jaf.a2a.client.httpx.AsyncClient")
|
|
185
170
|
async def test_send_http_request_timeout(self, mock_client_class):
|
|
186
171
|
"""Test HTTP request timeout"""
|
|
187
172
|
# Mock client that raises timeout
|
|
@@ -200,17 +185,13 @@ class TestHTTPRequests:
|
|
|
200
185
|
client = create_a2a_client("http://localhost:3000")
|
|
201
186
|
request = {"test": "request"}
|
|
202
187
|
|
|
203
|
-
with patch(
|
|
188
|
+
with patch("jaf.a2a.client.send_http_request") as mock_send:
|
|
204
189
|
mock_send.return_value = {"result": "success"}
|
|
205
190
|
|
|
206
191
|
result = await send_a2a_request(client, request)
|
|
207
192
|
|
|
208
193
|
assert result == {"result": "success"}
|
|
209
|
-
mock_send.assert_called_once_with(
|
|
210
|
-
"http://localhost:3000/a2a",
|
|
211
|
-
request,
|
|
212
|
-
30000
|
|
213
|
-
)
|
|
194
|
+
mock_send.assert_called_once_with("http://localhost:3000/a2a", request, 30000)
|
|
214
195
|
|
|
215
196
|
|
|
216
197
|
class TestMessageSending:
|
|
@@ -227,13 +208,11 @@ class TestMessageSending:
|
|
|
227
208
|
"id": "req_123",
|
|
228
209
|
"result": {
|
|
229
210
|
"kind": "task",
|
|
230
|
-
"artifacts": [{
|
|
231
|
-
|
|
232
|
-
}]
|
|
233
|
-
}
|
|
211
|
+
"artifacts": [{"parts": [{"kind": "text", "text": "Hello back!"}]}],
|
|
212
|
+
},
|
|
234
213
|
}
|
|
235
214
|
|
|
236
|
-
with patch(
|
|
215
|
+
with patch("jaf.a2a.client.send_a2a_request") as mock_send:
|
|
237
216
|
mock_send.return_value = mock_response
|
|
238
217
|
|
|
239
218
|
result = await send_message(client, "Hello!", {"model": "gpt-4"})
|
|
@@ -250,13 +229,10 @@ class TestMessageSending:
|
|
|
250
229
|
mock_response = {
|
|
251
230
|
"jsonrpc": "2.0",
|
|
252
231
|
"id": "req_123",
|
|
253
|
-
"error": {
|
|
254
|
-
"code": -32603,
|
|
255
|
-
"message": "Internal error"
|
|
256
|
-
}
|
|
232
|
+
"error": {"code": -32603, "message": "Internal error"},
|
|
257
233
|
}
|
|
258
234
|
|
|
259
|
-
with patch(
|
|
235
|
+
with patch("jaf.a2a.client.send_a2a_request") as mock_send:
|
|
260
236
|
mock_send.return_value = mock_response
|
|
261
237
|
|
|
262
238
|
with pytest.raises(Exception) as exc_info:
|
|
@@ -269,18 +245,12 @@ class TestMessageSending:
|
|
|
269
245
|
"""Test sending message to specific agent"""
|
|
270
246
|
client = create_a2a_client("http://localhost:3000")
|
|
271
247
|
|
|
272
|
-
mock_response = {
|
|
273
|
-
"jsonrpc": "2.0",
|
|
274
|
-
"id": "req_123",
|
|
275
|
-
"result": "Agent response"
|
|
276
|
-
}
|
|
248
|
+
mock_response = {"jsonrpc": "2.0", "id": "req_123", "result": "Agent response"}
|
|
277
249
|
|
|
278
|
-
with patch(
|
|
250
|
+
with patch("jaf.a2a.client.send_http_request") as mock_send:
|
|
279
251
|
mock_send.return_value = mock_response
|
|
280
252
|
|
|
281
|
-
result = await send_message_to_agent(
|
|
282
|
-
client, "TestAgent", "Hello agent!"
|
|
283
|
-
)
|
|
253
|
+
result = await send_message_to_agent(client, "TestAgent", "Hello agent!")
|
|
284
254
|
|
|
285
255
|
assert result == "Agent response"
|
|
286
256
|
mock_send.assert_called_once()
|
|
@@ -294,7 +264,7 @@ class TestStreaming:
|
|
|
294
264
|
"""Test streaming functionality"""
|
|
295
265
|
|
|
296
266
|
@pytest.mark.asyncio
|
|
297
|
-
@patch(
|
|
267
|
+
@patch("jaf.a2a.client.stream_message")
|
|
298
268
|
async def test_stream_message_success(self, mock_stream_message):
|
|
299
269
|
"""Test successful message streaming"""
|
|
300
270
|
client = create_a2a_client("http://localhost:3000")
|
|
@@ -316,7 +286,7 @@ class TestStreaming:
|
|
|
316
286
|
mock_stream_message.assert_called_once_with(client, "Stream test")
|
|
317
287
|
|
|
318
288
|
@pytest.mark.asyncio
|
|
319
|
-
@patch(
|
|
289
|
+
@patch("jaf.a2a.client.stream_message_to_agent")
|
|
320
290
|
async def test_stream_message_to_agent(self, mock_stream_message_to_agent):
|
|
321
291
|
"""Test streaming message to specific agent"""
|
|
322
292
|
client = create_a2a_client("http://localhost:3000")
|
|
@@ -328,9 +298,7 @@ class TestStreaming:
|
|
|
328
298
|
mock_stream_message_to_agent.side_effect = mock_stream_events
|
|
329
299
|
|
|
330
300
|
events = []
|
|
331
|
-
async for event in mock_stream_message_to_agent(
|
|
332
|
-
client, "TestAgent", "Stream to agent"
|
|
333
|
-
):
|
|
301
|
+
async for event in mock_stream_message_to_agent(client, "TestAgent", "Stream to agent"):
|
|
334
302
|
events.append(event)
|
|
335
303
|
|
|
336
304
|
assert len(events) == 1
|
|
@@ -342,7 +310,7 @@ class TestAgentDiscovery:
|
|
|
342
310
|
"""Test agent discovery functions"""
|
|
343
311
|
|
|
344
312
|
@pytest.mark.asyncio
|
|
345
|
-
@patch(
|
|
313
|
+
@patch("jaf.a2a.client.httpx.AsyncClient")
|
|
346
314
|
async def test_get_agent_card(self, mock_client_class):
|
|
347
315
|
"""Test getting agent card"""
|
|
348
316
|
client = create_a2a_client("http://localhost:3000")
|
|
@@ -351,7 +319,7 @@ class TestAgentDiscovery:
|
|
|
351
319
|
"protocolVersion": "0.3.0",
|
|
352
320
|
"name": "Test Agent",
|
|
353
321
|
"description": "A test agent",
|
|
354
|
-
"skills": []
|
|
322
|
+
"skills": [],
|
|
355
323
|
}
|
|
356
324
|
|
|
357
325
|
# Mock response
|
|
@@ -367,23 +335,19 @@ class TestAgentDiscovery:
|
|
|
367
335
|
result = await get_agent_card(client)
|
|
368
336
|
|
|
369
337
|
# Handle mock coroutine if needed
|
|
370
|
-
if hasattr(result,
|
|
338
|
+
if hasattr(result, "__await__"):
|
|
371
339
|
result = await result
|
|
372
340
|
assert result == mock_agent_card
|
|
373
341
|
mock_client.get.assert_called_once_with(
|
|
374
|
-
"http://localhost:3000/.well-known/agent-card",
|
|
375
|
-
headers={"Accept": "application/json"}
|
|
342
|
+
"http://localhost:3000/.well-known/agent-card", headers={"Accept": "application/json"}
|
|
376
343
|
)
|
|
377
344
|
|
|
378
345
|
@pytest.mark.asyncio
|
|
379
346
|
async def test_discover_agents(self):
|
|
380
347
|
"""Test discover agents convenience function"""
|
|
381
|
-
mock_agent_card = {
|
|
382
|
-
"name": "Test Server",
|
|
383
|
-
"skills": [{"name": "skill1"}]
|
|
384
|
-
}
|
|
348
|
+
mock_agent_card = {"name": "Test Server", "skills": [{"name": "skill1"}]}
|
|
385
349
|
|
|
386
|
-
with patch(
|
|
350
|
+
with patch("jaf.a2a.client.get_agent_card") as mock_get_card:
|
|
387
351
|
mock_get_card.return_value = mock_agent_card
|
|
388
352
|
|
|
389
353
|
result = await discover_agents("http://localhost:3000")
|
|
@@ -396,16 +360,12 @@ class TestHealthAndCapabilities:
|
|
|
396
360
|
"""Test health and capabilities functions"""
|
|
397
361
|
|
|
398
362
|
@pytest.mark.asyncio
|
|
399
|
-
@patch(
|
|
363
|
+
@patch("jaf.a2a.client.httpx.AsyncClient")
|
|
400
364
|
async def test_check_a2a_health(self, mock_client_class):
|
|
401
365
|
"""Test health check"""
|
|
402
366
|
client = create_a2a_client("http://localhost:3000")
|
|
403
367
|
|
|
404
|
-
mock_health = {
|
|
405
|
-
"status": "healthy",
|
|
406
|
-
"protocol": "A2A",
|
|
407
|
-
"version": "0.3.0"
|
|
408
|
-
}
|
|
368
|
+
mock_health = {"status": "healthy", "protocol": "A2A", "version": "0.3.0"}
|
|
409
369
|
|
|
410
370
|
# Mock response
|
|
411
371
|
mock_response = AsyncMock()
|
|
@@ -420,23 +380,22 @@ class TestHealthAndCapabilities:
|
|
|
420
380
|
result = await check_a2a_health(client)
|
|
421
381
|
|
|
422
382
|
# Handle mock coroutine if needed
|
|
423
|
-
if hasattr(result,
|
|
383
|
+
if hasattr(result, "__await__"):
|
|
424
384
|
result = await result
|
|
425
385
|
assert result == mock_health
|
|
426
386
|
mock_client.get.assert_called_once_with(
|
|
427
|
-
"http://localhost:3000/a2a/health",
|
|
428
|
-
headers={"Accept": "application/json"}
|
|
387
|
+
"http://localhost:3000/a2a/health", headers={"Accept": "application/json"}
|
|
429
388
|
)
|
|
430
389
|
|
|
431
390
|
@pytest.mark.asyncio
|
|
432
|
-
@patch(
|
|
391
|
+
@patch("jaf.a2a.client.httpx.AsyncClient")
|
|
433
392
|
async def test_get_a2a_capabilities(self, mock_client_class):
|
|
434
393
|
"""Test getting capabilities"""
|
|
435
394
|
client = create_a2a_client("http://localhost:3000")
|
|
436
395
|
|
|
437
396
|
mock_capabilities = {
|
|
438
397
|
"supportedMethods": ["message/send", "message/stream"],
|
|
439
|
-
"supportedTransports": ["JSONRPC"]
|
|
398
|
+
"supportedTransports": ["JSONRPC"],
|
|
440
399
|
}
|
|
441
400
|
|
|
442
401
|
# Mock response
|
|
@@ -452,12 +411,11 @@ class TestHealthAndCapabilities:
|
|
|
452
411
|
result = await get_a2a_capabilities(client)
|
|
453
412
|
|
|
454
413
|
# Handle mock coroutine if needed
|
|
455
|
-
if hasattr(result,
|
|
414
|
+
if hasattr(result, "__await__"):
|
|
456
415
|
result = await result
|
|
457
416
|
assert result == mock_capabilities
|
|
458
417
|
mock_client.get.assert_called_once_with(
|
|
459
|
-
"http://localhost:3000/a2a/capabilities",
|
|
460
|
-
headers={"Accept": "application/json"}
|
|
418
|
+
"http://localhost:3000/a2a/capabilities", headers={"Accept": "application/json"}
|
|
461
419
|
)
|
|
462
420
|
|
|
463
421
|
|
|
@@ -473,20 +431,16 @@ class TestResponseProcessing:
|
|
|
473
431
|
"""Test extracting text from task response"""
|
|
474
432
|
task_response = {
|
|
475
433
|
"kind": "task",
|
|
476
|
-
"artifacts": [
|
|
477
|
-
"parts": [
|
|
478
|
-
{"kind": "text", "text": "First text part"},
|
|
479
|
-
{"kind": "data", "data": {"key": "value"}},
|
|
480
|
-
{"kind": "text", "text": "Second text part"}
|
|
481
|
-
]
|
|
482
|
-
}],
|
|
483
|
-
"history": [
|
|
434
|
+
"artifacts": [
|
|
484
435
|
{
|
|
485
436
|
"parts": [
|
|
486
|
-
{"kind": "text", "text": "
|
|
437
|
+
{"kind": "text", "text": "First text part"},
|
|
438
|
+
{"kind": "data", "data": {"key": "value"}},
|
|
439
|
+
{"kind": "text", "text": "Second text part"},
|
|
487
440
|
]
|
|
488
441
|
}
|
|
489
|
-
]
|
|
442
|
+
],
|
|
443
|
+
"history": [{"parts": [{"kind": "text", "text": "History message"}]}],
|
|
490
444
|
}
|
|
491
445
|
|
|
492
446
|
result = extract_text_response(task_response)
|
|
@@ -501,10 +455,10 @@ class TestResponseProcessing:
|
|
|
501
455
|
{
|
|
502
456
|
"parts": [
|
|
503
457
|
{"kind": "text", "text": "History text 1"},
|
|
504
|
-
{"kind": "text", "text": "History text 2"}
|
|
458
|
+
{"kind": "text", "text": "History text 2"},
|
|
505
459
|
]
|
|
506
460
|
}
|
|
507
|
-
]
|
|
461
|
+
],
|
|
508
462
|
}
|
|
509
463
|
|
|
510
464
|
result = extract_text_response(task_response)
|
|
@@ -516,8 +470,8 @@ class TestResponseProcessing:
|
|
|
516
470
|
"kind": "message",
|
|
517
471
|
"parts": [
|
|
518
472
|
{"kind": "text", "text": "Message part 1"},
|
|
519
|
-
{"kind": "text", "text": "Message part 2"}
|
|
520
|
-
]
|
|
473
|
+
{"kind": "text", "text": "Message part 2"},
|
|
474
|
+
],
|
|
521
475
|
}
|
|
522
476
|
|
|
523
477
|
result = extract_text_response(message_response)
|
|
@@ -546,11 +500,7 @@ class TestUtilityFunctions:
|
|
|
546
500
|
|
|
547
501
|
def test_create_a2a_message_dict(self):
|
|
548
502
|
"""Test creating A2A message dictionary"""
|
|
549
|
-
message = create_a2a_message_dict(
|
|
550
|
-
"Hello world",
|
|
551
|
-
"agent",
|
|
552
|
-
"ctx_123"
|
|
553
|
-
)
|
|
503
|
+
message = create_a2a_message_dict("Hello world", "agent", "ctx_123")
|
|
554
504
|
|
|
555
505
|
assert message["role"] == "agent"
|
|
556
506
|
assert message["parts"][0]["kind"] == "text"
|
|
@@ -589,11 +539,7 @@ class TestUtilityFunctions:
|
|
|
589
539
|
|
|
590
540
|
def test_validate_a2a_response_valid(self):
|
|
591
541
|
"""Test validating valid A2A responses"""
|
|
592
|
-
valid_response = {
|
|
593
|
-
"jsonrpc": "2.0",
|
|
594
|
-
"id": "req_123",
|
|
595
|
-
"result": {"data": "success"}
|
|
596
|
-
}
|
|
542
|
+
valid_response = {"jsonrpc": "2.0", "id": "req_123", "result": {"data": "success"}}
|
|
597
543
|
|
|
598
544
|
assert validate_a2a_response(valid_response) is True
|
|
599
545
|
|
|
@@ -601,7 +547,7 @@ class TestUtilityFunctions:
|
|
|
601
547
|
valid_error = {
|
|
602
548
|
"jsonrpc": "2.0",
|
|
603
549
|
"id": "req_123",
|
|
604
|
-
"error": {"code": -32603, "message": "Error"}
|
|
550
|
+
"error": {"code": -32603, "message": "Error"},
|
|
605
551
|
}
|
|
606
552
|
|
|
607
553
|
assert validate_a2a_response(valid_error) is True
|
|
@@ -612,19 +558,13 @@ class TestUtilityFunctions:
|
|
|
612
558
|
assert validate_a2a_response({"id": "req_123", "result": {}}) is False
|
|
613
559
|
|
|
614
560
|
# Wrong jsonrpc version
|
|
615
|
-
assert validate_a2a_response({
|
|
616
|
-
"jsonrpc": "1.0", "id": "req_123", "result": {}
|
|
617
|
-
}) is False
|
|
561
|
+
assert validate_a2a_response({"jsonrpc": "1.0", "id": "req_123", "result": {}}) is False
|
|
618
562
|
|
|
619
563
|
# Missing id
|
|
620
|
-
assert validate_a2a_response({
|
|
621
|
-
"jsonrpc": "2.0", "result": {}
|
|
622
|
-
}) is False
|
|
564
|
+
assert validate_a2a_response({"jsonrpc": "2.0", "result": {}}) is False
|
|
623
565
|
|
|
624
566
|
# Missing both result and error
|
|
625
|
-
assert validate_a2a_response({
|
|
626
|
-
"jsonrpc": "2.0", "id": "req_123"
|
|
627
|
-
}) is False
|
|
567
|
+
assert validate_a2a_response({"jsonrpc": "2.0", "id": "req_123"}) is False
|
|
628
568
|
|
|
629
569
|
# Not a dict
|
|
630
570
|
assert validate_a2a_response("not a dict") is False
|
|
@@ -636,12 +576,9 @@ class TestConvenienceConnection:
|
|
|
636
576
|
@pytest.mark.asyncio
|
|
637
577
|
async def test_connect_to_a2a_agent(self):
|
|
638
578
|
"""Test convenience connection to A2A agent"""
|
|
639
|
-
mock_agent_card = {
|
|
640
|
-
"name": "Test Agent",
|
|
641
|
-
"description": "Test description"
|
|
642
|
-
}
|
|
579
|
+
mock_agent_card = {"name": "Test Agent", "description": "Test description"}
|
|
643
580
|
|
|
644
|
-
with patch(
|
|
581
|
+
with patch("jaf.a2a.client.get_agent_card") as mock_get_card:
|
|
645
582
|
mock_get_card.return_value = mock_agent_card
|
|
646
583
|
|
|
647
584
|
connection = await connect_to_a2a_agent("http://localhost:3000")
|