agnt5 0.1.0__cp39-abi3-macosx_11_0_arm64.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.
- agnt5/__init__.py +307 -0
- agnt5/__pycache__/__init__.cpython-311.pyc +0 -0
- agnt5/__pycache__/agent.cpython-311.pyc +0 -0
- agnt5/__pycache__/context.cpython-311.pyc +0 -0
- agnt5/__pycache__/durable.cpython-311.pyc +0 -0
- agnt5/__pycache__/extraction.cpython-311.pyc +0 -0
- agnt5/__pycache__/memory.cpython-311.pyc +0 -0
- agnt5/__pycache__/reflection.cpython-311.pyc +0 -0
- agnt5/__pycache__/runtime.cpython-311.pyc +0 -0
- agnt5/__pycache__/task.cpython-311.pyc +0 -0
- agnt5/__pycache__/tool.cpython-311.pyc +0 -0
- agnt5/__pycache__/tracing.cpython-311.pyc +0 -0
- agnt5/__pycache__/types.cpython-311.pyc +0 -0
- agnt5/__pycache__/workflow.cpython-311.pyc +0 -0
- agnt5/_core.abi3.so +0 -0
- agnt5/agent.py +1086 -0
- agnt5/context.py +406 -0
- agnt5/durable.py +1050 -0
- agnt5/extraction.py +410 -0
- agnt5/llm/__init__.py +179 -0
- agnt5/llm/__pycache__/__init__.cpython-311.pyc +0 -0
- agnt5/llm/__pycache__/anthropic.cpython-311.pyc +0 -0
- agnt5/llm/__pycache__/azure.cpython-311.pyc +0 -0
- agnt5/llm/__pycache__/base.cpython-311.pyc +0 -0
- agnt5/llm/__pycache__/google.cpython-311.pyc +0 -0
- agnt5/llm/__pycache__/mistral.cpython-311.pyc +0 -0
- agnt5/llm/__pycache__/openai.cpython-311.pyc +0 -0
- agnt5/llm/__pycache__/together.cpython-311.pyc +0 -0
- agnt5/llm/anthropic.py +319 -0
- agnt5/llm/azure.py +348 -0
- agnt5/llm/base.py +315 -0
- agnt5/llm/google.py +373 -0
- agnt5/llm/mistral.py +330 -0
- agnt5/llm/model_registry.py +467 -0
- agnt5/llm/models.json +227 -0
- agnt5/llm/openai.py +334 -0
- agnt5/llm/together.py +377 -0
- agnt5/memory.py +746 -0
- agnt5/reflection.py +514 -0
- agnt5/runtime.py +699 -0
- agnt5/task.py +476 -0
- agnt5/testing.py +451 -0
- agnt5/tool.py +516 -0
- agnt5/tracing.py +624 -0
- agnt5/types.py +210 -0
- agnt5/workflow.py +897 -0
- agnt5-0.1.0.dist-info/METADATA +93 -0
- agnt5-0.1.0.dist-info/RECORD +49 -0
- agnt5-0.1.0.dist-info/WHEEL +4 -0
agnt5/task.py
ADDED
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Task system for AGNT5 SDK.
|
|
3
|
+
|
|
4
|
+
Provides @task decorator for creating structured, reusable operations with
|
|
5
|
+
validation, error handling, and integration with durable execution.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import inspect
|
|
10
|
+
import json
|
|
11
|
+
import logging
|
|
12
|
+
from abc import ABC, abstractmethod
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from typing import Any, Callable, Dict, List, Optional, Type, TypeVar, Union, get_type_hints
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
from enum import Enum
|
|
17
|
+
|
|
18
|
+
from .durable import durable
|
|
19
|
+
from .context import Context, get_context
|
|
20
|
+
from .tracing import trace_agent_run, span, traced, log, TraceLevel
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
T = TypeVar('T')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class TaskStatus(Enum):
|
|
28
|
+
"""Task execution status."""
|
|
29
|
+
PENDING = "pending"
|
|
30
|
+
RUNNING = "running"
|
|
31
|
+
COMPLETED = "completed"
|
|
32
|
+
FAILED = "failed"
|
|
33
|
+
CANCELLED = "cancelled"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class OutputFormat(Enum):
|
|
37
|
+
"""Supported output formats."""
|
|
38
|
+
JSON = "json"
|
|
39
|
+
PYDANTIC = "pydantic"
|
|
40
|
+
STRING = "string"
|
|
41
|
+
RAW = "raw"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class TaskParameter:
|
|
46
|
+
"""Represents a task parameter with validation."""
|
|
47
|
+
name: str
|
|
48
|
+
type: Type
|
|
49
|
+
description: Optional[str] = None
|
|
50
|
+
required: bool = True
|
|
51
|
+
default: Any = None
|
|
52
|
+
|
|
53
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
54
|
+
return {
|
|
55
|
+
"name": self.name,
|
|
56
|
+
"type": self.type.__name__ if hasattr(self.type, '__name__') else str(self.type),
|
|
57
|
+
"description": self.description,
|
|
58
|
+
"required": self.required,
|
|
59
|
+
"default": self.default
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass
|
|
64
|
+
class TaskConfig:
|
|
65
|
+
"""Configuration for a task."""
|
|
66
|
+
name: str
|
|
67
|
+
description: Optional[str] = None
|
|
68
|
+
output_format: OutputFormat = OutputFormat.RAW
|
|
69
|
+
output_schema: Optional[Dict[str, Any]] = None
|
|
70
|
+
retry_count: int = 3
|
|
71
|
+
timeout: Optional[float] = None
|
|
72
|
+
enable_durability: bool = True
|
|
73
|
+
parameters: List[TaskParameter] = field(default_factory=list)
|
|
74
|
+
|
|
75
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
76
|
+
return {
|
|
77
|
+
"name": self.name,
|
|
78
|
+
"description": self.description,
|
|
79
|
+
"output_format": self.output_format.value,
|
|
80
|
+
"output_schema": self.output_schema,
|
|
81
|
+
"retry_count": self.retry_count,
|
|
82
|
+
"timeout": self.timeout,
|
|
83
|
+
"enable_durability": self.enable_durability,
|
|
84
|
+
"parameters": [param.to_dict() for param in self.parameters]
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@dataclass
|
|
89
|
+
class TaskResult:
|
|
90
|
+
"""Result of task execution."""
|
|
91
|
+
task_name: str
|
|
92
|
+
status: TaskStatus
|
|
93
|
+
output: Any = None
|
|
94
|
+
error: Optional[str] = None
|
|
95
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
96
|
+
started_at: Optional[datetime] = None
|
|
97
|
+
completed_at: Optional[datetime] = None
|
|
98
|
+
execution_time: Optional[float] = None
|
|
99
|
+
|
|
100
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
101
|
+
return {
|
|
102
|
+
"task_name": self.task_name,
|
|
103
|
+
"status": self.status.value,
|
|
104
|
+
"output": self.output,
|
|
105
|
+
"error": self.error,
|
|
106
|
+
"metadata": self.metadata,
|
|
107
|
+
"started_at": self.started_at.isoformat() if self.started_at else None,
|
|
108
|
+
"completed_at": self.completed_at.isoformat() if self.completed_at else None,
|
|
109
|
+
"execution_time": self.execution_time
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class TaskRegistry:
|
|
114
|
+
"""Global registry for tasks."""
|
|
115
|
+
_tasks: Dict[str, 'Task'] = {}
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
def register(cls, task: 'Task') -> None:
|
|
119
|
+
"""Register a task."""
|
|
120
|
+
cls._tasks[task.config.name] = task
|
|
121
|
+
|
|
122
|
+
@classmethod
|
|
123
|
+
def get(cls, name: str) -> Optional['Task']:
|
|
124
|
+
"""Get a task by name."""
|
|
125
|
+
return cls._tasks.get(name)
|
|
126
|
+
|
|
127
|
+
@classmethod
|
|
128
|
+
def list_tasks(cls) -> List[str]:
|
|
129
|
+
"""Get list of registered task names."""
|
|
130
|
+
return list(cls._tasks.keys())
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def get_all(cls) -> Dict[str, 'Task']:
|
|
134
|
+
"""Get all registered tasks."""
|
|
135
|
+
return cls._tasks.copy()
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class OutputValidator(ABC):
|
|
139
|
+
"""Base class for output validators."""
|
|
140
|
+
|
|
141
|
+
@abstractmethod
|
|
142
|
+
def validate(self, output: Any) -> Any:
|
|
143
|
+
"""Validate and potentially transform output."""
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class JSONValidator(OutputValidator):
|
|
148
|
+
"""Validates and parses JSON output."""
|
|
149
|
+
|
|
150
|
+
def __init__(self, schema: Optional[Dict[str, Any]] = None):
|
|
151
|
+
self.schema = schema
|
|
152
|
+
|
|
153
|
+
def validate(self, output: Any) -> Any:
|
|
154
|
+
"""Validate JSON output."""
|
|
155
|
+
if isinstance(output, str):
|
|
156
|
+
try:
|
|
157
|
+
parsed = json.loads(output)
|
|
158
|
+
return self._validate_schema(parsed) if self.schema else parsed
|
|
159
|
+
except json.JSONDecodeError as e:
|
|
160
|
+
raise ValueError(f"Invalid JSON output: {e}")
|
|
161
|
+
elif isinstance(output, (dict, list)):
|
|
162
|
+
return self._validate_schema(output) if self.schema else output
|
|
163
|
+
else:
|
|
164
|
+
raise ValueError(f"Expected JSON-serializable output, got {type(output)}")
|
|
165
|
+
|
|
166
|
+
def _validate_schema(self, data: Any) -> Any:
|
|
167
|
+
"""Basic schema validation (can be enhanced with jsonschema library)."""
|
|
168
|
+
if not self.schema:
|
|
169
|
+
return data
|
|
170
|
+
|
|
171
|
+
# Basic type checking
|
|
172
|
+
if "type" in self.schema:
|
|
173
|
+
expected_type = self.schema["type"]
|
|
174
|
+
if expected_type == "object" and not isinstance(data, dict):
|
|
175
|
+
raise ValueError(f"Expected object, got {type(data)}")
|
|
176
|
+
elif expected_type == "array" and not isinstance(data, list):
|
|
177
|
+
raise ValueError(f"Expected array, got {type(data)}")
|
|
178
|
+
|
|
179
|
+
# Check required properties for objects
|
|
180
|
+
if isinstance(data, dict) and "properties" in self.schema:
|
|
181
|
+
required = self.schema.get("required", [])
|
|
182
|
+
for prop in required:
|
|
183
|
+
if prop not in data:
|
|
184
|
+
raise ValueError(f"Missing required property: {prop}")
|
|
185
|
+
|
|
186
|
+
return data
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class PydanticValidator(OutputValidator):
|
|
190
|
+
"""Validates output using Pydantic models."""
|
|
191
|
+
|
|
192
|
+
def __init__(self, model_class: Type):
|
|
193
|
+
self.model_class = model_class
|
|
194
|
+
|
|
195
|
+
def validate(self, output: Any) -> Any:
|
|
196
|
+
"""Validate using Pydantic model."""
|
|
197
|
+
try:
|
|
198
|
+
if isinstance(output, str):
|
|
199
|
+
# Try to parse as JSON first
|
|
200
|
+
try:
|
|
201
|
+
output = json.loads(output)
|
|
202
|
+
except json.JSONDecodeError:
|
|
203
|
+
pass
|
|
204
|
+
|
|
205
|
+
if isinstance(output, dict):
|
|
206
|
+
return self.model_class(**output)
|
|
207
|
+
else:
|
|
208
|
+
return self.model_class(output)
|
|
209
|
+
except Exception as e:
|
|
210
|
+
raise ValueError(f"Failed to validate with {self.model_class.__name__}: {e}")
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class Task:
|
|
214
|
+
"""
|
|
215
|
+
A task represents a structured, reusable operation with validation and error handling.
|
|
216
|
+
|
|
217
|
+
Tasks can be used for data extraction, processing, validation, and other operations
|
|
218
|
+
that benefit from structured input/output and automatic retry mechanisms.
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
def __init__(self, config: TaskConfig, func: Callable):
|
|
222
|
+
self.config = config
|
|
223
|
+
self.func = func
|
|
224
|
+
self._validator = self._create_validator()
|
|
225
|
+
|
|
226
|
+
# Extract parameter information from function signature
|
|
227
|
+
self._extract_parameters()
|
|
228
|
+
|
|
229
|
+
def _create_validator(self) -> Optional[OutputValidator]:
|
|
230
|
+
"""Create appropriate validator based on configuration."""
|
|
231
|
+
if self.config.output_format == OutputFormat.JSON:
|
|
232
|
+
return JSONValidator(self.config.output_schema)
|
|
233
|
+
elif self.config.output_format == OutputFormat.PYDANTIC and self.config.output_schema:
|
|
234
|
+
# Output schema should contain the Pydantic model class
|
|
235
|
+
model_class = self.config.output_schema.get("model_class")
|
|
236
|
+
if model_class:
|
|
237
|
+
return PydanticValidator(model_class)
|
|
238
|
+
return None
|
|
239
|
+
|
|
240
|
+
def _extract_parameters(self) -> None:
|
|
241
|
+
"""Extract parameter information from function signature."""
|
|
242
|
+
try:
|
|
243
|
+
sig = inspect.signature(self.func)
|
|
244
|
+
|
|
245
|
+
# Try to get type hints, but handle forward references gracefully
|
|
246
|
+
try:
|
|
247
|
+
type_hints = get_type_hints(self.func)
|
|
248
|
+
except (NameError, AttributeError):
|
|
249
|
+
# Fall back to raw annotations if type hints can't be resolved
|
|
250
|
+
type_hints = getattr(self.func, '__annotations__', {})
|
|
251
|
+
|
|
252
|
+
parameters = []
|
|
253
|
+
for param_name, param in sig.parameters.items():
|
|
254
|
+
if param_name in ['self', 'cls']:
|
|
255
|
+
continue
|
|
256
|
+
|
|
257
|
+
param_type = type_hints.get(param_name, str)
|
|
258
|
+
required = param.default == inspect.Parameter.empty
|
|
259
|
+
default = param.default if not required else None
|
|
260
|
+
|
|
261
|
+
parameters.append(TaskParameter(
|
|
262
|
+
name=param_name,
|
|
263
|
+
type=param_type,
|
|
264
|
+
required=required,
|
|
265
|
+
default=default
|
|
266
|
+
))
|
|
267
|
+
|
|
268
|
+
self.config.parameters = parameters
|
|
269
|
+
except Exception as e:
|
|
270
|
+
logger.warning(f"Failed to extract parameters for task {self.config.name}: {e}")
|
|
271
|
+
|
|
272
|
+
async def run(self, *args, **kwargs) -> TaskResult:
|
|
273
|
+
"""Execute the task with validation and error handling."""
|
|
274
|
+
task_result = TaskResult(
|
|
275
|
+
task_name=self.config.name,
|
|
276
|
+
status=TaskStatus.RUNNING,
|
|
277
|
+
started_at=datetime.utcnow()
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
with traced(f"task.{self.config.name}"):
|
|
281
|
+
try:
|
|
282
|
+
with span("task.execution") as task_span:
|
|
283
|
+
task_span.set_attribute("task.name", self.config.name)
|
|
284
|
+
task_span.set_attribute("task.durability", self.config.enable_durability)
|
|
285
|
+
task_span.set_attribute("task.output_format", self.config.output_format.value)
|
|
286
|
+
|
|
287
|
+
# Execute with or without durability
|
|
288
|
+
if self.config.enable_durability:
|
|
289
|
+
output = await self._run_durable(*args, **kwargs)
|
|
290
|
+
else:
|
|
291
|
+
output = await self._run_direct(*args, **kwargs)
|
|
292
|
+
|
|
293
|
+
# Validate output
|
|
294
|
+
if self._validator:
|
|
295
|
+
output = self._validator.validate(output)
|
|
296
|
+
|
|
297
|
+
# Complete task
|
|
298
|
+
task_result.status = TaskStatus.COMPLETED
|
|
299
|
+
task_result.output = output
|
|
300
|
+
task_result.completed_at = datetime.utcnow()
|
|
301
|
+
task_result.execution_time = (
|
|
302
|
+
task_result.completed_at - task_result.started_at
|
|
303
|
+
).total_seconds()
|
|
304
|
+
|
|
305
|
+
task_span.set_attribute("task.status", "completed")
|
|
306
|
+
task_span.set_attribute("task.execution_time", task_result.execution_time)
|
|
307
|
+
|
|
308
|
+
log(TraceLevel.INFO, f"Task {self.config.name} completed successfully",
|
|
309
|
+
task_name=self.config.name, execution_time=task_result.execution_time)
|
|
310
|
+
|
|
311
|
+
return task_result
|
|
312
|
+
|
|
313
|
+
except Exception as e:
|
|
314
|
+
task_result.status = TaskStatus.FAILED
|
|
315
|
+
task_result.error = str(e)
|
|
316
|
+
task_result.completed_at = datetime.utcnow()
|
|
317
|
+
task_result.execution_time = (
|
|
318
|
+
task_result.completed_at - task_result.started_at
|
|
319
|
+
).total_seconds()
|
|
320
|
+
|
|
321
|
+
logger.error(f"Task {self.config.name} failed: {e}")
|
|
322
|
+
log(TraceLevel.ERROR, f"Task {self.config.name} failed: {e}",
|
|
323
|
+
task_name=self.config.name, error_type=type(e).__name__)
|
|
324
|
+
|
|
325
|
+
return task_result
|
|
326
|
+
|
|
327
|
+
@durable.function
|
|
328
|
+
async def _run_durable(self, *args, **kwargs) -> Any:
|
|
329
|
+
"""Run task with durability guarantees."""
|
|
330
|
+
return await self._run_direct(*args, **kwargs)
|
|
331
|
+
|
|
332
|
+
async def _run_direct(self, *args, **kwargs) -> Any:
|
|
333
|
+
"""Run task directly without durability."""
|
|
334
|
+
if inspect.iscoroutinefunction(self.func):
|
|
335
|
+
return await self.func(*args, **kwargs)
|
|
336
|
+
else:
|
|
337
|
+
# Run sync function in thread pool
|
|
338
|
+
import asyncio
|
|
339
|
+
loop = asyncio.get_event_loop()
|
|
340
|
+
return await loop.run_in_executor(None, self.func, *args, **kwargs)
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def task(
|
|
344
|
+
name: Optional[str] = None,
|
|
345
|
+
description: Optional[str] = None,
|
|
346
|
+
output_format: OutputFormat = OutputFormat.RAW,
|
|
347
|
+
output_schema: Optional[Dict[str, Any]] = None,
|
|
348
|
+
retry_count: int = 3,
|
|
349
|
+
timeout: Optional[float] = None,
|
|
350
|
+
enable_durability: bool = True,
|
|
351
|
+
) -> Callable:
|
|
352
|
+
"""
|
|
353
|
+
Decorator to create a task from a function.
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
name: Task name (defaults to function name)
|
|
357
|
+
description: Task description
|
|
358
|
+
output_format: Expected output format (json, pydantic, string, raw)
|
|
359
|
+
output_schema: Schema for output validation
|
|
360
|
+
retry_count: Number of retry attempts on failure
|
|
361
|
+
timeout: Execution timeout in seconds
|
|
362
|
+
enable_durability: Whether to enable durable execution
|
|
363
|
+
|
|
364
|
+
Example:
|
|
365
|
+
```python
|
|
366
|
+
@task(name="extract_data", output_format=OutputFormat.JSON)
|
|
367
|
+
def extract_json_data(text: str) -> dict:
|
|
368
|
+
'''Extract structured data from text.'''
|
|
369
|
+
# Processing logic
|
|
370
|
+
return {"extracted": "data"}
|
|
371
|
+
|
|
372
|
+
# Use the task
|
|
373
|
+
result = await extract_json_data.run("input text")
|
|
374
|
+
print(result.output) # {"extracted": "data"}
|
|
375
|
+
```
|
|
376
|
+
"""
|
|
377
|
+
def decorator(func: Callable) -> 'TaskFunction':
|
|
378
|
+
task_name = name or func.__name__
|
|
379
|
+
task_description = description or inspect.getdoc(func) or f"Task: {task_name}"
|
|
380
|
+
|
|
381
|
+
config = TaskConfig(
|
|
382
|
+
name=task_name,
|
|
383
|
+
description=task_description,
|
|
384
|
+
output_format=output_format,
|
|
385
|
+
output_schema=output_schema,
|
|
386
|
+
retry_count=retry_count,
|
|
387
|
+
timeout=timeout,
|
|
388
|
+
enable_durability=enable_durability
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
task_instance = Task(config, func)
|
|
392
|
+
TaskRegistry.register(task_instance)
|
|
393
|
+
|
|
394
|
+
# Create a wrapper that preserves the original function interface
|
|
395
|
+
# but adds task capabilities
|
|
396
|
+
return TaskFunction(task_instance, func)
|
|
397
|
+
|
|
398
|
+
return decorator
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
class TaskFunction:
|
|
402
|
+
"""Wrapper that makes a task behave like a function while adding task capabilities."""
|
|
403
|
+
|
|
404
|
+
def __init__(self, task: Task, original_func: Callable):
|
|
405
|
+
self.task = task
|
|
406
|
+
self.original_func = original_func
|
|
407
|
+
self.__name__ = original_func.__name__
|
|
408
|
+
self.__doc__ = original_func.__doc__
|
|
409
|
+
|
|
410
|
+
async def __call__(self, *args, **kwargs) -> Any:
|
|
411
|
+
"""Direct function call returns just the output."""
|
|
412
|
+
result = await self.task.run(*args, **kwargs)
|
|
413
|
+
if result.status == TaskStatus.COMPLETED:
|
|
414
|
+
return result.output
|
|
415
|
+
else:
|
|
416
|
+
raise RuntimeError(f"Task failed: {result.error}")
|
|
417
|
+
|
|
418
|
+
async def run(self, *args, **kwargs) -> TaskResult:
|
|
419
|
+
"""Run as task and return full TaskResult."""
|
|
420
|
+
return await self.task.run(*args, **kwargs)
|
|
421
|
+
|
|
422
|
+
@property
|
|
423
|
+
def config(self) -> TaskConfig:
|
|
424
|
+
"""Get task configuration."""
|
|
425
|
+
return self.task.config
|
|
426
|
+
|
|
427
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
428
|
+
"""Export task configuration."""
|
|
429
|
+
return self.task.config.to_dict()
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
# Convenience functions for common task types
|
|
433
|
+
def json_extraction_task(
|
|
434
|
+
name: Optional[str] = None,
|
|
435
|
+
description: Optional[str] = None,
|
|
436
|
+
schema: Optional[Dict[str, Any]] = None,
|
|
437
|
+
**kwargs
|
|
438
|
+
) -> Callable:
|
|
439
|
+
"""Create a task for JSON data extraction."""
|
|
440
|
+
return task(
|
|
441
|
+
name=name,
|
|
442
|
+
description=description,
|
|
443
|
+
output_format=OutputFormat.JSON,
|
|
444
|
+
output_schema=schema,
|
|
445
|
+
**kwargs
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
def pydantic_task(
|
|
450
|
+
model_class: Type,
|
|
451
|
+
name: Optional[str] = None,
|
|
452
|
+
description: Optional[str] = None,
|
|
453
|
+
**kwargs
|
|
454
|
+
) -> Callable:
|
|
455
|
+
"""Create a task with Pydantic output validation."""
|
|
456
|
+
return task(
|
|
457
|
+
name=name,
|
|
458
|
+
description=description,
|
|
459
|
+
output_format=OutputFormat.PYDANTIC,
|
|
460
|
+
output_schema={"model_class": model_class},
|
|
461
|
+
**kwargs
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def string_task(
|
|
466
|
+
name: Optional[str] = None,
|
|
467
|
+
description: Optional[str] = None,
|
|
468
|
+
**kwargs
|
|
469
|
+
) -> Callable:
|
|
470
|
+
"""Create a task that returns string output."""
|
|
471
|
+
return task(
|
|
472
|
+
name=name,
|
|
473
|
+
description=description,
|
|
474
|
+
output_format=OutputFormat.STRING,
|
|
475
|
+
**kwargs
|
|
476
|
+
)
|