xpander-sdk 2.0.150__tar.gz → 2.0.151__tar.gz

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.
Files changed (99) hide show
  1. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/PKG-INFO +35 -1
  2. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/README.md +34 -0
  3. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/setup.py +1 -1
  4. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/consts/api_routes.py +1 -0
  5. xpander_sdk-2.0.151/src/xpander_sdk/models/activity.py +65 -0
  6. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tasks/sub_modules/task.py +163 -78
  7. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk.egg-info/PKG-INFO +35 -1
  8. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk.egg-info/SOURCES.txt +1 -0
  9. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/LICENSE +0 -0
  10. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/pyproject.toml +0 -0
  11. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/setup.cfg +0 -0
  12. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/__init__.py +0 -0
  13. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/consts/__init__.py +0 -0
  14. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/core/__init__.py +0 -0
  15. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/core/module_base.py +0 -0
  16. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/core/state.py +0 -0
  17. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/core/xpander_api_client.py +0 -0
  18. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/exceptions/__init__.py +0 -0
  19. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/exceptions/module_exception.py +0 -0
  20. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/models/__init__.py +0 -0
  21. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/models/configuration.py +0 -0
  22. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/models/events.py +0 -0
  23. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/models/frameworks.py +0 -0
  24. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/models/shared.py +0 -0
  25. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/models/user.py +0 -0
  26. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/__init__.py +0 -0
  27. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/agents/__init__.py +0 -0
  28. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/agents/agents_module.py +0 -0
  29. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/agents/models/__init__.py +0 -0
  30. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/agents/models/agent.py +0 -0
  31. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/agents/models/agent_list.py +0 -0
  32. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/agents/models/knowledge_bases.py +0 -0
  33. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/agents/sub_modules/__init__.py +0 -0
  34. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/agents/sub_modules/agent.py +0 -0
  35. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/agents/utils/__init__.py +0 -0
  36. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/agents/utils/generic.py +0 -0
  37. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/backend/__init__.py +0 -0
  38. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/backend/backend_module.py +0 -0
  39. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/backend/frameworks/__init__.py +0 -0
  40. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/backend/frameworks/agno.py +0 -0
  41. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/backend/frameworks/dispatch.py +0 -0
  42. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/backend/utils/__init__.py +0 -0
  43. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/backend/utils/mcp_oauth.py +0 -0
  44. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/events/__init__.py +0 -0
  45. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/events/decorators/__init__.py +0 -0
  46. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/events/decorators/on_boot.py +0 -0
  47. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/events/decorators/on_shutdown.py +0 -0
  48. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/events/decorators/on_task.py +0 -0
  49. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/events/events_module.py +0 -0
  50. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/events/models/__init__.py +0 -0
  51. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/events/models/deployments.py +0 -0
  52. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/events/models/events.py +0 -0
  53. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/events/utils/__init__.py +0 -0
  54. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/events/utils/generic.py +0 -0
  55. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/events/utils/git_init.py +0 -0
  56. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/knowledge_bases/__init__.py +0 -0
  57. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/knowledge_bases/knowledge_bases_module.py +0 -0
  58. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/knowledge_bases/models/__init__.py +0 -0
  59. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/knowledge_bases/models/knowledge_bases.py +0 -0
  60. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/knowledge_bases/sub_modules/__init__.py +0 -0
  61. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/knowledge_bases/sub_modules/knowledge_base.py +0 -0
  62. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/knowledge_bases/sub_modules/knowledge_base_document_item.py +0 -0
  63. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/knowledge_bases/utils/__init__.py +0 -0
  64. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tasks/__init__.py +0 -0
  65. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tasks/models/__init__.py +0 -0
  66. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tasks/models/task.py +0 -0
  67. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tasks/models/tasks_list.py +0 -0
  68. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tasks/sub_modules/__init__.py +0 -0
  69. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tasks/tasks_module.py +0 -0
  70. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tasks/utils/__init__.py +0 -0
  71. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tasks/utils/files.py +0 -0
  72. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tools_repository/__init__.py +0 -0
  73. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tools_repository/decorators/__init__.py +0 -0
  74. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tools_repository/decorators/register_tool.py +0 -0
  75. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tools_repository/models/__init__.py +0 -0
  76. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tools_repository/models/mcp.py +0 -0
  77. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tools_repository/models/tool_invocation_result.py +0 -0
  78. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tools_repository/sub_modules/__init__.py +0 -0
  79. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tools_repository/sub_modules/tool.py +0 -0
  80. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tools_repository/tools_repository_module.py +0 -0
  81. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tools_repository/utils/__init__.py +0 -0
  82. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tools_repository/utils/generic.py +0 -0
  83. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tools_repository/utils/local_tools.py +0 -0
  84. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/modules/tools_repository/utils/schemas.py +0 -0
  85. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/utils/__init__.py +0 -0
  86. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/utils/env.py +0 -0
  87. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/utils/event_loop.py +0 -0
  88. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk/utils/tools.py +0 -0
  89. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk.egg-info/dependency_links.txt +0 -0
  90. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk.egg-info/requires.txt +0 -0
  91. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/src/xpander_sdk.egg-info/top_level.txt +0 -0
  92. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/tests/test_agents_module.py +0 -0
  93. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/tests/test_api_client.py +0 -0
  94. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/tests/test_backend_module.py +0 -0
  95. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/tests/test_boot_shutdown_handlers.py +0 -0
  96. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/tests/test_configuration.py +0 -0
  97. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/tests/test_knowledge_bases_module.py +0 -0
  98. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/tests/test_tasks_module.py +0 -0
  99. {xpander_sdk-2.0.150 → xpander_sdk-2.0.151}/tests/test_tools_repository.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xpander-sdk
