jaf-py 2.5.10__py3-none-any.whl → 2.5.12__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 +310 -210
- jaf/core/types.py +403 -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 +475 -283
- 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.10.dist-info → jaf_py-2.5.12.dist-info}/METADATA +2 -2
- jaf_py-2.5.12.dist-info/RECORD +97 -0
- jaf_py-2.5.10.dist-info/RECORD +0 -96
- {jaf_py-2.5.10.dist-info → jaf_py-2.5.12.dist-info}/WHEEL +0 -0
- {jaf_py-2.5.10.dist-info → jaf_py-2.5.12.dist-info}/entry_points.txt +0 -0
- {jaf_py-2.5.10.dist-info → jaf_py-2.5.12.dist-info}/licenses/LICENSE +0 -0
- {jaf_py-2.5.10.dist-info → jaf_py-2.5.12.dist-info}/top_level.txt +0 -0
|
@@ -39,22 +39,18 @@ class InMemoryTaskState:
|
|
|
39
39
|
self.config = config
|
|
40
40
|
self.tasks: Dict[str, A2ATaskStorage] = {}
|
|
41
41
|
self.context_index: Dict[str, Set[str]] = defaultdict(set) # contextId -> Set[taskId]
|
|
42
|
-
self.state_index: Dict[str, Set[str]] = defaultdict(set)
|
|
43
|
-
self.stats = {
|
|
44
|
-
'total_tasks': 0,
|
|
45
|
-
'created_at': datetime.now()
|
|
46
|
-
}
|
|
42
|
+
self.state_index: Dict[str, Set[str]] = defaultdict(set) # state -> Set[taskId]
|
|
43
|
+
self.stats = {"total_tasks": 0, "created_at": datetime.now()}
|
|
47
44
|
self.lock = asyncio.Lock()
|
|
48
45
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
) -> A2ATaskProvider:
|
|
46
|
+
|
|
47
|
+
def create_a2a_in_memory_task_provider(config: A2AInMemoryTaskConfig) -> A2ATaskProvider:
|
|
52
48
|
"""
|
|
53
49
|
Create an in-memory A2A task provider
|
|
54
|
-
|
|
50
|
+
|
|
55
51
|
Args:
|
|
56
52
|
config: Configuration for the in-memory provider
|
|
57
|
-
|
|
53
|
+
|
|
58
54
|
Returns:
|
|
59
55
|
A2ATaskProvider implementation
|
|
60
56
|
"""
|
|
@@ -64,13 +60,18 @@ def create_a2a_in_memory_task_provider(
|
|
|
64
60
|
def _convert_storage_to_serialized(stored: A2ATaskStorage) -> A2ATaskSerialized:
|
|
65
61
|
"""Convert storage format to serialized format"""
|
|
66
62
|
import json
|
|
63
|
+
|
|
67
64
|
metadata_str = None
|
|
68
65
|
if stored.metadata:
|
|
66
|
+
|
|
69
67
|
def datetime_converter(obj):
|
|
70
68
|
if isinstance(obj, datetime):
|
|
71
69
|
return obj.isoformat()
|
|
72
70
|
raise TypeError(f"Object of type {type(obj)} is not JSON serializable")
|
|
73
|
-
|
|
71
|
+
|
|
72
|
+
metadata_str = json.dumps(
|
|
73
|
+
stored.metadata, separators=(",", ":"), default=datetime_converter
|
|
74
|
+
)
|
|
74
75
|
|
|
75
76
|
return A2ATaskSerialized(
|
|
76
77
|
task_id=stored.task_id,
|
|
@@ -80,7 +81,7 @@ def create_a2a_in_memory_task_provider(
|
|
|
80
81
|
status_message=stored.status_message,
|
|
81
82
|
created_at=stored.created_at.isoformat(),
|
|
82
83
|
updated_at=stored.updated_at.isoformat(),
|
|
83
|
-
metadata=metadata_str
|
|
84
|
+
metadata=metadata_str,
|
|
84
85
|
)
|
|
85
86
|
|
|
86
87
|
def _add_to_indices(task_id: str, context_id: str, task_state: TaskState) -> None:
|
|
@@ -103,17 +104,16 @@ def create_a2a_in_memory_task_provider(
|
|
|
103
104
|
if len(state.tasks) >= config.max_tasks:
|
|
104
105
|
return create_a2a_failure(
|
|
105
106
|
create_a2a_task_storage_error(
|
|
106
|
-
|
|
107
|
-
|
|
107
|
+
"store",
|
|
108
|
+
"in-memory",
|
|
108
109
|
None,
|
|
109
|
-
Exception(f
|
|
110
|
+
Exception(f"Storage limit exceeded: maximum {config.max_tasks} tasks allowed"),
|
|
110
111
|
)
|
|
111
112
|
)
|
|
112
113
|
return create_a2a_success(None)
|
|
113
114
|
|
|
114
115
|
async def store_task(
|
|
115
|
-
task: A2ATask,
|
|
116
|
-
metadata: Optional[Dict[str, Any]] = None
|
|
116
|
+
task: A2ATask, metadata: Optional[Dict[str, Any]] = None
|
|
117
117
|
) -> A2AResult[None]:
|
|
118
118
|
"""Store a new A2A task"""
|
|
119
119
|
try:
|
|
@@ -143,21 +143,21 @@ def create_a2a_in_memory_task_provider(
|
|
|
143
143
|
status_message=serialized_task.status_message,
|
|
144
144
|
created_at=datetime.fromisoformat(serialized_task.created_at),
|
|
145
145
|
updated_at=datetime.fromisoformat(serialized_task.updated_at),
|
|
146
|
-
expires_at=metadata.get(
|
|
147
|
-
metadata=metadata
|
|
146
|
+
expires_at=metadata.get("expires_at") if metadata else None,
|
|
147
|
+
metadata=metadata,
|
|
148
148
|
)
|
|
149
149
|
|
|
150
150
|
async with state.lock:
|
|
151
151
|
# Store task and update indices
|
|
152
152
|
state.tasks[task.id] = task_storage
|
|
153
153
|
_add_to_indices(task.id, task.context_id, task.status.state)
|
|
154
|
-
state.stats[
|
|
154
|
+
state.stats["total_tasks"] = len(state.tasks)
|
|
155
155
|
|
|
156
156
|
return create_a2a_success(None)
|
|
157
157
|
|
|
158
158
|
except Exception as error:
|
|
159
159
|
return create_a2a_failure(
|
|
160
|
-
create_a2a_task_storage_error(
|
|
160
|
+
create_a2a_task_storage_error("store", "in-memory", task.id, error)
|
|
161
161
|
)
|
|
162
162
|
|
|
163
163
|
async def get_task(task_id: str) -> A2AResult[Optional[A2ATask]]:
|
|
@@ -182,20 +182,17 @@ def create_a2a_in_memory_task_provider(
|
|
|
182
182
|
|
|
183
183
|
except Exception as error:
|
|
184
184
|
return create_a2a_failure(
|
|
185
|
-
create_a2a_task_storage_error(
|
|
185
|
+
create_a2a_task_storage_error("get", "in-memory", task_id, error)
|
|
186
186
|
)
|
|
187
187
|
|
|
188
188
|
async def update_task(
|
|
189
|
-
task: A2ATask,
|
|
190
|
-
metadata: Optional[Dict[str, Any]] = None
|
|
189
|
+
task: A2ATask, metadata: Optional[Dict[str, Any]] = None
|
|
191
190
|
) -> A2AResult[None]:
|
|
192
191
|
"""Update an existing task"""
|
|
193
192
|
try:
|
|
194
193
|
existing = state.tasks.get(task.id)
|
|
195
194
|
if not existing:
|
|
196
|
-
return create_a2a_failure(
|
|
197
|
-
create_a2a_task_not_found_error(task.id, 'in-memory')
|
|
198
|
-
)
|
|
195
|
+
return create_a2a_failure(create_a2a_task_not_found_error(task.id, "in-memory"))
|
|
199
196
|
|
|
200
197
|
# Validate and sanitize task
|
|
201
198
|
sanitize_result = sanitize_task(task)
|
|
@@ -222,7 +219,7 @@ def create_a2a_in_memory_task_provider(
|
|
|
222
219
|
created_at=existing.created_at,
|
|
223
220
|
updated_at=datetime.fromisoformat(serialized_task.updated_at),
|
|
224
221
|
expires_at=existing.expires_at,
|
|
225
|
-
metadata=merged_metadata
|
|
222
|
+
metadata=merged_metadata,
|
|
226
223
|
)
|
|
227
224
|
|
|
228
225
|
# Update indices if state changed
|
|
@@ -237,22 +234,20 @@ def create_a2a_in_memory_task_provider(
|
|
|
237
234
|
|
|
238
235
|
except Exception as error:
|
|
239
236
|
return create_a2a_failure(
|
|
240
|
-
create_a2a_task_storage_error(
|
|
237
|
+
create_a2a_task_storage_error("update", "in-memory", task.id, error)
|
|
241
238
|
)
|
|
242
239
|
|
|
243
240
|
async def update_task_status(
|
|
244
241
|
task_id: str,
|
|
245
242
|
new_state: TaskState,
|
|
246
243
|
status_message: Optional[Any] = None,
|
|
247
|
-
timestamp: Optional[str] = None
|
|
244
|
+
timestamp: Optional[str] = None,
|
|
248
245
|
) -> A2AResult[None]:
|
|
249
246
|
"""Update task status only (optimized for frequent status changes)"""
|
|
250
247
|
try:
|
|
251
248
|
existing = state.tasks.get(task_id)
|
|
252
249
|
if not existing:
|
|
253
|
-
return create_a2a_failure(
|
|
254
|
-
create_a2a_task_not_found_error(task_id, 'in-memory')
|
|
255
|
-
)
|
|
250
|
+
return create_a2a_failure(create_a2a_task_not_found_error(task_id, "in-memory"))
|
|
256
251
|
|
|
257
252
|
# Deserialize existing task
|
|
258
253
|
serialized = _convert_storage_to_serialized(existing)
|
|
@@ -270,23 +265,23 @@ def create_a2a_in_memory_task_provider(
|
|
|
270
265
|
|
|
271
266
|
# Update task status
|
|
272
267
|
from ...types import A2ATaskStatus
|
|
268
|
+
|
|
273
269
|
updated_status = A2ATaskStatus(
|
|
274
270
|
state=new_state,
|
|
275
271
|
message=status_message,
|
|
276
|
-
timestamp=timestamp or datetime.now().isoformat()
|
|
272
|
+
timestamp=timestamp or datetime.now().isoformat(),
|
|
277
273
|
)
|
|
278
274
|
|
|
279
|
-
updated_task = task.model_copy(
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
})
|
|
275
|
+
updated_task = task.model_copy(
|
|
276
|
+
update={"status": updated_status, "history": updated_history}
|
|
277
|
+
)
|
|
283
278
|
|
|
284
279
|
# Use update_task for the actual update
|
|
285
280
|
return await update_task(updated_task)
|
|
286
281
|
|
|
287
282
|
except Exception as error:
|
|
288
283
|
return create_a2a_failure(
|
|
289
|
-
create_a2a_task_storage_error(
|
|
284
|
+
create_a2a_task_storage_error("update-status", "in-memory", task_id, error)
|
|
290
285
|
)
|
|
291
286
|
|
|
292
287
|
async def find_tasks(query: A2ATaskQuery) -> A2AResult[List[A2ATask]]:
|
|
@@ -305,20 +300,22 @@ def create_a2a_in_memory_task_provider(
|
|
|
305
300
|
# Filter by task_id
|
|
306
301
|
if query.task_id and task_id != query.task_id:
|
|
307
302
|
continue
|
|
308
|
-
|
|
303
|
+
|
|
309
304
|
# Check expiration
|
|
310
305
|
if stored.expires_at and stored.expires_at < datetime.now():
|
|
311
306
|
continue
|
|
312
307
|
|
|
313
308
|
# Date filtering - use metadata created_at if available, otherwise use stored created_at
|
|
314
309
|
task_timestamp = stored.created_at
|
|
315
|
-
if stored.metadata and stored.metadata.get(
|
|
310
|
+
if stored.metadata and stored.metadata.get("created_at"):
|
|
316
311
|
try:
|
|
317
|
-
task_timestamp = datetime.fromisoformat(
|
|
312
|
+
task_timestamp = datetime.fromisoformat(
|
|
313
|
+
stored.metadata["created_at"].replace("Z", "+00:00")
|
|
314
|
+
)
|
|
318
315
|
except:
|
|
319
316
|
# Fall back to stored timestamp if parsing fails
|
|
320
317
|
pass
|
|
321
|
-
|
|
318
|
+
|
|
322
319
|
if query.since and task_timestamp < query.since:
|
|
323
320
|
continue
|
|
324
321
|
if query.until and task_timestamp > query.until:
|
|
@@ -330,28 +327,24 @@ def create_a2a_in_memory_task_provider(
|
|
|
330
327
|
|
|
331
328
|
if isinstance(deserialize_result, Success):
|
|
332
329
|
results.append(deserialize_result.data)
|
|
333
|
-
|
|
330
|
+
|
|
334
331
|
# Sort by timestamp (newest first)
|
|
335
|
-
results.sort(
|
|
336
|
-
key=lambda t: t.status.timestamp or "1970-01-01T00:00:00Z",
|
|
337
|
-
reverse=True
|
|
338
|
-
)
|
|
332
|
+
results.sort(key=lambda t: t.status.timestamp or "1970-01-01T00:00:00Z", reverse=True)
|
|
339
333
|
|
|
340
334
|
# Apply pagination
|
|
341
335
|
offset = query.offset or 0
|
|
342
336
|
limit = query.limit or len(results)
|
|
343
|
-
paginated_results = results[offset:offset + limit]
|
|
337
|
+
paginated_results = results[offset : offset + limit]
|
|
344
338
|
|
|
345
339
|
return create_a2a_success(paginated_results)
|
|
346
340
|
|
|
347
341
|
except Exception as error:
|
|
348
342
|
return create_a2a_failure(
|
|
349
|
-
create_a2a_task_storage_error(
|
|
343
|
+
create_a2a_task_storage_error("find", "in-memory", None, error)
|
|
350
344
|
)
|
|
351
345
|
|
|
352
346
|
async def get_tasks_by_context(
|
|
353
|
-
context_id: str,
|
|
354
|
-
limit: Optional[int] = None
|
|
347
|
+
context_id: str, limit: Optional[int] = None
|
|
355
348
|
) -> A2AResult[List[A2ATask]]:
|
|
356
349
|
"""Get tasks by context ID"""
|
|
357
350
|
return await find_tasks(A2ATaskQuery(context_id=context_id, limit=limit))
|
|
@@ -366,13 +359,13 @@ def create_a2a_in_memory_task_provider(
|
|
|
366
359
|
# Remove from storage and indices
|
|
367
360
|
del state.tasks[task_id]
|
|
368
361
|
_remove_from_indices(task_id, existing.context_id, existing.state)
|
|
369
|
-
state.stats[
|
|
362
|
+
state.stats["total_tasks"] = len(state.tasks)
|
|
370
363
|
|
|
371
364
|
return create_a2a_success(True)
|
|
372
365
|
|
|
373
366
|
except Exception as error:
|
|
374
367
|
return create_a2a_failure(
|
|
375
|
-
create_a2a_task_storage_error(
|
|
368
|
+
create_a2a_task_storage_error("delete", "in-memory", task_id, error)
|
|
376
369
|
)
|
|
377
370
|
|
|
378
371
|
async def delete_tasks_by_context(context_id: str) -> A2AResult[int]:
|
|
@@ -390,13 +383,13 @@ def create_a2a_in_memory_task_provider(
|
|
|
390
383
|
_remove_from_indices(task_id, stored_task.context_id, stored_task.state)
|
|
391
384
|
deleted_count += 1
|
|
392
385
|
|
|
393
|
-
state.stats[
|
|
386
|
+
state.stats["total_tasks"] = len(state.tasks)
|
|
394
387
|
|
|
395
388
|
return create_a2a_success(deleted_count)
|
|
396
389
|
|
|
397
390
|
except Exception as error:
|
|
398
391
|
return create_a2a_failure(
|
|
399
|
-
create_a2a_task_storage_error(
|
|
392
|
+
create_a2a_task_storage_error("delete-by-context", "in-memory", None, error)
|
|
400
393
|
)
|
|
401
394
|
|
|
402
395
|
async def cleanup_expired_tasks() -> A2AResult[int]:
|
|
@@ -421,7 +414,7 @@ def create_a2a_in_memory_task_provider(
|
|
|
421
414
|
|
|
422
415
|
except Exception as error:
|
|
423
416
|
return create_a2a_failure(
|
|
424
|
-
create_a2a_task_storage_error(
|
|
417
|
+
create_a2a_task_storage_error("cleanup", "in-memory", None, error)
|
|
425
418
|
)
|
|
426
419
|
|
|
427
420
|
async def cleanup_expired_tasks_by_context(context_id: str) -> A2AResult[int]:
|
|
@@ -429,7 +422,7 @@ def create_a2a_in_memory_task_provider(
|
|
|
429
422
|
try:
|
|
430
423
|
now = datetime.now()
|
|
431
424
|
cleaned_count = 0
|
|
432
|
-
|
|
425
|
+
|
|
433
426
|
task_ids = state.context_index.get(context_id, set()).copy()
|
|
434
427
|
expired_task_ids = []
|
|
435
428
|
for task_id in task_ids:
|
|
@@ -441,11 +434,11 @@ def create_a2a_in_memory_task_provider(
|
|
|
441
434
|
delete_result = await delete_task(task_id)
|
|
442
435
|
if isinstance(delete_result.data, bool) and delete_result.data:
|
|
443
436
|
cleaned_count += 1
|
|
444
|
-
|
|
437
|
+
|
|
445
438
|
return create_a2a_success(cleaned_count)
|
|
446
439
|
except Exception as error:
|
|
447
440
|
return create_a2a_failure(
|
|
448
|
-
create_a2a_task_storage_error(
|
|
441
|
+
create_a2a_task_storage_error("cleanup-by-context", "in-memory", None, error)
|
|
449
442
|
)
|
|
450
443
|
|
|
451
444
|
async def get_task_stats(context_id: Optional[str] = None) -> A2AResult[Dict[str, Any]]:
|
|
@@ -479,12 +472,12 @@ def create_a2a_in_memory_task_provider(
|
|
|
479
472
|
oldest_task = stored.created_at
|
|
480
473
|
if not newest_task or stored.created_at > newest_task:
|
|
481
474
|
newest_task = stored.created_at
|
|
482
|
-
|
|
475
|
+
|
|
483
476
|
stats = {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
477
|
+
"total_tasks": total_tasks,
|
|
478
|
+
"tasks_by_state": dict(tasks_by_state),
|
|
479
|
+
"oldest_task": oldest_task,
|
|
480
|
+
"newest_task": newest_task,
|
|
488
481
|
}
|
|
489
482
|
# Also add individual state counts for backwards compatibility
|
|
490
483
|
for task_state in TaskState:
|
|
@@ -494,7 +487,7 @@ def create_a2a_in_memory_task_provider(
|
|
|
494
487
|
|
|
495
488
|
except Exception as error:
|
|
496
489
|
return create_a2a_failure(
|
|
497
|
-
create_a2a_task_storage_error(
|
|
490
|
+
create_a2a_task_storage_error("stats", "in-memory", None, error)
|
|
498
491
|
)
|
|
499
492
|
|
|
500
493
|
async def health_check() -> A2AResult[Dict[str, Any]]:
|
|
@@ -506,18 +499,17 @@ def create_a2a_in_memory_task_provider(
|
|
|
506
499
|
task_count = len(state.tasks)
|
|
507
500
|
latency_ms = (datetime.now() - start_time).total_seconds() * 1000
|
|
508
501
|
|
|
509
|
-
return create_a2a_success(
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
502
|
+
return create_a2a_success(
|
|
503
|
+
{
|
|
504
|
+
"healthy": True,
|
|
505
|
+
"provider": "in_memory",
|
|
506
|
+
"latency_ms": latency_ms,
|
|
507
|
+
"task_count": task_count,
|
|
508
|
+
}
|
|
509
|
+
)
|
|
515
510
|
|
|
516
511
|
except Exception as error:
|
|
517
|
-
return create_a2a_success({
|
|
518
|
-
'healthy': False,
|
|
519
|
-
'error': str(error)
|
|
520
|
-
})
|
|
512
|
+
return create_a2a_success({"healthy": False, "error": str(error)})
|
|
521
513
|
|
|
522
514
|
async def close() -> A2AResult[None]:
|
|
523
515
|
"""Close/cleanup the provider"""
|
|
@@ -526,35 +518,47 @@ def create_a2a_in_memory_task_provider(
|
|
|
526
518
|
state.tasks.clear()
|
|
527
519
|
state.context_index.clear()
|
|
528
520
|
state.state_index.clear()
|
|
529
|
-
state.stats = {
|
|
521
|
+
state.stats = {"total_tasks": 0, "created_at": datetime.now()}
|
|
530
522
|
|
|
531
523
|
return create_a2a_success(None)
|
|
532
524
|
|
|
533
525
|
except Exception as error:
|
|
534
526
|
return create_a2a_failure(
|
|
535
|
-
create_a2a_task_storage_error(
|
|
527
|
+
create_a2a_task_storage_error("close", "in-memory", None, error)
|
|
536
528
|
)
|
|
537
529
|
|
|
538
530
|
# Create a simple class that implements the protocol
|
|
539
531
|
class InMemoryA2ATaskProvider:
|
|
540
532
|
"""In-memory implementation of A2ATaskProvider"""
|
|
541
533
|
|
|
542
|
-
async def store_task(
|
|
534
|
+
async def store_task(
|
|
535
|
+
self, task: A2ATask, metadata: Optional[Dict[str, Any]] = None
|
|
536
|
+
) -> A2AResult[None]:
|
|
543
537
|
return await store_task(task, metadata)
|
|
544
538
|
|
|
545
539
|
async def get_task(self, task_id: str) -> A2AResult[Optional[A2ATask]]:
|
|
546
540
|
return await get_task(task_id)
|
|
547
541
|
|
|
548
|
-
async def update_task(
|
|
542
|
+
async def update_task(
|
|
543
|
+
self, task: A2ATask, metadata: Optional[Dict[str, Any]] = None
|
|
544
|
+
) -> A2AResult[None]:
|
|
549
545
|
return await update_task(task, metadata)
|
|
550
546
|
|
|
551
|
-
async def update_task_status(
|
|
547
|
+
async def update_task_status(
|
|
548
|
+
self,
|
|
549
|
+
task_id: str,
|
|
550
|
+
state: TaskState,
|
|
551
|
+
status_message: Optional[Any] = None,
|
|
552
|
+
timestamp: Optional[str] = None,
|
|
553
|
+
) -> A2AResult[None]:
|
|
552
554
|
return await update_task_status(task_id, state, status_message, timestamp)
|
|
553
555
|
|
|
554
556
|
async def find_tasks(self, query: A2ATaskQuery) -> A2AResult[List[A2ATask]]:
|
|
555
557
|
return await find_tasks(query)
|
|
556
558
|
|
|
557
|
-
async def get_tasks_by_context(
|
|
559
|
+
async def get_tasks_by_context(
|
|
560
|
+
self, context_id: str, limit: Optional[int] = None
|
|
561
|
+
) -> A2AResult[List[A2ATask]]:
|
|
558
562
|
return await get_tasks_by_context(context_id, limit)
|
|
559
563
|
|
|
560
564
|
async def delete_task(self, task_id: str) -> A2AResult[bool]:
|
|
@@ -569,7 +573,9 @@ def create_a2a_in_memory_task_provider(
|
|
|
569
573
|
async def cleanup_expired_tasks_by_context(self, context_id: str) -> A2AResult[int]:
|
|
570
574
|
return await cleanup_expired_tasks_by_context(context_id)
|
|
571
575
|
|
|
572
|
-
async def get_task_stats(
|
|
576
|
+
async def get_task_stats(
|
|
577
|
+
self, context_id: Optional[str] = None
|
|
578
|
+
) -> A2AResult[Dict[str, Any]]:
|
|
573
579
|
return await get_task_stats(context_id)
|
|
574
580
|
|
|
575
581
|
async def health_check(self) -> A2AResult[Dict[str, Any]]:
|