xpander-sdk 1.60.4__py3-none-any.whl → 2.0.155__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.
- xpander_sdk/__init__.py +76 -7793
- xpander_sdk/consts/__init__.py +0 -0
- xpander_sdk/consts/api_routes.py +63 -0
- xpander_sdk/core/__init__.py +0 -0
- xpander_sdk/core/module_base.py +164 -0
- xpander_sdk/core/state.py +10 -0
- xpander_sdk/core/xpander_api_client.py +119 -0
- xpander_sdk/exceptions/__init__.py +0 -0
- xpander_sdk/exceptions/module_exception.py +45 -0
- xpander_sdk/models/__init__.py +0 -0
- xpander_sdk/models/activity.py +65 -0
- xpander_sdk/models/configuration.py +92 -0
- xpander_sdk/models/events.py +70 -0
- xpander_sdk/models/frameworks.py +64 -0
- xpander_sdk/models/shared.py +102 -0
- xpander_sdk/models/user.py +21 -0
- xpander_sdk/modules/__init__.py +0 -0
- xpander_sdk/modules/agents/__init__.py +0 -0
- xpander_sdk/modules/agents/agents_module.py +164 -0
- xpander_sdk/modules/agents/models/__init__.py +0 -0
- xpander_sdk/modules/agents/models/agent.py +477 -0
- xpander_sdk/modules/agents/models/agent_list.py +107 -0
- xpander_sdk/modules/agents/models/knowledge_bases.py +33 -0
- xpander_sdk/modules/agents/sub_modules/__init__.py +0 -0
- xpander_sdk/modules/agents/sub_modules/agent.py +953 -0
- xpander_sdk/modules/agents/utils/__init__.py +0 -0
- xpander_sdk/modules/agents/utils/generic.py +2 -0
- xpander_sdk/modules/backend/__init__.py +0 -0
- xpander_sdk/modules/backend/backend_module.py +425 -0
- xpander_sdk/modules/backend/frameworks/__init__.py +0 -0
- xpander_sdk/modules/backend/frameworks/agno.py +627 -0
- xpander_sdk/modules/backend/frameworks/dispatch.py +36 -0
- xpander_sdk/modules/backend/utils/__init__.py +0 -0
- xpander_sdk/modules/backend/utils/mcp_oauth.py +95 -0
- xpander_sdk/modules/events/__init__.py +0 -0
- xpander_sdk/modules/events/decorators/__init__.py +0 -0
- xpander_sdk/modules/events/decorators/on_boot.py +94 -0
- xpander_sdk/modules/events/decorators/on_shutdown.py +94 -0
- xpander_sdk/modules/events/decorators/on_task.py +203 -0
- xpander_sdk/modules/events/events_module.py +629 -0
- xpander_sdk/modules/events/models/__init__.py +0 -0
- xpander_sdk/modules/events/models/deployments.py +25 -0
- xpander_sdk/modules/events/models/events.py +57 -0
- xpander_sdk/modules/events/utils/__init__.py +0 -0
- xpander_sdk/modules/events/utils/generic.py +56 -0
- xpander_sdk/modules/events/utils/git_init.py +32 -0
- xpander_sdk/modules/knowledge_bases/__init__.py +0 -0
- xpander_sdk/modules/knowledge_bases/knowledge_bases_module.py +217 -0
- xpander_sdk/modules/knowledge_bases/models/__init__.py +0 -0
- xpander_sdk/modules/knowledge_bases/models/knowledge_bases.py +11 -0
- xpander_sdk/modules/knowledge_bases/sub_modules/__init__.py +0 -0
- xpander_sdk/modules/knowledge_bases/sub_modules/knowledge_base.py +107 -0
- xpander_sdk/modules/knowledge_bases/sub_modules/knowledge_base_document_item.py +40 -0
- xpander_sdk/modules/knowledge_bases/utils/__init__.py +0 -0
- xpander_sdk/modules/tasks/__init__.py +0 -0
- xpander_sdk/modules/tasks/models/__init__.py +0 -0
- xpander_sdk/modules/tasks/models/task.py +153 -0
- xpander_sdk/modules/tasks/models/tasks_list.py +107 -0
- xpander_sdk/modules/tasks/sub_modules/__init__.py +0 -0
- xpander_sdk/modules/tasks/sub_modules/task.py +887 -0
- xpander_sdk/modules/tasks/tasks_module.py +492 -0
- xpander_sdk/modules/tasks/utils/__init__.py +0 -0
- xpander_sdk/modules/tasks/utils/files.py +114 -0
- xpander_sdk/modules/tools_repository/__init__.py +0 -0
- xpander_sdk/modules/tools_repository/decorators/__init__.py +0 -0
- xpander_sdk/modules/tools_repository/decorators/register_tool.py +108 -0
- xpander_sdk/modules/tools_repository/models/__init__.py +0 -0
- xpander_sdk/modules/tools_repository/models/mcp.py +68 -0
- xpander_sdk/modules/tools_repository/models/tool_invocation_result.py +14 -0
- xpander_sdk/modules/tools_repository/sub_modules/__init__.py +0 -0
- xpander_sdk/modules/tools_repository/sub_modules/tool.py +578 -0
- xpander_sdk/modules/tools_repository/tools_repository_module.py +259 -0
- xpander_sdk/modules/tools_repository/utils/__init__.py +0 -0
- xpander_sdk/modules/tools_repository/utils/generic.py +57 -0
- xpander_sdk/modules/tools_repository/utils/local_tools.py +52 -0
- xpander_sdk/modules/tools_repository/utils/schemas.py +308 -0
- xpander_sdk/utils/__init__.py +0 -0
- xpander_sdk/utils/env.py +44 -0
- xpander_sdk/utils/event_loop.py +67 -0
- xpander_sdk/utils/tools.py +32 -0
- xpander_sdk-2.0.155.dist-info/METADATA +538 -0
- xpander_sdk-2.0.155.dist-info/RECORD +85 -0
- {xpander_sdk-1.60.4.dist-info → xpander_sdk-2.0.155.dist-info}/WHEEL +1 -1
- {xpander_sdk-1.60.4.dist-info → xpander_sdk-2.0.155.dist-info/licenses}/LICENSE +0 -1
- xpander_sdk/_jsii/__init__.py +0 -39
- xpander_sdk/_jsii/xpander-sdk@1.60.4.jsii.tgz +0 -0
- xpander_sdk/py.typed +0 -1
- xpander_sdk-1.60.4.dist-info/METADATA +0 -368
- xpander_sdk-1.60.4.dist-info/RECORD +0 -9
- {xpander_sdk-1.60.4.dist-info → xpander_sdk-2.0.155.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,887 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Task Management Module for xpander.ai SDK.
|
|
3
|
+
|
|
4
|
+
This module provides the Task class which serves as the primary interface
|
|
5
|
+
for managing task execution within the xpander.ai platform. It handles
|
|
6
|
+
task lifecycle operations including loading, saving, status updates,
|
|
7
|
+
and termination.
|
|
8
|
+
|
|
9
|
+
The Task class integrates with the xpander.ai Backend-as-a-Service (BaaS)
|
|
10
|
+
platform to provide seamless task management capabilities with both
|
|
11
|
+
synchronous and asynchronous operations.
|
|
12
|
+
|
|
13
|
+
Typical usage example:
|
|
14
|
+
>>> from xpander_sdk.modules.tasks.sub_modules.task import Task
|
|
15
|
+
>>> from xpander_sdk.modules.tasks.models.task import AgentExecutionStatus
|
|
16
|
+
|
|
17
|
+
>>> # Load an existing task
|
|
18
|
+
>>> task = Task.load(task_id="task_123")
|
|
19
|
+
|
|
20
|
+
>>> # Update task status
|
|
21
|
+
>>> task.set_status(AgentExecutionStatus.Running)
|
|
22
|
+
|
|
23
|
+
>>> # Save changes
|
|
24
|
+
>>> task.save()
|
|
25
|
+
|
|
26
|
+
>>> # Stop the task when needed
|
|
27
|
+
>>> task.stop()
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from datetime import datetime
|
|
31
|
+
from typing import (
|
|
32
|
+
Any,
|
|
33
|
+
AsyncGenerator,
|
|
34
|
+
Dict,
|
|
35
|
+
Generator,
|
|
36
|
+
List,
|
|
37
|
+
Optional,
|
|
38
|
+
Type,
|
|
39
|
+
TypeVar,
|
|
40
|
+
Union,
|
|
41
|
+
)
|
|
42
|
+
from httpx import HTTPStatusError
|
|
43
|
+
import httpx
|
|
44
|
+
import json
|
|
45
|
+
from httpx_sse import aconnect_sse
|
|
46
|
+
|
|
47
|
+
from xpander_sdk.consts.api_routes import APIRoute
|
|
48
|
+
from xpander_sdk.core.xpander_api_client import APIClient
|
|
49
|
+
from xpander_sdk.exceptions.module_exception import ModuleException
|
|
50
|
+
from xpander_sdk.models.activity import AgentActivityThread
|
|
51
|
+
from xpander_sdk.models.configuration import Configuration
|
|
52
|
+
from xpander_sdk.models.events import (
|
|
53
|
+
TaskUpdateEventType,
|
|
54
|
+
ToolCallRequest,
|
|
55
|
+
ToolCallResult,
|
|
56
|
+
)
|
|
57
|
+
from xpander_sdk.models.shared import (
|
|
58
|
+
ExecutionTokens,
|
|
59
|
+
OutputFormat,
|
|
60
|
+
ThinkMode,
|
|
61
|
+
Tokens,
|
|
62
|
+
XPanderSharedModel,
|
|
63
|
+
)
|
|
64
|
+
from xpander_sdk.modules.events.utils.generic import get_events_base, get_events_headers
|
|
65
|
+
from xpander_sdk.modules.tasks.models.task import (
|
|
66
|
+
AgentExecutionInput,
|
|
67
|
+
AgentExecutionStatus,
|
|
68
|
+
HumanInTheLoop,
|
|
69
|
+
ExecutionMetricsReport,
|
|
70
|
+
PendingECARequest,
|
|
71
|
+
TaskReportRequest,
|
|
72
|
+
)
|
|
73
|
+
from xpander_sdk.modules.tasks.utils.files import (
|
|
74
|
+
categorize_files,
|
|
75
|
+
fetch_urls,
|
|
76
|
+
fetch_file,
|
|
77
|
+
)
|
|
78
|
+
from xpander_sdk.modules.tools_repository.models.mcp import (
|
|
79
|
+
MCPOAuthGetTokenResponse,
|
|
80
|
+
MCPServerDetails,
|
|
81
|
+
)
|
|
82
|
+
from xpander_sdk.utils.event_loop import run_sync
|
|
83
|
+
|
|
84
|
+
# Type variable for Task class methods
|
|
85
|
+
T = TypeVar("T", bound="Task")
|
|
86
|
+
|
|
87
|
+
TaskUpdateEventData = Union[
|
|
88
|
+
T, ToolCallRequest, ToolCallResult, MCPOAuthGetTokenResponse
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class TaskUpdateEvent(XPanderSharedModel):
|
|
93
|
+
type: TaskUpdateEventType
|
|
94
|
+
task_id: str
|
|
95
|
+
organization_id: str
|
|
96
|
+
time: datetime
|
|
97
|
+
data: TaskUpdateEventData
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class Task(XPanderSharedModel):
|
|
101
|
+
"""
|
|
102
|
+
Represents a task entity in the xpander.ai platform.
|
|
103
|
+
|
|
104
|
+
This class manages task-related operations, including state updates,
|
|
105
|
+
API interaction, status control, and lifecycle management.
|
|
106
|
+
|
|
107
|
+
Attributes:
|
|
108
|
+
configuration (Optional[Configuration]): The current configuration settings for the task.
|
|
109
|
+
id (str): Unique identifier for the task.
|
|
110
|
+
agent_id (str): Identifier for the associated agent.
|
|
111
|
+
organization_id (str): Identifier for the organization.
|
|
112
|
+
input (AgentExecutionInput): The input parameters for agent execution.
|
|
113
|
+
status (Optional[AgentExecutionStatus]): Current status of the task.
|
|
114
|
+
last_executed_node_id (Optional[str]): ID of the last executed node.
|
|
115
|
+
agent_version (Optional[str]): Version of the agent.
|
|
116
|
+
created_at (datetime): Timestamp when the task was created.
|
|
117
|
+
started_at (Optional[datetime]): Timestamp when the task was started.
|
|
118
|
+
paused_at (Optional[datetime]): Timestamp when the task was paused.
|
|
119
|
+
finished_at (Optional[datetime]): Timestamp when the task was finished.
|
|
120
|
+
result (Optional[str]): Result of the task execution.
|
|
121
|
+
parent_execution (Optional[str]): Parent execution ID, if applicable.
|
|
122
|
+
sub_executions (Optional[List[str]]): List of sub-execution IDs.
|
|
123
|
+
is_manually_stopped (Optional[bool]): Flag indicating if the task was manually stopped.
|
|
124
|
+
payload_extension (Optional[dict]): Additional data for the task.
|
|
125
|
+
hitl_request (Optional[HumanInTheLoop]): Human-in-the-loop request state.
|
|
126
|
+
pending_eca_request (Optional[PendingECARequest]): Pending ECA request, if any.
|
|
127
|
+
source (Optional[str]): Source information of the task.
|
|
128
|
+
output_format (Optional[OutputFormat]): Desired output format of the task.
|
|
129
|
+
output_schema (Optional[Dict]): Schema for the task's output.
|
|
130
|
+
events_streaming (Optional[bool]): Flag indicating if the task has events streaming.
|
|
131
|
+
additional_context (Optional[str]): Additional context to be passed to the agent.
|
|
132
|
+
expected_output (Optional[str]): Expected output of the execution.
|
|
133
|
+
mcp_servers (Optional[List[MCPServerDetails]]): Optional list of mcp servers to use.
|
|
134
|
+
triggering_agent_id (Optional[str]): Optional triggering agent id.
|
|
135
|
+
title (Optional[str]): Optional task title.
|
|
136
|
+
|
|
137
|
+
Example:
|
|
138
|
+
>>> task = Task.load(task_id="task_123")
|
|
139
|
+
>>> task.set_status(AgentExecutionStatus.Running)
|
|
140
|
+
>>> task.save()
|
|
141
|
+
>>>
|
|
142
|
+
>>> # Get files for Agno integration
|
|
143
|
+
>>> files = task.get_files() # PDF files as Agno File objects
|
|
144
|
+
>>> images = task.get_images() # Image files as Agno Image objects
|
|
145
|
+
>>> result = await agno_agent.arun(
|
|
146
|
+
... input=task.to_message(),
|
|
147
|
+
... files=files,
|
|
148
|
+
... images=images
|
|
149
|
+
... )
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
configuration: Optional[Configuration] = None
|
|
153
|
+
id: str
|
|
154
|
+
agent_id: str
|
|
155
|
+
organization_id: str
|
|
156
|
+
input: AgentExecutionInput
|
|
157
|
+
status: Optional[AgentExecutionStatus] = AgentExecutionStatus.Pending
|
|
158
|
+
internal_status: Optional[str] = None
|
|
159
|
+
last_executed_node_id: Optional[str] = None
|
|
160
|
+
agent_version: Optional[str] = None
|
|
161
|
+
created_at: datetime
|
|
162
|
+
started_at: Optional[datetime] = None
|
|
163
|
+
paused_at: Optional[datetime] = None
|
|
164
|
+
finished_at: Optional[datetime] = None
|
|
165
|
+
result: Optional[str] = None
|
|
166
|
+
parent_execution: Optional[str] = None
|
|
167
|
+
sub_executions: Optional[List[str]] = []
|
|
168
|
+
is_manually_stopped: Optional[bool] = False
|
|
169
|
+
payload_extension: Optional[dict] = None
|
|
170
|
+
hitl_request: Optional[HumanInTheLoop] = None
|
|
171
|
+
pending_eca_request: Optional[PendingECARequest] = None
|
|
172
|
+
source: Optional[str] = None
|
|
173
|
+
output_format: Optional[OutputFormat] = None
|
|
174
|
+
output_schema: Optional[Dict] = None
|
|
175
|
+
events_streaming: Optional[bool] = False
|
|
176
|
+
additional_context: Optional[str] = None
|
|
177
|
+
expected_output: Optional[str] = (None,)
|
|
178
|
+
mcp_servers: Optional[List[MCPServerDetails]] = ([],)
|
|
179
|
+
triggering_agent_id: Optional[str] = (None,)
|
|
180
|
+
title: Optional[str] = (None,)
|
|
181
|
+
think_mode: Optional[ThinkMode] = ThinkMode.Default
|
|
182
|
+
disable_attachment_injection: Optional[bool] = False
|
|
183
|
+
|
|
184
|
+
# metrics
|
|
185
|
+
tokens: Optional[Tokens] = None
|
|
186
|
+
used_tools: Optional[List[str]] = []
|
|
187
|
+
duration: Optional[float] = 0
|
|
188
|
+
|
|
189
|
+
def model_post_init(self, context):
|
|
190
|
+
"""
|
|
191
|
+
Post-initialization hook for the model.
|
|
192
|
+
|
|
193
|
+
This method is called after the model is initialized. It sets the current
|
|
194
|
+
task state and then calls the parent class's `model_post_init` method.
|
|
195
|
+
|
|
196
|
+
Parameters:
|
|
197
|
+
context (Any): Context object provided during model initialization.
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
Any: The result from the superclass `model_post_init` method.
|
|
201
|
+
|
|
202
|
+
Note:
|
|
203
|
+
This method uses `self.configuration.state.task = self` to register the current task
|
|
204
|
+
in the global state.
|
|
205
|
+
|
|
206
|
+
Powered by xpander.ai
|
|
207
|
+
"""
|
|
208
|
+
self.configuration.state.task = self
|
|
209
|
+
return super().model_post_init(context)
|
|
210
|
+
|
|
211
|
+
async def areload(self):
|
|
212
|
+
"""
|
|
213
|
+
Reload the current object asynchronously.
|
|
214
|
+
|
|
215
|
+
This method fetches a new instance of the object from the data source
|
|
216
|
+
using the current object's `id` and `configuration`, then updates the
|
|
217
|
+
current object's attributes with the new instance's attributes.
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
self: The reloaded instance of the object.
|
|
221
|
+
|
|
222
|
+
Powered by xpander.ai
|
|
223
|
+
"""
|
|
224
|
+
new_obj = await self.aload(
|
|
225
|
+
task_id=self.id,
|
|
226
|
+
configuration=self.configuration,
|
|
227
|
+
)
|
|
228
|
+
self.__dict__.update(new_obj.__dict__)
|
|
229
|
+
return self
|
|
230
|
+
|
|
231
|
+
def reload(self):
|
|
232
|
+
"""
|
|
233
|
+
Reload the current object synchronously.
|
|
234
|
+
|
|
235
|
+
This method runs the asynchronous `areload` method synchronously
|
|
236
|
+
to update the current object's attributes.
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
self: The reloaded instance of the object.
|
|
240
|
+
|
|
241
|
+
Powered by xpander.ai
|
|
242
|
+
"""
|
|
243
|
+
run_sync(self.areload())
|
|
244
|
+
|
|
245
|
+
@classmethod
|
|
246
|
+
async def aload(
|
|
247
|
+
cls: Type[T], task_id: str, configuration: Optional[Configuration] = None
|
|
248
|
+
) -> T:
|
|
249
|
+
"""
|
|
250
|
+
Asynchronously loads a task by its ID.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
task_id (str): Unique identifier for the task to load.
|
|
254
|
+
configuration (Optional[Configuration]): Configuration settings for API interaction.
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
T: Instance of the Task class.
|
|
258
|
+
|
|
259
|
+
Raises:
|
|
260
|
+
ModuleException: Error related to HTTP requests or task fetching.
|
|
261
|
+
|
|
262
|
+
Example:
|
|
263
|
+
>>> task = await Task.aload(task_id="task_123")
|
|
264
|
+
"""
|
|
265
|
+
try:
|
|
266
|
+
client = APIClient(configuration=configuration)
|
|
267
|
+
response_data = await client.make_request(
|
|
268
|
+
path=APIRoute.GetTask.format(task_id=task_id)
|
|
269
|
+
)
|
|
270
|
+
task = cls.model_validate(
|
|
271
|
+
{**response_data, "configuration": configuration or Configuration()}
|
|
272
|
+
)
|
|
273
|
+
return task
|
|
274
|
+
except HTTPStatusError as e:
|
|
275
|
+
raise ModuleException(
|
|
276
|
+
status_code=e.response.status_code, description=e.response.text
|
|
277
|
+
)
|
|
278
|
+
except Exception as e:
|
|
279
|
+
raise ModuleException(
|
|
280
|
+
status_code=500, description=f"Failed to get tas - {str(e)}"
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
@classmethod
|
|
284
|
+
def load(
|
|
285
|
+
cls: Type[T], task_id: str, configuration: Optional[Configuration] = None
|
|
286
|
+
) -> T:
|
|
287
|
+
"""
|
|
288
|
+
Loads a task by its ID synchronously.
|
|
289
|
+
|
|
290
|
+
This function wraps the asynchronous aload method.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
task_id (str): Unique identifier for the task to load.
|
|
294
|
+
configuration (Optional[Configuration]): Configuration settings for API interaction.
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
T: Instance of the Task class.
|
|
298
|
+
|
|
299
|
+
Example:
|
|
300
|
+
>>> task = Task.load(task_id="task_123")
|
|
301
|
+
"""
|
|
302
|
+
return run_sync(cls.aload(task_id=task_id, configuration=configuration))
|
|
303
|
+
|
|
304
|
+
async def aset_status(
|
|
305
|
+
self, status: AgentExecutionStatus, result: Optional[str] = None
|
|
306
|
+
):
|
|
307
|
+
"""
|
|
308
|
+
Asynchronously sets the task status and updates it in the backend.
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
status (AgentExecutionStatus): The new status to apply.
|
|
312
|
+
result (str): The result to apply.
|
|
313
|
+
|
|
314
|
+
Example:
|
|
315
|
+
>>> await task.aset_status(AgentExecutionStatus.Running, "task started")
|
|
316
|
+
"""
|
|
317
|
+
self.status = status
|
|
318
|
+
self.result = result
|
|
319
|
+
await self.asave()
|
|
320
|
+
|
|
321
|
+
def set_status(self, status: AgentExecutionStatus, result: Optional[str] = None):
|
|
322
|
+
"""
|
|
323
|
+
Sets the task status synchronously.
|
|
324
|
+
|
|
325
|
+
This function wraps the asynchronous aset_status method.
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
status (AgentExecutionStatus): The new status to apply.
|
|
329
|
+
result (str): The result to apply.
|
|
330
|
+
|
|
331
|
+
Example:
|
|
332
|
+
>>> task.set_status(AgentExecutionStatus.Running, "task started")
|
|
333
|
+
"""
|
|
334
|
+
return run_sync(self.aset_status(status=status, result=result))
|
|
335
|
+
|
|
336
|
+
async def asave(self):
|
|
337
|
+
"""
|
|
338
|
+
Asynchronously saves the current task state to the backend.
|
|
339
|
+
|
|
340
|
+
Raises:
|
|
341
|
+
ModuleException: Error related to HTTP requests or task saving.
|
|
342
|
+
|
|
343
|
+
Example:
|
|
344
|
+
>>> await task.asave()
|
|
345
|
+
"""
|
|
346
|
+
client = APIClient(configuration=self.configuration)
|
|
347
|
+
try:
|
|
348
|
+
response = await client.make_request(
|
|
349
|
+
path=APIRoute.UpdateTask.format(task_id=self.id),
|
|
350
|
+
method="PATCH",
|
|
351
|
+
payload=self.model_dump_safe(),
|
|
352
|
+
)
|
|
353
|
+
updated_task = Task(**response, configuration=self.configuration)
|
|
354
|
+
for field, value in updated_task.__dict__.items():
|
|
355
|
+
setattr(self, field, value)
|
|
356
|
+
except HTTPStatusError as e:
|
|
357
|
+
raise ModuleException(e.response.status_code, e.response.text)
|
|
358
|
+
except Exception as e:
|
|
359
|
+
raise ModuleException(500, f"Failed to save task: {str(e)}")
|
|
360
|
+
|
|
361
|
+
def save(self):
|
|
362
|
+
"""
|
|
363
|
+
Saves the current task state synchronously.
|
|
364
|
+
|
|
365
|
+
This function wraps the asynchronous asave method.
|
|
366
|
+
|
|
367
|
+
Example:
|
|
368
|
+
>>> task.save()
|
|
369
|
+
"""
|
|
370
|
+
return run_sync(self.asave())
|
|
371
|
+
|
|
372
|
+
async def astop(self):
|
|
373
|
+
"""
|
|
374
|
+
Asynchronously stops the task.
|
|
375
|
+
|
|
376
|
+
Communicates with the backend to terminate the task execution.
|
|
377
|
+
|
|
378
|
+
Raises:
|
|
379
|
+
ModuleException: Error related to HTTP requests or task stopping.
|
|
380
|
+
|
|
381
|
+
Example:
|
|
382
|
+
>>> await task.astop()
|
|
383
|
+
"""
|
|
384
|
+
client = APIClient(configuration=self.configuration)
|
|
385
|
+
try:
|
|
386
|
+
response = await client.make_request(
|
|
387
|
+
path=APIRoute.TaskCrud.format(agent_or_task_id=self.id), method="DELETE"
|
|
388
|
+
)
|
|
389
|
+
updated_task = Task(**response, configuration=self.configuration)
|
|
390
|
+
for field, value in updated_task.__dict__.items():
|
|
391
|
+
setattr(self, field, value)
|
|
392
|
+
except HTTPStatusError as e:
|
|
393
|
+
raise ModuleException(e.response.status_code, e.response.text)
|
|
394
|
+
except Exception as e:
|
|
395
|
+
raise ModuleException(500, f"Failed to stop task: {str(e)}")
|
|
396
|
+
|
|
397
|
+
def stop(self):
|
|
398
|
+
"""
|
|
399
|
+
Stops the task synchronously.
|
|
400
|
+
|
|
401
|
+
This function wraps the asynchronous astop method.
|
|
402
|
+
|
|
403
|
+
Example:
|
|
404
|
+
>>> task.stop()
|
|
405
|
+
"""
|
|
406
|
+
return run_sync(self.astop())
|
|
407
|
+
|
|
408
|
+
def get_files(self) -> list[Any]:
|
|
409
|
+
"""
|
|
410
|
+
Get PDF files from task input, formatted for Agno integration.
|
|
411
|
+
|
|
412
|
+
Returns PDF files as Agno File objects when the Agno framework is available,
|
|
413
|
+
or as URL strings otherwise. This method is designed for seamless integration
|
|
414
|
+
with Agno agents.
|
|
415
|
+
|
|
416
|
+
Returns:
|
|
417
|
+
list[Any]: List of File objects (when Agno is available) or URL strings.
|
|
418
|
+
Returns empty list if no PDF files are present in task input.
|
|
419
|
+
|
|
420
|
+
Example:
|
|
421
|
+
>>> files = task.get_files()
|
|
422
|
+
>>> result = await agno_agent.arun(
|
|
423
|
+
... input=task.to_message(),
|
|
424
|
+
... files=files
|
|
425
|
+
... )
|
|
426
|
+
"""
|
|
427
|
+
|
|
428
|
+
if not self.input.files or len(self.input.files) == 0:
|
|
429
|
+
return []
|
|
430
|
+
|
|
431
|
+
categorized_files = categorize_files(file_urls=self.input.files)
|
|
432
|
+
|
|
433
|
+
if not categorized_files.pdfs or len(categorized_files.pdfs) == 0:
|
|
434
|
+
return []
|
|
435
|
+
|
|
436
|
+
try:
|
|
437
|
+
from agno.media import File # test import
|
|
438
|
+
|
|
439
|
+
return [fetch_file(url=url) for url in categorized_files.pdfs]
|
|
440
|
+
except Exception:
|
|
441
|
+
return categorized_files.pdfs
|
|
442
|
+
|
|
443
|
+
def get_images(self) -> list[Any]:
|
|
444
|
+
"""
|
|
445
|
+
Get image files from task input, formatted for Agno integration.
|
|
446
|
+
|
|
447
|
+
Returns image files as Agno Image objects when the Agno framework is available,
|
|
448
|
+
or as URL strings otherwise. This method is designed for seamless integration
|
|
449
|
+
with Agno agents that support image processing.
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
list[Any]: List of Image objects (when Agno is available) or URL strings.
|
|
453
|
+
Returns empty list if no image files are present in task input.
|
|
454
|
+
|
|
455
|
+
Example:
|
|
456
|
+
>>> images = task.get_images()
|
|
457
|
+
>>> result = await agno_agent.arun(
|
|
458
|
+
... input=task.to_message(),
|
|
459
|
+
... images=images
|
|
460
|
+
... )
|
|
461
|
+
"""
|
|
462
|
+
if not self.input.files or len(self.input.files) == 0:
|
|
463
|
+
return []
|
|
464
|
+
|
|
465
|
+
categorized_files = categorize_files(file_urls=self.input.files)
|
|
466
|
+
|
|
467
|
+
if not categorized_files.images or len(categorized_files.images) == 0:
|
|
468
|
+
return []
|
|
469
|
+
|
|
470
|
+
try:
|
|
471
|
+
from agno.media import Image
|
|
472
|
+
|
|
473
|
+
return [Image(url=url) for url in categorized_files.images]
|
|
474
|
+
except Exception:
|
|
475
|
+
return categorized_files.images
|
|
476
|
+
|
|
477
|
+
def get_human_readable_files(self) -> list[Any]:
|
|
478
|
+
"""
|
|
479
|
+
Get human-readable files from task input with their content.
|
|
480
|
+
|
|
481
|
+
Returns text-based files (like .txt, .csv, .json, .py, etc.) with their content
|
|
482
|
+
fetched and parsed. This method is automatically used by to_message() to include
|
|
483
|
+
file contents in the task message.
|
|
484
|
+
|
|
485
|
+
Returns:
|
|
486
|
+
list[dict[str, str]]: List of dictionaries with 'url' and 'content' keys.
|
|
487
|
+
Returns empty list if no human-readable files are present.
|
|
488
|
+
|
|
489
|
+
Example:
|
|
490
|
+
>>> readable_files = task.get_human_readable_files()
|
|
491
|
+
>>> for file_data in readable_files:
|
|
492
|
+
... print(f"File: {file_data['url']}")
|
|
493
|
+
... print(f"Content: {file_data['content']}")
|
|
494
|
+
"""
|
|
495
|
+
if not self.input.files or len(self.input.files) == 0:
|
|
496
|
+
return []
|
|
497
|
+
|
|
498
|
+
categorized_files = categorize_files(file_urls=self.input.files)
|
|
499
|
+
|
|
500
|
+
if not categorized_files.files or len(categorized_files.files) == 0:
|
|
501
|
+
return []
|
|
502
|
+
|
|
503
|
+
return run_sync(
|
|
504
|
+
fetch_urls(
|
|
505
|
+
urls=categorized_files.files,
|
|
506
|
+
disable_attachment_injection=self.disable_attachment_injection,
|
|
507
|
+
)
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
def to_message(self) -> str:
|
|
511
|
+
"""
|
|
512
|
+
Converts the input data into a formatted message string.
|
|
513
|
+
|
|
514
|
+
This method constructs a message from text and file inputs.
|
|
515
|
+
If text exists, it is included first. If files are present,
|
|
516
|
+
they are appended as a comma-separated list under "Files:".
|
|
517
|
+
|
|
518
|
+
Returns:
|
|
519
|
+
str: A formatted message string including text and/or file names.
|
|
520
|
+
|
|
521
|
+
Powered by xpander.ai
|
|
522
|
+
"""
|
|
523
|
+
message = ""
|
|
524
|
+
if self.input.text:
|
|
525
|
+
message = self.input.text
|
|
526
|
+
|
|
527
|
+
if self.input.files and len(self.input.files) != 0:
|
|
528
|
+
if len(message) != 0:
|
|
529
|
+
message += "\n"
|
|
530
|
+
message += "Files: " + (", ".join(self.input.files))
|
|
531
|
+
|
|
532
|
+
# append human readable content like csv and such
|
|
533
|
+
readable_files = self.get_human_readable_files()
|
|
534
|
+
if readable_files and len(readable_files) != 0:
|
|
535
|
+
message += "\nFiles contents:"
|
|
536
|
+
for f in readable_files:
|
|
537
|
+
message += f"\n{json.dumps(f)}"
|
|
538
|
+
|
|
539
|
+
return message
|
|
540
|
+
|
|
541
|
+
async def aget_activity_log(self) -> AgentActivityThread:
|
|
542
|
+
"""
|
|
543
|
+
Asynchronously retrieves the activity log for this task.
|
|
544
|
+
|
|
545
|
+
Fetches a detailed activity thread containing all messages, tool calls,
|
|
546
|
+
reasoning steps, sub-agent triggers, and authentication events that
|
|
547
|
+
occurred during the task execution.
|
|
548
|
+
|
|
549
|
+
Returns:
|
|
550
|
+
AgentActivityThread: Complete activity log including messages,
|
|
551
|
+
tool calls, reasoning, and other execution events.
|
|
552
|
+
|
|
553
|
+
Raises:
|
|
554
|
+
ModuleException: If the activity log cannot be retrieved or doesn't exist.
|
|
555
|
+
|
|
556
|
+
Example:
|
|
557
|
+
>>> task = await Task.aload(task_id="task_123")
|
|
558
|
+
>>> activity_log = await task.aget_activity_log()
|
|
559
|
+
>>> for message in activity_log.messages:
|
|
560
|
+
... print(f"{message.role}: {message.content.text}")
|
|
561
|
+
"""
|
|
562
|
+
try:
|
|
563
|
+
client = APIClient(configuration=self.configuration)
|
|
564
|
+
activity_log: AgentActivityThread = await client.make_request(
|
|
565
|
+
path=APIRoute.GetTaskActivityLog.format(
|
|
566
|
+
agent_id=self.agent_id, task_id=self.id
|
|
567
|
+
),
|
|
568
|
+
model=AgentActivityThread,
|
|
569
|
+
)
|
|
570
|
+
if not activity_log:
|
|
571
|
+
raise HTTPStatusError(404, "Log not found")
|
|
572
|
+
|
|
573
|
+
return activity_log
|
|
574
|
+
except HTTPStatusError as e:
|
|
575
|
+
raise ModuleException(
|
|
576
|
+
status_code=e.response.status_code, description=e.response.text
|
|
577
|
+
)
|
|
578
|
+
except Exception as e:
|
|
579
|
+
raise ModuleException(
|
|
580
|
+
status_code=500, description=f"Failed to get activity log - {str(e)}"
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
def get_activity_log(self) -> AgentActivityThread:
|
|
584
|
+
"""
|
|
585
|
+
Retrieves the activity log for this task synchronously.
|
|
586
|
+
|
|
587
|
+
This method wraps the asynchronous aget_activity_log method for use
|
|
588
|
+
in synchronous environments.
|
|
589
|
+
|
|
590
|
+
Returns:
|
|
591
|
+
AgentActivityThread: Complete activity log including messages,
|
|
592
|
+
tool calls, reasoning, and other execution events.
|
|
593
|
+
|
|
594
|
+
Raises:
|
|
595
|
+
ModuleException: If the activity log cannot be retrieved or doesn't exist.
|
|
596
|
+
|
|
597
|
+
Example:
|
|
598
|
+
>>> task = Task.load(task_id="task_123")
|
|
599
|
+
>>> activity_log = task.get_activity_log()
|
|
600
|
+
>>> for message in activity_log.messages:
|
|
601
|
+
... print(f"{message.role}: {message.content.text}")
|
|
602
|
+
"""
|
|
603
|
+
return run_sync(self.aget_activity_log())
|
|
604
|
+
|
|
605
|
+
async def aevents(self) -> AsyncGenerator[TaskUpdateEvent, None]:
|
|
606
|
+
"""
|
|
607
|
+
Asynchronously streams task events.
|
|
608
|
+
|
|
609
|
+
This method connects to the xpander.ai event stream using Server-Sent Events (SSE)
|
|
610
|
+
and yields each `TaskUpdateEvent` related to the current task as they arrive.
|
|
611
|
+
|
|
612
|
+
Requires that the task was created or loaded with `events_streaming=True`.
|
|
613
|
+
|
|
614
|
+
Yields:
|
|
615
|
+
TaskUpdateEvent: A parsed event containing real-time updates about the task.
|
|
616
|
+
|
|
617
|
+
Raises:
|
|
618
|
+
ValueError: If the task is not configured for event streaming.
|
|
619
|
+
|
|
620
|
+
Example:
|
|
621
|
+
>>> async for event in task.aevents():
|
|
622
|
+
>>> print(event)
|
|
623
|
+
"""
|
|
624
|
+
if not self.events_streaming:
|
|
625
|
+
raise ValueError(f"Task {self.id} does not set with events streaming")
|
|
626
|
+
|
|
627
|
+
headers = get_events_headers(configuration=self.configuration)
|
|
628
|
+
url = get_events_base(configuration=self.configuration).replace(
|
|
629
|
+
"/events", f"/agent-execution/{self.id}/events"
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
async with httpx.AsyncClient(timeout=None, headers=headers) as client:
|
|
633
|
+
async with aconnect_sse(client, method="GET", url=url) as sse:
|
|
634
|
+
async for event in sse.aiter_sse():
|
|
635
|
+
# parse task and add configuration
|
|
636
|
+
if event.data:
|
|
637
|
+
try:
|
|
638
|
+
json_event_data: dict = json.loads(event.data)
|
|
639
|
+
if json_event_data.get("type", None).startswith("task"):
|
|
640
|
+
task_data = json_event_data.get("data")
|
|
641
|
+
json_event_data.pop("data") # delete data
|
|
642
|
+
yield TaskUpdateEvent(
|
|
643
|
+
**json_event_data,
|
|
644
|
+
data=Task(
|
|
645
|
+
**task_data, configuration=self.configuration
|
|
646
|
+
),
|
|
647
|
+
)
|
|
648
|
+
continue
|
|
649
|
+
except Exception:
|
|
650
|
+
pass
|
|
651
|
+
yield TaskUpdateEvent.model_validate_json(event.data)
|
|
652
|
+
|
|
653
|
+
def events(self) -> Generator[TaskUpdateEvent, None, None]:
|
|
654
|
+
"""
|
|
655
|
+
Synchronously streams task events.
|
|
656
|
+
|
|
657
|
+
This method wraps the asynchronous `aevents` generator and yields events in a
|
|
658
|
+
blocking manner for use in synchronous environments.
|
|
659
|
+
|
|
660
|
+
Requires that the task was created or loaded with `events_streaming=True`.
|
|
661
|
+
|
|
662
|
+
Yields:
|
|
663
|
+
TaskUpdateEvent: A parsed event containing real-time updates about the task.
|
|
664
|
+
|
|
665
|
+
Raises:
|
|
666
|
+
ValueError: If the task is not configured for event streaming.
|
|
667
|
+
|
|
668
|
+
Example:
|
|
669
|
+
>>> for event in task.events():
|
|
670
|
+
>>> print(event)
|
|
671
|
+
"""
|
|
672
|
+
|
|
673
|
+
async def _consume():
|
|
674
|
+
async for event in self.aevents():
|
|
675
|
+
yield event
|
|
676
|
+
|
|
677
|
+
queue = []
|
|
678
|
+
|
|
679
|
+
async def _run():
|
|
680
|
+
async for item in _consume():
|
|
681
|
+
queue.append(item)
|
|
682
|
+
|
|
683
|
+
run_sync(_run())
|
|
684
|
+
|
|
685
|
+
while queue:
|
|
686
|
+
yield queue.pop(0)
|
|
687
|
+
|
|
688
|
+
async def areport_metrics(self, configuration: Optional[Configuration] = None):
|
|
689
|
+
"""
|
|
690
|
+
Asynchronously report LLM task metrics to xpander.ai.
|
|
691
|
+
|
|
692
|
+
Args:
|
|
693
|
+
configuration (Optional[Configuration], optional):
|
|
694
|
+
API client configuration. If not provided, a new instance is created. Defaults to None.
|
|
695
|
+
|
|
696
|
+
Raises:
|
|
697
|
+
ModuleException: If the request fails due to an HTTP or unexpected error.
|
|
698
|
+
|
|
699
|
+
Returns:
|
|
700
|
+
None
|
|
701
|
+
"""
|
|
702
|
+
try:
|
|
703
|
+
configuration = configuration or Configuration()
|
|
704
|
+
client = APIClient(configuration=configuration)
|
|
705
|
+
|
|
706
|
+
if not self.tokens:
|
|
707
|
+
raise ValueError("tokens must be provided. task.tokens = Tokens()")
|
|
708
|
+
|
|
709
|
+
task_report_request = ExecutionMetricsReport(
|
|
710
|
+
execution_id=self.id,
|
|
711
|
+
source=self.source,
|
|
712
|
+
memory_thread_id=self.id,
|
|
713
|
+
task=self.input.text or "",
|
|
714
|
+
status=self.status.value,
|
|
715
|
+
internal_status=self.internal_status,
|
|
716
|
+
duration=0.0,
|
|
717
|
+
ai_model="xpander",
|
|
718
|
+
api_calls_made=self.used_tools,
|
|
719
|
+
result=self.result or None,
|
|
720
|
+
llm_tokens=ExecutionTokens(worker=self.tokens),
|
|
721
|
+
)
|
|
722
|
+
|
|
723
|
+
await client.make_request(
|
|
724
|
+
path=APIRoute.ReportExecutionMetrics.format(agent_id=self.agent_id),
|
|
725
|
+
method="POST",
|
|
726
|
+
payload=task_report_request.model_dump_safe(),
|
|
727
|
+
)
|
|
728
|
+
|
|
729
|
+
except HTTPStatusError as e:
|
|
730
|
+
raise ModuleException(
|
|
731
|
+
status_code=e.response.status_code, description=e.response.text
|
|
732
|
+
)
|
|
733
|
+
except Exception as e:
|
|
734
|
+
raise ModuleException(
|
|
735
|
+
status_code=500, description=f"Failed to report metrics - {str(e)}"
|
|
736
|
+
)
|
|
737
|
+
|
|
738
|
+
def report_metrics(self, configuration: Optional[Configuration] = None):
|
|
739
|
+
"""
|
|
740
|
+
Report LLM task metrics to xpander.ai.
|
|
741
|
+
|
|
742
|
+
Args:
|
|
743
|
+
configuration (Optional[Configuration], optional):
|
|
744
|
+
API client configuration. If not provided, a new instance is created. Defaults to None.
|
|
745
|
+
|
|
746
|
+
Raises:
|
|
747
|
+
ModuleException: If the request fails due to an HTTP or unexpected error.
|
|
748
|
+
|
|
749
|
+
Returns:
|
|
750
|
+
None
|
|
751
|
+
"""
|
|
752
|
+
return run_sync(self.areport_metrics(configuration=configuration))
|
|
753
|
+
|
|
754
|
+
@classmethod
|
|
755
|
+
async def areport_external_task(
|
|
756
|
+
cls: Type[T],
|
|
757
|
+
configuration: Optional[Configuration] = None,
|
|
758
|
+
agent_id: Optional[str] = None,
|
|
759
|
+
id: Optional[str] = None,
|
|
760
|
+
input: Optional[str] = None,
|
|
761
|
+
llm_response: Optional[Any] = None,
|
|
762
|
+
tokens: Optional[Tokens] = None,
|
|
763
|
+
is_success: Optional[bool] = True,
|
|
764
|
+
result: Optional[str] = None,
|
|
765
|
+
duration: Optional[float] = 0,
|
|
766
|
+
used_tools: Optional[List[str]] = [],
|
|
767
|
+
) -> T:
|
|
768
|
+
"""
|
|
769
|
+
Asynchronously reports an external task to the xpander.ai backend.
|
|
770
|
+
|
|
771
|
+
This method is used to report the result of a task that was executed
|
|
772
|
+
externally (outside the xpander.ai platform). It submits execution details,
|
|
773
|
+
including inputs, outputs, success status, and resource usage, to the backend.
|
|
774
|
+
|
|
775
|
+
Args:
|
|
776
|
+
configuration (Optional[Configuration]): Optional configuration for API calls.
|
|
777
|
+
agent_id (Optional[str]): Identifier of the agent associated with the task.
|
|
778
|
+
id (Optional[str]): Task identifier (external or internal).
|
|
779
|
+
input (Optional[str]): The input parameters or data used in execution.
|
|
780
|
+
llm_response (Optional[Any]): The raw LLM response or relevant output object.
|
|
781
|
+
tokens (Optional[Tokens]): Tokens used in the execution.
|
|
782
|
+
is_success (Optional[bool]): Whether the task execution was successful. Defaults to True.
|
|
783
|
+
result (Optional[str]): String representation of the final result.
|
|
784
|
+
duration (Optional[float]): Task execution duration, in seconds. Defaults to 0.
|
|
785
|
+
used_tools (Optional[List[str]]): List of tools used during the execution. Defaults to empty list.
|
|
786
|
+
|
|
787
|
+
Returns:
|
|
788
|
+
T: Instance of the Task class, representing the reported task.
|
|
789
|
+
|
|
790
|
+
Raises:
|
|
791
|
+
ModuleException: Raised on backend or network errors.
|
|
792
|
+
|
|
793
|
+
Example:
|
|
794
|
+
>>> task = await Task.areport_external_task(
|
|
795
|
+
... agent_id="agent_xyz",
|
|
796
|
+
... id="external_task_123",
|
|
797
|
+
... input="User message",
|
|
798
|
+
... result="Done"
|
|
799
|
+
... )
|
|
800
|
+
"""
|
|
801
|
+
try:
|
|
802
|
+
configuration = configuration or Configuration()
|
|
803
|
+
client = APIClient(configuration=configuration)
|
|
804
|
+
task_report_request = TaskReportRequest(
|
|
805
|
+
id=id,
|
|
806
|
+
input=input,
|
|
807
|
+
llm_response=llm_response,
|
|
808
|
+
tokens=tokens,
|
|
809
|
+
is_success=is_success,
|
|
810
|
+
result=result,
|
|
811
|
+
duration=duration,
|
|
812
|
+
used_tools=used_tools,
|
|
813
|
+
)
|
|
814
|
+
response_data = await client.make_request(
|
|
815
|
+
path=APIRoute.ReportExternalTask.format(agent_id=agent_id),
|
|
816
|
+
method="POST",
|
|
817
|
+
payload=task_report_request.model_dump_safe(),
|
|
818
|
+
)
|
|
819
|
+
return cls.model_validate({**response_data, "configuration": configuration})
|
|
820
|
+
except HTTPStatusError as e:
|
|
821
|
+
raise ModuleException(
|
|
822
|
+
status_code=e.response.status_code, description=e.response.text
|
|
823
|
+
)
|
|
824
|
+
except Exception as e:
|
|
825
|
+
raise ModuleException(
|
|
826
|
+
status_code=500,
|
|
827
|
+
description=f"Failed to report external task - {str(e)}",
|
|
828
|
+
)
|
|
829
|
+
|
|
830
|
+
@classmethod
|
|
831
|
+
def report_external_task(
|
|
832
|
+
cls: Type[T],
|
|
833
|
+
configuration: Optional[Configuration] = None,
|
|
834
|
+
agent_id: Optional[str] = None,
|
|
835
|
+
id: Optional[str] = None,
|
|
836
|
+
input: Optional[str] = None,
|
|
837
|
+
llm_response: Optional[Any] = None,
|
|
838
|
+
tokens: Optional[Tokens] = None,
|
|
839
|
+
is_success: Optional[bool] = True,
|
|
840
|
+
result: Optional[str] = None,
|
|
841
|
+
duration: Optional[float] = 0,
|
|
842
|
+
used_tools: Optional[List[str]] = [],
|
|
843
|
+
) -> T:
|
|
844
|
+
"""
|
|
845
|
+
Synchronously reports an external task to the xpander.ai backend.
|
|
846
|
+
|
|
847
|
+
This function wraps the asynchronous `areport_external_task` method for
|
|
848
|
+
synchronous usage. It submits execution details, including inputs, outputs,
|
|
849
|
+
success status, and resource usage, to the backend.
|
|
850
|
+
|
|
851
|
+
Args:
|
|
852
|
+
configuration (Optional[Configuration]): Optional configuration for API calls.
|
|
853
|
+
agent_id (Optional[str]): Identifier of the agent associated with the task.
|
|
854
|
+
id (Optional[str]): Task identifier (external or internal).
|
|
855
|
+
input (Optional[str]): The input parameters or data used in execution.
|
|
856
|
+
llm_response (Optional[Any]): The raw LLM response or relevant output object.
|
|
857
|
+
tokens (Optional[Tokens]): Tokens used in the execution.
|
|
858
|
+
is_success (Optional[bool]): Whether the task execution was successful. Defaults to True.
|
|
859
|
+
result (Optional[str]): String representation of the final result.
|
|
860
|
+
duration (Optional[float]): Task execution duration, in seconds. Defaults to 0.
|
|
861
|
+
used_tools (Optional[List[str]]): List of tools used during the execution. Defaults to empty list.
|
|
862
|
+
|
|
863
|
+
Returns:
|
|
864
|
+
T: Instance of the Task class, representing the reported task.
|
|
865
|
+
|
|
866
|
+
Example:
|
|
867
|
+
>>> task = Task.report_external_task(
|
|
868
|
+
... agent_id="agent_xyz",
|
|
869
|
+
... id="external_task_123",
|
|
870
|
+
... input="User message",
|
|
871
|
+
... result="Done"
|
|
872
|
+
... )
|
|
873
|
+
"""
|
|
874
|
+
return run_sync(
|
|
875
|
+
cls.areport_external_task(
|
|
876
|
+
configuration=configuration,
|
|
877
|
+
agent_id=agent_id,
|
|
878
|
+
id=id,
|
|
879
|
+
input=input,
|
|
880
|
+
llm_response=llm_response,
|
|
881
|
+
tokens=tokens,
|
|
882
|
+
is_success=is_success,
|
|
883
|
+
result=result,
|
|
884
|
+
duration=duration,
|
|
885
|
+
used_tools=used_tools,
|
|
886
|
+
)
|
|
887
|
+
)
|