3
- Version: 2.0.150
3
+ Version: 2.0.151
4
4
  Summary: xpander.ai Backend-as-a-service for AI Agents - SDK
5
5
  Home-page: https://www.xpander.ai
6
6
  Author: xpanderAI
@@ -131,6 +131,11 @@ tasks = Tasks(configuration=config)
131
131
  task = await tasks.aget("task-id")
132
132
  await task.aset_status(AgentExecutionStatus.Running)
133
133
  await task.asave()
134
+
135
+ # Retrieve task activity log
136
+ activity_log = await task.aget_activity_log()
137
+ for message in activity_log.messages:
138
+ print(f"{message.role}: {message.content.text}")
134
139
  ```
135
140
 
136
141
  ### 4. Tools Integration
@@ -287,6 +292,35 @@ async for event in task.aevents():
287
292
  print(f"Event Data: {event.data}")
288
293
  ```
289
294
 
295
+ ### Task Activity Monitoring
296
+
297
+ ```python
298
+ from xpander_sdk import Task
299
+
300
+ # Load a completed task
301
+ task = await Task.aload("task-id")
302
+
303
+ # Get detailed activity log
304
+ activity_log = await task.aget_activity_log()
305
+
306
+ # Analyze messages between user and agent
307
+ for message in activity_log.messages:
308
+ if hasattr(message, 'role'):
309
+ print(f"{message.role}: {message.content.text}")
310
+ elif hasattr(message, 'tool_name'):
311
+ # Tool call
312
+ print(f"Tool: {message.tool_name}")
313
+ print(f"Payload: {message.payload}")
314
+ print(f"Result: {message.result}")
315
+ elif hasattr(message, 'type'):
316
+ # Reasoning step
317
+ print(f"Reasoning ({message.type}): {message.thought}")
318
+
319
+ # Synchronous version
320
+ task = Task.load("task-id")
321
+ activity_log = task.get_activity_log()
322
+ ```
323
+
290
324
  ### Local Task Testing
291
325
 
292
326
  ```python
@@ -82,6 +82,11 @@ tasks = Tasks(configuration=config)
82
82
  task = await tasks.aget("task-id")
83
83
  await task.aset_status(AgentExecutionStatus.Running)
84
84
  await task.asave()
85
+
86
+ # Retrieve task activity log
87
+ activity_log = await task.aget_activity_log()
88
+ for message in activity_log.messages:
89
+ print(f"{message.role}: {message.content.text}")
85
90
  ```
86
91
 
87
92
  ### 4. Tools Integration
@@ -238,6 +243,35 @@ async for event in task.aevents():
238
243
  print(f"Event Data: {event.data}")
239
244
  ```
240
245
 
246
+ ### Task Activity Monitoring
247
+
248
+ ```python
249
+ from xpander_sdk import Task
250
+
251
+ # Load a completed task
252
+ task = await Task.aload("task-id")
253
+
254
+ # Get detailed activity log
255
+ activity_log = await task.aget_activity_log()
256
+
257
+ # Analyze messages between user and agent
258
+ for message in activity_log.messages:
259
+ if hasattr(message, 'role'):
260
+ print(f"{message.role}: {message.content.text}")
261
+ elif hasattr(message, 'tool_name'):
262
+ # Tool call
263
+ print(f"Tool: {message.tool_name}")
264
+ print(f"Payload: {message.payload}")
265
+ print(f"Result: {message.result}")
266
+ elif hasattr(message, 'type'):
267
+ # Reasoning step
268
+ print(f"Reasoning ({message.type}): {message.thought}")
269
+
270
+ # Synchronous version
271
+ task = Task.load("task-id")
272
+ activity_log = task.get_activity_log()
273
+ ```
274
+
241
275
  ### Local Task Testing
242
276
 
243
277
  ```python
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setup(
7
7
  name="xpander-sdk",
8
- version="2.0.150",
8
+ version="2.0.151",
9
9
  author="xpanderAI",
10
10
  author_email="dev@xpander.ai",
11
11
  description="xpander.ai Backend-as-a-service for AI Agents - SDK",
@@ -35,6 +35,7 @@ and deleting resources.
35
35
  ListTasks = "/agent-execution/executions/history/{agent_id}"
36
36
  ListUserTasks = "/agent-execution/executions/history/user/{user_id}"
37
37
  GetTask = "/agent-execution/{task_id}/status"
38
+ GetTaskActivityLog = "/activity/{agent_id}/{task_id}"
38
39
  TaskCrud = "/agent-execution/{agent_or_task_id}"
39
40
  UpdateTask = "/agent-execution/{task_id}/update"
40
41
  ReportExternalTask = "/agent-execution/{agent_id}/report_task"
@@ -0,0 +1,65 @@
1
+ from datetime import datetime
2
+ from enum import Enum
3
+ from typing import Any, List, Literal, Optional, Union
4
+
5
+ from xpander_sdk.models.events import ToolCallRequestReasoning
6
+ from xpander_sdk.models.shared import XPanderSharedModel
7
+ from xpander_sdk.models.user import User
8
+ from xpander_sdk.modules.tools_repository.models.mcp import MCPOAuthGetTokenResponse
9
+
10
+ class AgentActivityThreadMessageContent(XPanderSharedModel):
11
+ text: Optional[str] = None
12
+ files: Optional[List[str]] = []
13
+
14
+ class AgentActivityThreadMessage(XPanderSharedModel):
15
+ id: str
16
+ created_at: datetime
17
+ role: Literal["user","agent"]
18
+ content: AgentActivityThreadMessageContent
19
+
20
+ class AgentActivityThreadToolCall(XPanderSharedModel):
21
+ id: str
22
+ created_at: datetime
23
+ tool_name: str
24
+ payload: Any
25
+ is_error: Optional[bool] = False
26
+ reasoning: Optional[ToolCallRequestReasoning] = None
27
+ result: Optional[Any] = None
28
+
29
+ class AgentActivityThreadReasoningType(str, Enum):
30
+ Think = "think"
31
+ Analyze = "analyze"
32
+
33
+ class AgentActivityThreadReasoning(XPanderSharedModel):
34
+ id: str
35
+ created_at: datetime
36
+ type: AgentActivityThreadReasoningType
37
+ title: str
38
+ confidence: float
39
+ thought: Optional[str] = None
40
+ action: Optional[str] = None
41
+ result: Optional[str] = None
42
+ analysis: Optional[str] = None
43
+
44
+ class AgentActivityThreadSubAgentTrigger(XPanderSharedModel):
45
+ id: str
46
+ created_at: datetime
47
+ agent_id: str
48
+ query: Optional[str] = None
49
+ files: Optional[List[str]] = []
50
+ reasoning: ToolCallRequestReasoning
51
+
52
+ class AgentActivityThreadAuth(MCPOAuthGetTokenResponse):
53
+ id: str
54
+ created_at: datetime
55
+
56
+ AgentActivityThreadMessageType = Union[AgentActivityThreadMessage, AgentActivityThreadToolCall, AgentActivityThreadReasoning, AgentActivityThreadSubAgentTrigger, AgentActivityThreadAuth]
57
+ class AgentActivityThread(XPanderSharedModel):
58
+ id: str
59
+ created_at: datetime
60
+ messages: List[AgentActivityThreadMessageType]
61
+ user: Optional[User] = None
62
+
63
+ class AgentActivityThreadListItem(XPanderSharedModel):
64
+ id: str
65
+ created_at: datetime
@@ -28,7 +28,17 @@ Typical usage example:
28
28
  """
29
29
 
30
30
  from datetime import datetime
31
- from typing import Any, AsyncGenerator, Dict, Generator, List, Optional, Type, TypeVar, Union
31
+ from typing import (
32
+ Any,
33
+ AsyncGenerator,
34
+ Dict,
35
+ Generator,
36
+ List,
37
+ Optional,
38
+ Type,
39
+ TypeVar,
40
+ Union,
41
+ )
32
42
  from httpx import HTTPStatusError
33
43
  import httpx
34
44
  import json
@@ -37,13 +47,20 @@ from httpx_sse import aconnect_sse
37
47
  from xpander_sdk.consts.api_routes import APIRoute
38
48
  from xpander_sdk.core.xpander_api_client import APIClient
39
49
  from xpander_sdk.exceptions.module_exception import ModuleException
50
+ from xpander_sdk.models.activity import AgentActivityThread
40
51
  from xpander_sdk.models.configuration import Configuration
41
52
  from xpander_sdk.models.events import (
42
53
  TaskUpdateEventType,
43
54
  ToolCallRequest,
44
55
  ToolCallResult,
45
56
  )
46
- from xpander_sdk.models.shared import ExecutionTokens, OutputFormat, ThinkMode, Tokens, XPanderSharedModel
57
+ from xpander_sdk.models.shared import (
58
+ ExecutionTokens,
59
+ OutputFormat,
60
+ ThinkMode,
61
+ Tokens,
62
+ XPanderSharedModel,
63
+ )
47
64
  from xpander_sdk.modules.events.utils.generic import get_events_base, get_events_headers
48
65
  from xpander_sdk.modules.tasks.models.task import (
49
66
  AgentExecutionInput,
@@ -51,16 +68,25 @@ from xpander_sdk.modules.tasks.models.task import (
51
68
  HumanInTheLoop,
52
69
  ExecutionMetricsReport,
53
70
  PendingECARequest,
54
- TaskReportRequest
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,
55
81
  )
56
- from xpander_sdk.modules.tasks.utils.files import categorize_files, fetch_urls, fetch_file
57
- from xpander_sdk.modules.tools_repository.models.mcp import MCPOAuthGetTokenResponse, MCPServerDetails
58
82
  from xpander_sdk.utils.event_loop import run_sync
59
83
 
60
84
  # Type variable for Task class methods
61
85
  T = TypeVar("T", bound="Task")
62
86
 
63
- TaskUpdateEventData = Union[T, ToolCallRequest, ToolCallResult, MCPOAuthGetTokenResponse]
87
+ TaskUpdateEventData = Union[
88
+ T, ToolCallRequest, ToolCallResult, MCPOAuthGetTokenResponse
89
+ ]
64
90
 
65
91
 
66
92
  class TaskUpdateEvent(XPanderSharedModel):
@@ -112,7 +138,7 @@ class Task(XPanderSharedModel):
112
138
  >>> task = Task.load(task_id="task_123")
113
139
  >>> task.set_status(AgentExecutionStatus.Running)
114
140
  >>> task.save()
115
- >>>
141
+ >>>
116
142
  >>> # Get files for Agno integration
117
143
  >>> files = task.get_files() # PDF files as Agno File objects
118
144
  >>> images = task.get_images() # Image files as Agno Image objects
@@ -148,13 +174,13 @@ class Task(XPanderSharedModel):
148
174
  output_schema: Optional[Dict] = None
149
175
  events_streaming: Optional[bool] = False
150
176
  additional_context: Optional[str] = None
151
- expected_output: Optional[str] = None,
152
- mcp_servers: Optional[List[MCPServerDetails]] = [],
153
- triggering_agent_id: Optional[str] = None,
154
- title: 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,)
155
181
  think_mode: Optional[ThinkMode] = ThinkMode.Default
156
182
  disable_attachment_injection: Optional[bool] = False
157
-
183
+
158
184
  # metrics
159
185
  tokens: Optional[Tokens] = None
160
186
  used_tools: Optional[List[str]] = []
@@ -202,7 +228,6 @@ class Task(XPanderSharedModel):
202
228
  self.__dict__.update(new_obj.__dict__)
203
229
  return self
204
230
 
205
-
206
231
  def reload(self):
207
232
  """
208
233
  Reload the current object synchronously.
@@ -217,7 +242,6 @@ class Task(XPanderSharedModel):
217
242
  """
218
243
  run_sync(self.areload())
219
244
 
220
-
221
245
  @classmethod
222
246
  async def aload(
223
247
  cls: Type[T], task_id: str, configuration: Optional[Configuration] = None
@@ -243,7 +267,9 @@ class Task(XPanderSharedModel):
243
267
  response_data = await client.make_request(
244
268
  path=APIRoute.GetTask.format(task_id=task_id)
245
269
  )
246
- task = cls.model_validate({**response_data, "configuration": configuration or Configuration()})
270
+ task = cls.model_validate(
271
+ {**response_data, "configuration": configuration or Configuration()}
272
+ )
247
273
  return task
248
274
  except HTTPStatusError as e:
249
275
  raise ModuleException(
@@ -382,15 +408,15 @@ class Task(XPanderSharedModel):
382
408
  def get_files(self) -> list[Any]:
383
409
  """
384
410
  Get PDF files from task input, formatted for Agno integration.
385
-
411
+
386
412
  Returns PDF files as Agno File objects when the Agno framework is available,
387
413
  or as URL strings otherwise. This method is designed for seamless integration
388
414
  with Agno agents.
389
-
415
+
390
416
  Returns:
391
417
  list[Any]: List of File objects (when Agno is available) or URL strings.
392
418
  Returns empty list if no PDF files are present in task input.
393
-
419
+
394
420
  Example:
395
421
  >>> files = task.get_files()
396
422
  >>> result = await agno_agent.arun(
@@ -398,33 +424,34 @@ class Task(XPanderSharedModel):
398
424
  ... files=files
399
425
  ... )
400
426
  """
401
-
427
+
402
428
  if not self.input.files or len(self.input.files) == 0:
403
429
  return []
404
-
430
+
405
431
  categorized_files = categorize_files(file_urls=self.input.files)
406
-
432
+
407
433
  if not categorized_files.pdfs or len(categorized_files.pdfs) == 0:
408
434
  return []
409
435
 
410
436
  try:
411
- from agno.media import File # test import
437
+ from agno.media import File # test import
438
+
412
439
  return [fetch_file(url=url) for url in categorized_files.pdfs]
413
440
  except Exception:
414
441
  return categorized_files.pdfs
415
-
442
+
416
443
  def get_images(self) -> list[Any]:
417
444
  """
418
445
  Get image files from task input, formatted for Agno integration.
419
-
446
+
420
447
  Returns image files as Agno Image objects when the Agno framework is available,
421
448
  or as URL strings otherwise. This method is designed for seamless integration
422
449
  with Agno agents that support image processing.
423
-
450
+
424
451
  Returns:
425
452
  list[Any]: List of Image objects (when Agno is available) or URL strings.
426
453
  Returns empty list if no image files are present in task input.
427
-
454
+
428
455
  Example:
429
456
  >>> images = task.get_images()
430
457
  >>> result = await agno_agent.arun(
@@ -434,30 +461,31 @@ class Task(XPanderSharedModel):
434
461
  """
435
462
  if not self.input.files or len(self.input.files) == 0:
436
463
  return []
437
-
464
+
438
465
  categorized_files = categorize_files(file_urls=self.input.files)
439
-
466
+
440
467
  if not categorized_files.images or len(categorized_files.images) == 0:
441
468
  return []
442
469
 
443
470
  try:
444
471
  from agno.media import Image
472
+
445
473
  return [Image(url=url) for url in categorized_files.images]
446
474
  except Exception:
447
475
  return categorized_files.images
448
-
476
+
449
477
  def get_human_readable_files(self) -> list[Any]:
450
478
  """
451
479
  Get human-readable files from task input with their content.
452
-
480
+
453
481
  Returns text-based files (like .txt, .csv, .json, .py, etc.) with their content
454
482
  fetched and parsed. This method is automatically used by to_message() to include
455
483
  file contents in the task message.
456
-
484
+
457
485
  Returns:
458
486
  list[dict[str, str]]: List of dictionaries with 'url' and 'content' keys.
459
487
  Returns empty list if no human-readable files are present.
460
-
488
+
461
489
  Example:
462
490
  >>> readable_files = task.get_human_readable_files()
463
491
  >>> for file_data in readable_files:
@@ -466,14 +494,19 @@ class Task(XPanderSharedModel):
466
494
  """
467
495
  if not self.input.files or len(self.input.files) == 0:
468
496
  return []
469
-
497
+
470
498
  categorized_files = categorize_files(file_urls=self.input.files)
471
-
499
+
472
500
  if not categorized_files.files or len(categorized_files.files) == 0:
473
501
  return []
474
502
 
475
- return run_sync(fetch_urls(urls=categorized_files.files, disable_attachment_injection=self.disable_attachment_injection))
476
-
503
+ return run_sync(
504
+ fetch_urls(
505
+ urls=categorized_files.files,
506
+ disable_attachment_injection=self.disable_attachment_injection,
507
+ )
508
+ )
509
+
477
510
  def to_message(self) -> str:
478
511
  """
479
512
  Converts the input data into a formatted message string.
@@ -495,7 +528,7 @@ class Task(XPanderSharedModel):
495
528
  if len(message) != 0:
496
529
  message += "\n"
497
530
  message += "Files: " + (", ".join(self.input.files))
498
-
531
+
499
532
  # append human readable content like csv and such
500
533
  readable_files = self.get_human_readable_files()
501
534
  if readable_files and len(readable_files) != 0:
@@ -505,6 +538,70 @@ class Task(XPanderSharedModel):
505
538
 
506
539
  return message
507
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
+
508
605
  async def aevents(self) -> AsyncGenerator[TaskUpdateEvent, None]:
509
606
  """
510
607
  Asynchronously streams task events.
@@ -541,10 +638,12 @@ class Task(XPanderSharedModel):
541
638
  json_event_data: dict = json.loads(event.data)
542
639
  if json_event_data.get("type", None).startswith("task"):
543
640
  task_data = json_event_data.get("data")
544
- json_event_data.pop("data") # delete data
641
+ json_event_data.pop("data") # delete data
545
642
  yield TaskUpdateEvent(
546
643
  **json_event_data,
547
- data=Task(**task_data,configuration=self.configuration)
644
+ data=Task(
645
+ **task_data, configuration=self.configuration
646
+ ),
548
647
  )
549
648
  continue
550
649
  except Exception:
@@ -585,16 +684,13 @@ class Task(XPanderSharedModel):
585
684
 
586
685
  while queue:
587
686
  yield queue.pop(0)
588
-
589
- async def areport_metrics(
590
- self,
591
- configuration: Optional[Configuration] = None
592
- ):
687
+
688
+ async def areport_metrics(self, configuration: Optional[Configuration] = None):
593
689
  """
594
690
  Asynchronously report LLM task metrics to xpander.ai.
595
691
 
596
692
  Args:
597
- configuration (Optional[Configuration], optional):
693
+ configuration (Optional[Configuration], optional):
598
694
  API client configuration. If not provided, a new instance is created. Defaults to None.
599
695
 
600
696
  Raises:
@@ -606,10 +702,10 @@ class Task(XPanderSharedModel):
606
702
  try:
607
703
  configuration = configuration or Configuration()
608
704
  client = APIClient(configuration=configuration)
609
-
705
+
610
706
  if not self.tokens:
611
707
  raise ValueError("tokens must be provided. task.tokens = Tokens()")
612
-
708
+
613
709
  task_report_request = ExecutionMetricsReport(
614
710
  execution_id=self.id,
615
711
  source=self.source,
@@ -621,38 +717,30 @@ class Task(XPanderSharedModel):
621
717
  ai_model="xpander",
622
718
  api_calls_made=self.used_tools,
623
719
  result=self.result or None,
624
- llm_tokens=ExecutionTokens(worker=self.tokens)
720
+ llm_tokens=ExecutionTokens(worker=self.tokens),
625
721
  )
626
722
 
627
723
  await client.make_request(
628
- path=APIRoute.ReportExecutionMetrics.format(
629
- agent_id=self.agent_id
630
- ),
724
+ path=APIRoute.ReportExecutionMetrics.format(agent_id=self.agent_id),
631
725
  method="POST",
632
726
  payload=task_report_request.model_dump_safe(),
633
727
  )
634
728
 
635
729
  except HTTPStatusError as e:
636
730
  raise ModuleException(
637
- status_code=e.response.status_code,
638
- description=e.response.text
731
+ status_code=e.response.status_code, description=e.response.text
639
732
  )
640
733
  except Exception as e:
641
734
  raise ModuleException(
642
- status_code=500,
643
- description=f"Failed to report metrics - {str(e)}"
735
+ status_code=500, description=f"Failed to report metrics - {str(e)}"
644
736
  )
645
737
 
646
-
647
- def report_metrics(
648
- self,
649
- configuration: Optional[Configuration] = None
650
- ):
738
+ def report_metrics(self, configuration: Optional[Configuration] = None):
651
739
  """
652
740
  Report LLM task metrics to xpander.ai.
653
741
 
654
742
  Args:
655
- configuration (Optional[Configuration], optional):
743
+ configuration (Optional[Configuration], optional):
656
744
  API client configuration. If not provided, a new instance is created. Defaults to None.
657
745
 
658
746
  Raises:
@@ -661,15 +749,11 @@ class Task(XPanderSharedModel):
661
749
  Returns:
662
750
  None
663
751
  """
664
- return run_sync(
665
- self.areport_metrics(
666
- configuration=configuration
667
- )
668
- )
669
-
752
+ return run_sync(self.areport_metrics(configuration=configuration))
753
+
670
754
  @classmethod
671
755
  async def areport_external_task(
672
- cls: Type[T],
756
+ cls: Type[T],
673
757
  configuration: Optional[Configuration] = None,
674
758
  agent_id: Optional[str] = None,
675
759
  id: Optional[str] = None,
@@ -679,7 +763,7 @@ class Task(XPanderSharedModel):
679
763
  is_success: Optional[bool] = True,
680
764
  result: Optional[str] = None,
681
765
  duration: Optional[float] = 0,
682
- used_tools: Optional[List[str]] = []
766
+ used_tools: Optional[List[str]] = [],
683
767
  ) -> T:
684
768
  """
685
769
  Asynchronously reports an external task to the xpander.ai backend.
@@ -687,7 +771,7 @@ class Task(XPanderSharedModel):
687
771
  This method is used to report the result of a task that was executed
688
772
  externally (outside the xpander.ai platform). It submits execution details,
689
773
  including inputs, outputs, success status, and resource usage, to the backend.
690
-
774
+
691
775
  Args:
692
776
  configuration (Optional[Configuration]): Optional configuration for API calls.
693
777
  agent_id (Optional[str]): Identifier of the agent associated with the task.
@@ -699,13 +783,13 @@ class Task(XPanderSharedModel):
699
783
  result (Optional[str]): String representation of the final result.
700
784
  duration (Optional[float]): Task execution duration, in seconds. Defaults to 0.
701
785
  used_tools (Optional[List[str]]): List of tools used during the execution. Defaults to empty list.
702
-
786
+
703
787
  Returns:
704
788
  T: Instance of the Task class, representing the reported task.
705
-
789
+
706
790
  Raises:
707
791
  ModuleException: Raised on backend or network errors.
708
-
792
+
709
793
  Example:
710
794
  >>> task = await Task.areport_external_task(
711
795
  ... agent_id="agent_xyz",
@@ -725,7 +809,7 @@ class Task(XPanderSharedModel):
725
809
  is_success=is_success,
726
810
  result=result,
727
811
  duration=duration,
728
- used_tools=used_tools
812
+ used_tools=used_tools,
729
813
  )
730
814
  response_data = await client.make_request(
731
815
  path=APIRoute.ReportExternalTask.format(agent_id=agent_id),
@@ -739,12 +823,13 @@ class Task(XPanderSharedModel):
739
823
  )
740
824
  except Exception as e:
741
825
  raise ModuleException(
742
- status_code=500, description=f"Failed to report external task - {str(e)}"
826
+ status_code=500,
827
+ description=f"Failed to report external task - {str(e)}",
743
828
  )
744
829
 
745
830
  @classmethod
746
831
  def report_external_task(
747
- cls: Type[T],
832
+ cls: Type[T],
748
833
  configuration: Optional[Configuration] = None,
749
834
  agent_id: Optional[str] = None,
750
835
  id: Optional[str] = None,
@@ -754,7 +839,7 @@ class Task(XPanderSharedModel):
754
839
  is_success: Optional[bool] = True,
755
840
  result: Optional[str] = None,
756
841
  duration: Optional[float] = 0,
757
- used_tools: Optional[List[str]] = []
842
+ used_tools: Optional[List[str]] = [],
758
843
  ) -> T:
759
844
  """
760
845
  Synchronously reports an external task to the xpander.ai backend.
@@ -799,4 +884,4 @@ class Task(XPanderSharedModel):
799
884
  duration=duration,
800
885
  used_tools=used_tools,
801
886
  )
802
- )
887
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xpander-sdk
3
- Version: 2.0.150
3
+ Version: 2.0.151
4
4
  Summary: xpander.ai Backend-as-a-service for AI Agents - SDK
5
5
  Home-page: https://www.xpander.ai
6
6
  Author: xpanderAI
@@ -131,6 +131,11 @@ tasks = Tasks(configuration=config)
131
131
  task = await tasks.aget("task-id")
132
132
  await task.aset_status(AgentExecutionStatus.Running)
133
133
  await task.asave()
134
+
135
+ # Retrieve task activity log
136
+ activity_log = await task.aget_activity_log()
137
+ for message in activity_log.messages:
138
+ print(f"{message.role}: {message.content.text}")
134
139
  ```
135
140
 
136
141
  ### 4. Tools Integration
@@ -287,6 +292,35 @@ async for event in task.aevents():
287
292
  print(f"Event Data: {event.data}")
288
293
  ```
289
294
 
295
+ ### Task Activity Monitoring
296
+
297
+ ```python
298
+ from xpander_sdk import Task
299
+
300
+ # Load a completed task
301
+ task = await Task.aload("task-id")
302
+
303
+ # Get detailed activity log
304
+ activity_log = await task.aget_activity_log()
305
+
306
+ # Analyze messages between user and agent
307
+ for message in activity_log.messages:
308
+ if hasattr(message, 'role'):
309
+ print(f"{message.role}: {message.content.text}")
310
+ elif hasattr(message, 'tool_name'):
311
+ # Tool call
312
+ print(f"Tool: {message.tool_name}")
313
+ print(f"Payload: {message.payload}")
314
+ print(f"Result: {message.result}")
315
+ elif hasattr(message, 'type'):
316
+ # Reasoning step
317
+ print(f"Reasoning ({message.type}): {message.thought}")
318
+
319
+ # Synchronous version
320
+ task = Task.load("task-id")
321
+ activity_log = task.get_activity_log()
322
+ ```
323
+
290
324
  ### Local Task Testing
291
325
 
292
326
  ```python
@@ -17,6 +17,7 @@ src/xpander_sdk/core/xpander_api_client.py
17
17
  src/xpander_sdk/exceptions/__init__.py
18
18
  src/xpander_sdk/exceptions/module_exception.py
19
19
  src/xpander_sdk/models/__init__.py
20
+ src/xpander_sdk/models/activity.py
20
21
  src/xpander_sdk/models/configuration.py
21
22
  src/xpander_sdk/models/events.py
22
23
  src/xpander_sdk/models/frameworks.py
File without changes
File without changes