xpander-sdk 2.0.161__py3-none-any.whl → 2.0.192__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.
Files changed (33) hide show
  1. xpander_sdk/__init__.py +6 -0
  2. xpander_sdk/consts/api_routes.py +8 -0
  3. xpander_sdk/models/compactization.py +112 -0
  4. xpander_sdk/models/events.py +3 -0
  5. xpander_sdk/models/frameworks.py +2 -2
  6. xpander_sdk/models/generic.py +27 -0
  7. xpander_sdk/models/notifications.py +98 -0
  8. xpander_sdk/models/orchestrations.py +271 -0
  9. xpander_sdk/modules/agents/models/agent.py +7 -4
  10. xpander_sdk/modules/agents/sub_modules/agent.py +18 -10
  11. xpander_sdk/modules/backend/__init__.py +8 -0
  12. xpander_sdk/modules/backend/backend_module.py +47 -2
  13. xpander_sdk/modules/backend/decorators/__init__.py +7 -0
  14. xpander_sdk/modules/backend/decorators/on_auth_event.py +131 -0
  15. xpander_sdk/modules/backend/events_registry.py +172 -0
  16. xpander_sdk/modules/backend/frameworks/agno.py +176 -54
  17. xpander_sdk/modules/backend/frameworks/dispatch.py +3 -1
  18. xpander_sdk/modules/backend/utils/mcp_oauth.py +36 -24
  19. xpander_sdk/modules/events/decorators/__init__.py +3 -0
  20. xpander_sdk/modules/events/decorators/on_tool.py +384 -0
  21. xpander_sdk/modules/events/events_module.py +9 -3
  22. xpander_sdk/modules/tasks/models/task.py +3 -14
  23. xpander_sdk/modules/tasks/sub_modules/task.py +54 -20
  24. xpander_sdk/modules/tools_repository/sub_modules/tool.py +46 -15
  25. xpander_sdk/modules/tools_repository/utils/generic.py +3 -0
  26. xpander_sdk/utils/agents/__init__.py +0 -0
  27. xpander_sdk/utils/agents/compactization_agent.py +257 -0
  28. xpander_sdk/utils/generic.py +5 -0
  29. {xpander_sdk-2.0.161.dist-info → xpander_sdk-2.0.192.dist-info}/METADATA +97 -13
  30. {xpander_sdk-2.0.161.dist-info → xpander_sdk-2.0.192.dist-info}/RECORD +33 -22
  31. {xpander_sdk-2.0.161.dist-info → xpander_sdk-2.0.192.dist-info}/WHEEL +0 -0
  32. {xpander_sdk-2.0.161.dist-info → xpander_sdk-2.0.192.dist-info}/licenses/LICENSE +0 -0
  33. {xpander_sdk-2.0.161.dist-info → xpander_sdk-2.0.192.dist-info}/top_level.txt +0 -0
@@ -41,6 +41,7 @@ from xpander_sdk.modules.tools_repository.utils.schemas import (
41
41
  schema_enforcement_block_and_descriptions,
42
42
  )
43
43
  from xpander_sdk.utils.event_loop import run_sync
44
+ from xpander_sdk.modules.events.decorators.on_tool import ToolHooksRegistry
44
45
 
45
46
 
46
47
  class Tool(XPanderSharedModel):
@@ -376,6 +377,15 @@ class Tool(XPanderSharedModel):
376
377
  task_id=task_id,
377
378
  )
378
379
 
380
+ # Execute before hooks
381
+ await ToolHooksRegistry.execute_before_hooks(
382
+ tool=self,
383
+ payload=payload,
384
+ payload_extension=payload_extension,
385
+ tool_call_id=tool_call_id,
386
+ agent_version=agent_version
387
+ )
388
+
379
389
  try:
380
390
  if self.schema and payload:
381
391
  try:
@@ -386,32 +396,43 @@ class Tool(XPanderSharedModel):
386
396
  ) from validation_error
387
397
 
388
398
  if self.is_local:
389
- await self.agraph_preflight_check(
390
- agent_id=agent_id,
391
- agent_version=agent_version,
392
- configuration=configuration,
393
- task_id=task_id,
394
- )
395
-
396
399
  if self.fn is None:
397
400
  raise RuntimeError(
398
401
  f"No local function provided for this tool ({self.id})."
399
402
  )
400
403
 
401
404
  result = await invoke_local_fn(fn=self.fn, payload=payload)
405
+
406
+ await self.agraph_preflight_check(
407
+ agent_id=agent_id,
408
+ agent_version=agent_version,
409
+ configuration=configuration,
410
+ task_id=task_id,
411
+ payload={"input": payload, "output": result.model_dump() if isinstance(result, BaseModel) else result}
412
+ )
413
+
402
414
  tool_invocation_result.result = result
403
415
  tool_invocation_result.is_success = True
404
- return tool_invocation_result
405
-
406
- tool_invocation_result.result = await self.acall_remote_tool(
407
- agent_id=agent_id,
408
- agent_version=agent_version,
416
+ else:
417
+ tool_invocation_result.result = await self.acall_remote_tool(
418
+ agent_id=agent_id,
419
+ agent_version=agent_version,
420
+ payload=payload,
421
+ payload_extension=payload_extension,
422
+ configuration=configuration,
423
+ task_id=task_id,
424
+ )
425
+ tool_invocation_result.is_success = True
426
+
427
+ # Execute after hooks on success
428
+ await ToolHooksRegistry.execute_after_hooks(
429
+ tool=self,
409
430
  payload=payload,
410
431
  payload_extension=payload_extension,
411
- configuration=configuration,
412
- task_id=task_id,
432
+ tool_call_id=tool_call_id,
433
+ agent_version=agent_version,
434
+ result=tool_invocation_result.result
413
435
  )
414
- tool_invocation_result.is_success = True
415
436
 
416
437
  except Exception as e:
417
438
  tool_invocation_result.is_error = True
@@ -421,6 +442,16 @@ class Tool(XPanderSharedModel):
421
442
  else:
422
443
  tool_invocation_result.status_code = 500
423
444
  tool_invocation_result.result = str(e)
445
+
446
+ # Execute error hooks on failure
447
+ await ToolHooksRegistry.execute_error_hooks(
448
+ tool=self,
449
+ payload=payload,
450
+ payload_extension=payload_extension,
451
+ tool_call_id=tool_call_id,
452
+ agent_version=agent_version,
453
+ error=e
454
+ )
424
455
 
425
456
  return tool_invocation_result
426
457
 
@@ -38,6 +38,9 @@ def json_type_to_python(json_type: str, prop_schema: dict = None):
38
38
  item_type = json_type_to_python(items.get("type"), items)
39
39
  return List[item_type]
40
40
 
41
+ if isinstance(json_type, list) and len(json_type) > 1:
42
+ json_type = next((t for t in json_type if t != "null"), None)
43
+
41
44
  return {
42
45
  "string": str,
43
46
  "integer": int,
File without changes
@@ -0,0 +1,257 @@
1
+ from typing import TYPE_CHECKING, List, Union
2
+ from agno.agent import Agent as AgnoAgent
3
+ from loguru import logger
4
+ import json
5
+ from xpander_sdk.models.compactization import TaskCompactizationEvent, TaskCompactizationOutput, TaskCompactizationInput, TaskCompactizationRetryEvent
6
+ from xpander_sdk.models.deep_planning import DeepPlanningItem
7
+ from xpander_sdk.models.events import TaskUpdateEventType
8
+ from xpander_sdk.models.frameworks import Framework
9
+ from xpander_sdk.models.shared import Tokens
10
+ from xpander_sdk.modules.agents.agents_module import Agents
11
+ from xpander_sdk.modules.backend.backend_module import Backend
12
+ from xpander_sdk.modules.backend.utils.mcp_oauth import push_event
13
+ from xpander_sdk.modules.tasks.sub_modules.task import TaskUpdateEvent
14
+ from xpander_sdk.utils.event_loop import run_sync
15
+
16
+ if TYPE_CHECKING:
17
+ from xpander_sdk.modules.tasks.sub_modules.task import Task
18
+
19
+ def run_task_compactization(message: str, task: "Task", uncompleted_tasks: List[DeepPlanningItem]) -> Union[str, TaskCompactizationOutput]:
20
+ try:
21
+
22
+ # report retry event
23
+ try:
24
+ run_sync(
25
+ push_event(
26
+ task=task,
27
+ event=TaskCompactizationEvent(type="retry", data=TaskCompactizationRetryEvent(is_retry=True)),
28
+ event_type=TaskUpdateEventType.TaskCompactization
29
+ )
30
+ )
31
+ except Exception as e:
32
+ pass
33
+
34
+ # get agent to identify framework
35
+ agent = Agents(configuration=task.configuration).get(agent_id=task.agent_id,version=task.agent_version)
36
+
37
+ # non agno, let the same agent handle it
38
+ if agent.framework != Framework.Agno:
39
+ return "\n".join([
40
+ "Task not finished, uncompleted tasks detected:",
41
+ f"Uncompleted tasks: {[task.model_dump_json() for task in uncompleted_tasks]}",
42
+ "You must complete tasks if fulfilled",
43
+ f"User's original request: \"{message}\""
44
+ ])
45
+
46
+ # load backend args for consistency of model provider and settings
47
+ agno_args = Backend(configuration=agent.configuration).get_args(agent_id=agent.id, agent_version=agent.version, task=task)
48
+
49
+ if agent.model_provider == "openai":
50
+ agno_args["model"].id = "gpt-5-mini"
51
+
52
+ # create compacitzation agent
53
+ compactization_agent = AgnoAgent(
54
+ output_schema=TaskCompactizationOutput,
55
+ name="Task Compactization Agent",
56
+ model=agno_args.get("model"),
57
+ description="""
58
+ You are a system component that handles early/unapproved agent task exits.
59
+
60
+ When an agent stops execution with uncompleted tasks, you analyze the state and generate a continuation prompt
61
+ that will be sent DIRECTLY to that agent to resume its work.
62
+
63
+ Your output becomes the agent's next input - it must guide the agent to:
64
+ 1. Continue from where it stopped (seamlessly, no restart)
65
+ 2. Complete ALL remaining uncompleted tasks
66
+ 3. Use correct tools (especially xpask_for_information for questions)
67
+ 4. NOT expose internal orchestration (xp* tools, task IDs) to the user
68
+
69
+ You are a bridge between system orchestration and agent execution.
70
+ """,
71
+ role="""
72
+ You are the **Compactization Agent** - a system component for handling early agent exits.
73
+
74
+ **The Flow:**
75
+ 1. Agent A (e.g., researcher) starts task and creates plan
76
+ 2. Agent A executes but stops/exits early with uncompleted tasks
77
+ 3. System detects uncompleted tasks and triggers YOU
78
+ 4. You analyze Agent A's execution state and generate continuation guidance
79
+ 5. Your output goes DIRECTLY to Agent A as its next prompt
80
+ 6. Agent A resumes and completes remaining work
81
+
82
+ **Your Mission:**
83
+ Generate a prompt that Agent A will receive to continue its work. This prompt must:
84
+ - Guide Agent A on what's been done and what remains
85
+ - Correct any protocol violations (e.g., asking questions without tool)
86
+ - Instruct Agent A to NOT expose internal xp* tools to the user
87
+ - Make Agent A's continuation feel seamless to the user
88
+
89
+ You are NOT talking to the user. You are talking to Agent A.
90
+ """,
91
+ instructions="""
92
+ ## Your Role: Agent-to-Agent Handoff
93
+
94
+ You are writing a message that will be sent TO the agent (Agent A) to continue its task.
95
+
96
+ **Key Understanding:**
97
+ - Your `new_task_prompt` = The message Agent A will receive
98
+ - Agent A will see this message and continue working
99
+ - The user will see Agent A's response, not your message directly
100
+ - You must guide Agent A to work seamlessly without exposing internals
101
+
102
+ ## Core Principles
103
+
104
+ * **You are guiding Agent A**, not the user
105
+ * **Agent A must complete ALL uncompleted tasks** - tell it what remains
106
+ * **Stay factual** - Use "Unknown" for missing info
107
+ * **Preserve exact state** - Keep IDs, names, paths, outputs unchanged in context
108
+ * **Correct violations** - If Agent A asked questions without tool, tell it to use the tool
109
+ * **Hide orchestration** - Instruct Agent A to NOT mention xp* tools, task IDs, or internals to user
110
+
111
+ ## What You Must Capture
112
+
113
+ * **Tool call history.** For each tool: name/id, purpose, inputs (high-level), outputs (high-level), errors. Include plan tools (xpcreate_agent_plan, xpcomplete_agent_plan_item, etc.).
114
+ * **Artifacts and state.** All created files, IDs, URLs, variables, decisions, and configurations.
115
+ * **What worked / what didn't.** Successes, failures, blockers, missing info, wrong assumptions.
116
+ * **Task completion status.** For each uncompleted task: exact ID, title, and specific reason it's incomplete.
117
+ * **PROTOCOL VIOLATIONS.** Check if agent asked questions in response text AFTER calling xpstart_execution_plan (violates protocol).
118
+
119
+ ## Detecting Protocol Violations
120
+
121
+ If the agent's last message contains questions to the user AFTER the plan was started (after xpstart_execution_plan was called):
122
+ - This is a PROTOCOL VIOLATION
123
+ - The agent should have used xpask_for_information tool instead
124
+
125
+ When violation is detected, you MUST make it SUPER CLEAR in BOTH output fields:
126
+
127
+ **In `new_task_prompt`:**
128
+ - START with: "CRITICAL PROTOCOL VIOLATION DETECTED: You asked questions directly after starting the plan."
129
+ - Explicitly state: "You MUST use xpask_for_information tool to ask questions once plan is running."
130
+ - Include: "NEVER write questions in your response text after calling xpstart_execution_plan."
131
+ - Then provide the continuation instructions
132
+
133
+ **In `task_context`:**
134
+ - Add a dedicated section at the TOP before section 1: "**PROTOCOL VIOLATION DETECTED**"
135
+ - State clearly: "Agent asked questions in response text after calling xpstart_execution_plan. This violates execution protocol."
136
+ - Remind: "Rule: After xpstart_execution_plan is called, questions MUST be asked using xpask_for_information tool, NOT written in response text."
137
+
138
+ Signs of protocol violation in messages:
139
+ - Phrases like "Before I proceed", "I need clarification", "Please choose", "Which option"
140
+ - Questions written in response text after xpstart_execution_plan was called
141
+
142
+ ## Continuation Prompt: Your Message TO Agent A
143
+
144
+ Your `new_task_prompt` is what Agent A will read. Structure it as guidance TO the agent:
145
+
146
+ 1. **IF protocol violation:** "You asked questions without using xpask_for_information tool. Use the tool for questions."
147
+ 2. **Orient Agent A:** "You were working on [task]. You've completed [X, Y, Z]."
148
+ 3. **State what remains:** "You still need to complete: [list remaining work in plain language]."
149
+ 4. **Guide next steps:** "Continue by: [step-by-step what to do next]."
150
+ 5. **Hide internals instruction:** "Important: Do NOT mention xp* tools, task IDs, or internal workflow to the user. Present your work naturally."
151
+ 6. **Enforce protocol:** "Mark each task complete immediately after finishing using xpcomplete_agent_plan_item."
152
+ 7. **Natural tone:** "Continue your response to the user seamlessly, as if you never stopped."
153
+
154
+ You are INSTRUCTING Agent A on how to continue, not writing the user-facing response yourself.
155
+
156
+ ## Task Context Requirements
157
+
158
+ Your `task_context` must:
159
+ 1. **IF protocol violation detected:** Add "PROTOCOL VIOLATION DETECTED" section at the TOP before section 1
160
+ 2. Follow the exact 9-heading structure specified in the output schema (or 10 if violation detected)
161
+ 3. Be deterministic and parseable by downstream systems
162
+ 4. Focus on actionable continuation steps in section 9 (NEXT ACTIONS)
163
+ 5. Include task IDs for all uncompleted tasks
164
+ 6. Emphasize that ALL tasks must be completed and marked complete
165
+
166
+ ## Critical Rules
167
+
168
+ ❌ **NEVER:**
169
+ - Suggest restarting or creating a new plan
170
+ - Mark tasks as complete that aren't actually done
171
+ - Invent details or speculate
172
+ - Write a "fresh start" prompt
173
+
174
+ ✅ **ALWAYS:**
175
+ - Write as instructions TO Agent A (you're guiding it, not doing its work)
176
+ - Tell Agent A what it's done and what remains
177
+ - Instruct Agent A to complete remaining tasks
178
+ - Tell Agent A to use correct tools (xpask_for_information for questions)
179
+ - Instruct Agent A to hide xp* tools and internals from user
180
+ - Include technical details (task IDs, tool names) in task_context for Agent A's reference
181
+ - Correct any protocol violations Agent A made
182
+ """,
183
+ expected_output="""
184
+ Return a JSON object with exactly these two fields:
185
+
186
+ - new_task_prompt (string): Instructions TO Agent A for continuing its task.
187
+
188
+ This message will be sent directly to Agent A. Write it as guidance:
189
+
190
+ IF PROTOCOL VIOLATION:
191
+ "You asked questions without using xpask_for_information tool. Use the tool for questions after plan starts."
192
+
193
+ Then:
194
+ "You were working on [task name]. You've completed [work done in plain language].
195
+
196
+ You still need to complete: [list remaining uncompleted work naturally].
197
+
198
+ Continue by: [specific steps for Agent A to take].
199
+
200
+ IMPORTANT: When responding to the user, do NOT mention xp* tools, task IDs, or internal workflow.
201
+ Present your work naturally as if execution never stopped. The user should not see any interruption.
202
+
203
+ Mark each task complete immediately after finishing using xpcomplete_agent_plan_item."
204
+
205
+ - task_context (string): Comprehensive context for continuation.
206
+ IF PROTOCOL VIOLATION DETECTED:
207
+ - Add section at TOP: "**PROTOCOL VIOLATION DETECTED**\nAgent asked questions in response text after calling xpstart_execution_plan. This violates execution protocol. Rule: After xpstart_execution_plan is called, questions MUST be asked using xpask_for_information tool, NOT written in response text.\n\n"
208
+ Then follow the EXACT 9-section structure defined in TaskCompactizationOutput.task_context.
209
+ Must be deterministic, actionable, and focused on completing ALL remaining tasks and marking them as completed.
210
+
211
+ Important:
212
+ - Do NOT invent details; write 'Unknown' when information is missing.
213
+ - Preserve exact IDs, names, file paths, numbers, and user phrasing.
214
+ - Final actions must include marking each remaining task as completed with the plan tools.
215
+ - IF protocol violation: Make it SUPER CLEAR in both fields that tool must be used for questions.
216
+ """
217
+ )
218
+
219
+ session = agent.get_session(session_id=task.id)
220
+
221
+ # run compactization
222
+ run_result = compactization_agent.run(
223
+ input=TaskCompactizationInput(
224
+ user_input=task.input,
225
+ agent_instructions=agent.instructions,
226
+ task_context_and_messages=json.dumps({"messages": [message.model_dump() for message in session.get_messages() if message.role != "system"]}),
227
+ uncompleted_tasks=uncompleted_tasks
228
+ )
229
+ )
230
+
231
+ # reset old session
232
+ agent.delete_session(session_id=task.id)
233
+
234
+ # report LLM Metrics
235
+ task.tokens = Tokens(
236
+ completion_tokens=run_result.metrics.output_tokens,
237
+ prompt_tokens=run_result.metrics.input_tokens
238
+ )
239
+
240
+ task.report_metrics(configuration=task.configuration)
241
+
242
+ # report compactization event
243
+ try:
244
+ run_sync(
245
+ push_event(
246
+ task=task,
247
+ event=TaskCompactizationEvent(type="summarization", data=run_result.content),
248
+ event_type=TaskUpdateEventType.TaskCompactization
249
+ )
250
+ )
251
+ except Exception as e:
252
+ pass
253
+
254
+ return run_result.content
255
+ except Exception as e:
256
+ logger.warning(f"Failed to run task compactization - {str(e)}")
257
+ return message
@@ -0,0 +1,5 @@
1
+ from datetime import datetime, timezone
2
+
3
+
4
+ def get_current_timestamp() -> str:
5
+ return datetime.now(timezone.utc).isoformat()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xpander-sdk
3
- Version: 2.0.161
3
+ Version: 2.0.192
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
@@ -11,15 +11,16 @@ Classifier: Operating System :: OS Independent
11
11
  Requires-Python: >=3.9
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
- Requires-Dist: python-dotenv
15
- Requires-Dist: packaging
16
- Requires-Dist: pydantic
17
- Requires-Dist: loguru
18
- Requires-Dist: httpx
19
- Requires-Dist: httpx_sse
20
- Requires-Dist: nest-asyncio
21
- Requires-Dist: strands-agents
22
- Requires-Dist: openai-agents
14
+ Requires-Dist: python-dotenv>=1.2.1
15
+ Requires-Dist: packaging>=25.0
16
+ Requires-Dist: pydantic>=2.12.5
17
+ Requires-Dist: loguru>=0.7.3
18
+ Requires-Dist: httpx>=0.28.1
19
+ Requires-Dist: httpx_sse>=0.4.3
20
+ Requires-Dist: nest-asyncio>=1.6.0
21
+ Requires-Dist: strands-agents>=1.20.0
22
+ Requires-Dist: openai-agents>=0.6.4
23
+ Requires-Dist: python-toon>=0.1.3
23
24
  Provides-Extra: agno
24
25
  Requires-Dist: agno; extra == "agno"
25
26
  Requires-Dist: sqlalchemy; extra == "agno"
@@ -47,7 +48,7 @@ Dynamic: requires-dist
47
48
  Dynamic: requires-python
48
49
  Dynamic: summary
49
50
 
50
- # xpander.ai SDK
51
+ # xpander.ai SDK
51
52
 
52
53
  [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Documentation](https://img.shields.io/badge/docs-available-brightgreen.svg)](https://docs.xpander.ai) [![PyPI Version](https://img.shields.io/pypi/v/xpander-sdk?label=PyPI)](https://pypi.org/project/xpander-sdk/) [![Downloads](https://pepy.tech/badge/xpander-sdk)](https://pepy.tech/project/xpander-sdk)
53
54
 
@@ -292,6 +293,89 @@ async for event in task.aevents():
292
293
  print(f"Event Data: {event.data}")
293
294
  ```
294
295
 
296
+ ### Authentication Events Callback
297
+
298
+ Handle authentication events in real-time. This callback is triggered only for authentication flows (e.g., MCP OAuth requiring user login).
299
+
300
+ **You can use both approaches simultaneously** - decorated handlers will always be invoked, and you can also pass an explicit callback for additional handling.
301
+
302
+ You can provide the callback in two ways:
303
+
304
+ #### Option 1: Direct Function
305
+
306
+ ```python
307
+ from xpander_sdk import Backend
308
+ from xpander_sdk.modules.agents.sub_modules.agent import Agent
309
+ from xpander_sdk.modules.tasks.sub_modules.task import Task, TaskUpdateEvent
310
+ from agno.agent import Agent as AgnoAgent
311
+
312
+ # Define event callback (async or sync)
313
+ async def my_event_callback(agent: Agent, task: Task, event: TaskUpdateEvent):
314
+ """Called for authentication events only"""
315
+ # event.type will always be "auth_event"
316
+ print(f"Authentication required: {event.data}")
317
+ # Display login URL or handle OAuth flow
318
+
319
+ # Get args with callback
320
+ backend = Backend(configuration=config)
321
+ args = await backend.aget_args(
322
+ agent_id="agent-123",
323
+ task=my_task,
324
+ auth_events_callback=my_event_callback
325
+ )
326
+ ```
327
+
328
+ #### Option 2: Decorator (Auto-registered)
329
+
330
+ ```python
331
+ from xpander_sdk import Backend, on_auth_event
332
+ from xpander_sdk.modules.agents.sub_modules.agent import Agent
333
+ from xpander_sdk.modules.tasks.sub_modules.task import Task, TaskUpdateEvent
334
+ from agno.agent import Agent as AgnoAgent
335
+
336
+ # Use decorator - auto-registers globally
337
+ @on_auth_event
338
+ async def handle_auth(agent: Agent, task: Task, event: TaskUpdateEvent):
339
+ # event.type will always be "auth_event"
340
+ print(f"Authentication required for {agent.name}")
341
+ print(f"Auth data: {event.data}")
342
+
343
+ # Decorated handler is automatically invoked - no need to pass it
344
+ backend = Backend(configuration=config)
345
+ args = await backend.aget_args(
346
+ agent_id="agent-123",
347
+ task=my_task
348
+ )
349
+ ```
350
+
351
+ #### Option 3: Combine Both
352
+
353
+ ```python
354
+ from xpander_sdk import Backend, on_auth_event
355
+
356
+ # Global handler for all auth events
357
+ @on_auth_event
358
+ async def log_auth(agent, task, event):
359
+ print(f"[GLOBAL] Auth event for {agent.name}")
360
+
361
+ # Additional one-time handler
362
+ async def custom_handler(agent, task, event):
363
+ print(f"[CUSTOM] Specific handling for this call")
364
+
365
+ # Both handlers will be invoked
366
+ args = await backend.aget_args(
367
+ agent_id="agent-123",
368
+ auth_events_callback=custom_handler # Optional additional callback
369
+ )
370
+
371
+ # Use with Agno
372
+ agno_agent = AgnoAgent(**args)
373
+ result = await agno_agent.arun(
374
+ input="Process this data",
375
+ stream=True
376
+ )
377
+ ```
378
+
295
379
  ### Task Activity Monitoring
296
380
 
297
381
  ```python
@@ -483,11 +567,11 @@ async def main():
483
567
  organization_id="your-org-id",
484
568
  base_url="https://agent-controller.my-company.com"
485
569
  )
486
-
570
+
487
571
  # Load agent from self-hosted deployment
488
572
  agent = await Agent.aload("agent-123", configuration=config)
489
573
  print(f"Agent: {agent.name}")
490
-
574
+
491
575
  # Create and execute task
492
576
  task = await agent.acreate_task(
493
577
  prompt="Analyze Q4 sales data",
@@ -1,6 +1,6 @@
1
- xpander_sdk/__init__.py,sha256=subqRII3DHqi4FYdWS11fuliCXiOttOrd57m6zTW7pY,2671
1
+ xpander_sdk/__init__.py,sha256=34l3YcvIdkj81DTfMp_bgZgXpj2U1lTKpHQ0shwnc_8,2927
2
2
  xpander_sdk/consts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- xpander_sdk/consts/api_routes.py,sha256=dKUruLanvprTxZO15fR4OWe6ck8JQ8y64XmUJxsbeJY,2278
3
+ xpander_sdk/consts/api_routes.py,sha256=jRIxZqqufz14FOwE9gcFMURtm99vQ5g4uw6QLEAS6ks,2621
4
4
  xpander_sdk/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  xpander_sdk/core/module_base.py,sha256=YiUonUBXnXqa9wms5O8C9tEfQeWBJCIZg6xzEorV8gI,5480
6
6
  xpander_sdk/core/state.py,sha256=GKGJaMALpTGVV2-iPV3cPrQW4dNdFoZPv3oXBjHDhIY,214
@@ -9,36 +9,44 @@ xpander_sdk/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
9
9
  xpander_sdk/exceptions/module_exception.py,sha256=2Urni1QEdzOrCdYSRc5eLpuz8aDlvRcn8KNejo_2nGc,1687
10
10
  xpander_sdk/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  xpander_sdk/models/activity.py,sha256=I3CxOzUNbrKwHqynCbm7FJja6vanVkCzwwBwET7qvzA,2085
12
+ xpander_sdk/models/compactization.py,sha256=I0tfDQZKaaKvWHIg1O07oJUPUrbwvr4Q0azDsx5OfAE,5596
12
13
  xpander_sdk/models/configuration.py,sha256=Un8p3C3p3eMiqKK5VsHaZdWhZTRYHbrw2aPUMV8lJSc,3370
13
14
  xpander_sdk/models/deep_planning.py,sha256=pCFV5iNSfT99ap1-09k7oO_DIwXx2vPJ3aVM472xL4w,554
14
- xpander_sdk/models/events.py,sha256=2vIkuPGAbntN_7xggJRw5sMJ1_EzcXyljxPH0ekISlw,2235
15
- xpander_sdk/models/frameworks.py,sha256=Ptf4aMjZ44L_x8WsCc5X0kjsJObv4dwgSM61no0aW6E,2937
15
+ xpander_sdk/models/events.py,sha256=HnootQSUIIRM4BIdaTbuPUEJ55hLVtA7KDCSsnHeBKw,2313
16
+ xpander_sdk/models/frameworks.py,sha256=-7W_m5cvgS1qLp0gGAFP4noNWT82IT1ZqtQv5WuOC2k,2939
17
+ xpander_sdk/models/generic.py,sha256=yw5rBRdZ-6ucTI4AwtskenddepOooiFRM--9xx5jrL8,681
18
+ xpander_sdk/models/notifications.py,sha256=3tK4Z2gmA6YxRtqsWgzjiVISgJyHvmjTooiRgzrj5zY,3373
19
+ xpander_sdk/models/orchestrations.py,sha256=uMXkTZ_tdE10rbVUy8H8vxfh71HZGZcaJUEy61wwz2k,9898
16
20
  xpander_sdk/models/shared.py,sha256=gW88kA_UslNinUjtQKpLVF0sHDZnckwLWexRapxPivU,3125
17
21
  xpander_sdk/models/user.py,sha256=_FTG0JO6iTrbcvJp-BBJ6nuj281zhyQB5ldQkBCyYDU,749
18
22
  xpander_sdk/modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
23
  xpander_sdk/modules/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
24
  xpander_sdk/modules/agents/agents_module.py,sha256=3EhKOIPb4c39GOrNt4zU4V6WbsGj7W_yWwRNSJBKmfc,6419
21
25
  xpander_sdk/modules/agents/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- xpander_sdk/modules/agents/models/agent.py,sha256=tJXNogRjvwlxzJPzesdHm-NBhMOzDnWImC0ndWhyjx4,14969
26
+ xpander_sdk/modules/agents/models/agent.py,sha256=lHWz37a4_qB9Hq4sZhvjILjj566hJHZbDlj7JJ6iO68,15340
23
27
  xpander_sdk/modules/agents/models/agent_list.py,sha256=byEayS2uLwDKaVT3lAHltrFocQFKpr8XEwQ6NTEEEMo,4081
24
28
  xpander_sdk/modules/agents/models/knowledge_bases.py,sha256=YimpjVJxWe8YTbGMD6oGQOA_YV8ztHQHTTBOaBB44ZM,1037
25
29
  xpander_sdk/modules/agents/sub_modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
- xpander_sdk/modules/agents/sub_modules/agent.py,sha256=HHVz00hrRCFZV9uj8Q5TvZHO_ObijMwQw5Gqdwa_nDY,36298
30
+ xpander_sdk/modules/agents/sub_modules/agent.py,sha256=O3y2qKAFb19yO7gt2Ey6BNJGwA9cMHMuKG4_iNjqKL0,36841
27
31
  xpander_sdk/modules/agents/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
32
  xpander_sdk/modules/agents/utils/generic.py,sha256=XbG4OeHMQo4gVYCsasMlW_b8OoqS1xL3MlUZSjXivu0,81
29
- xpander_sdk/modules/backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
- xpander_sdk/modules/backend/backend_module.py,sha256=wYghMuNXEtXgoyMXBgbMhgE7wYcbRwXJcpEyybF30kA,18927
33
+ xpander_sdk/modules/backend/__init__.py,sha256=-NjikuZgHBhOM9xHML2vKsG0ICX9S2RKHktrWaODCBE,171
34
+ xpander_sdk/modules/backend/backend_module.py,sha256=A8NW5QqVy28O-E5eL1VU2iUHgtxyz7rFN7Ih0Jnv-TE,21713
35
+ xpander_sdk/modules/backend/events_registry.py,sha256=d0V-lsz3I3G1QB643EM1i-a5oJCiHnEfqBY_SmN2WrE,5983
36
+ xpander_sdk/modules/backend/decorators/__init__.py,sha256=ub9c8G0Ll6AuCvfcFB6rqR8iamMJxtcW7QjWw3WSkPU,106
37
+ xpander_sdk/modules/backend/decorators/on_auth_event.py,sha256=Xt_x9nncujMcF_SgM5hG6M-iZ6B-rDS97EPmgZkGdMk,4715
31
38
  xpander_sdk/modules/backend/frameworks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
- xpander_sdk/modules/backend/frameworks/agno.py,sha256=VDrNb2M2RaKDPjlmc-yQeXJZVDpTifF4zl2xaLXvDeg,32538
33
- xpander_sdk/modules/backend/frameworks/dispatch.py,sha256=5dP4c37C42U53VjM2kkwIRwEw1i0IN3G0YESHH7J3OE,1557
39
+ xpander_sdk/modules/backend/frameworks/agno.py,sha256=djHGWFGaMOetKfD6XNKEYxYzBm8GwPlhuPFRkB8PFkg,41712
40
+ xpander_sdk/modules/backend/frameworks/dispatch.py,sha256=ht9hT5-cHATofQbWsbWeTARx51Hne3TNNNjw6KECRtA,1814
34
41
  xpander_sdk/modules/backend/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
- xpander_sdk/modules/backend/utils/mcp_oauth.py,sha256=a4xQGQwRGf2T9h38Vc9VNUwpIeY9y7Mn6B4D2G3tMQM,4387
42
+ xpander_sdk/modules/backend/utils/mcp_oauth.py,sha256=5sYJcw557V3pSgutxUFzkBp5YxUJFUoB1V1rEe814pc,5430
36
43
  xpander_sdk/modules/events/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
- xpander_sdk/modules/events/events_module.py,sha256=WJcSdmShGmEhd-Qw0R2fWp4OOlefjLs5_WsQlfJ-UrQ,25317
38
- xpander_sdk/modules/events/decorators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
+ xpander_sdk/modules/events/events_module.py,sha256=tAjfc6kfjgmswQkgm-rcVs8wVpOYYPv03kqZHTVE8Uo,25737
45
+ xpander_sdk/modules/events/decorators/__init__.py,sha256=8GhR9afoLiS83a0OMLpn7TN2W6iTnlcVqos6bM34nac,129
39
46
  xpander_sdk/modules/events/decorators/on_boot.py,sha256=VGtoQcgs3g5bmx3Ze4QB_-ZwBESATYYVR0oZe35eCww,3076
40
47
  xpander_sdk/modules/events/decorators/on_shutdown.py,sha256=rFgChspnLDnZm9FS1K636dvZSQDkeugf2e3M83SDgAY,3127
41
48
  xpander_sdk/modules/events/decorators/on_task.py,sha256=G3jk0xzi3pqH96Bbut_GMJKExIlyyMYk4PbKfc6koa4,8551
49
+ xpander_sdk/modules/events/decorators/on_tool.py,sha256=ZacZ6tADjvl79ISqKxTSH1P0nZUS8C3mRwOL2SyLeZE,13750
42
50
  xpander_sdk/modules/events/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
51
  xpander_sdk/modules/events/models/deployments.py,sha256=6uwxFsybrZ-eHeohJzkm2RtQq4Eo_0xjHk7QouvszxU,1335
44
52
  xpander_sdk/modules/events/models/events.py,sha256=T_89pq48e7fMIbJcCbtM9Ocb6YKXQP7pbF6VbECiGcI,1550
@@ -56,10 +64,10 @@ xpander_sdk/modules/knowledge_bases/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-
56
64
  xpander_sdk/modules/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
65
  xpander_sdk/modules/tasks/tasks_module.py,sha256=wOMegfNQ4qoY7PEII5828SjWrP0Jocg2TRsFOaaCmW0,20444
58
66
  xpander_sdk/modules/tasks/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
- xpander_sdk/modules/tasks/models/task.py,sha256=B0_fwzQEkRE_pZMSLnWuXsUBMdy8HEIxm1FfRpCQma0,5000
67
+ xpander_sdk/modules/tasks/models/task.py,sha256=pYzXg0jnE6ft4pVFvxiVexO5eMUFkg1VxXybzFtL1ys,4483
60
68
  xpander_sdk/modules/tasks/models/tasks_list.py,sha256=8V1T0vCtGN79qLMPwe37pOA7Wvuf8pbJNOhWL0BPo-8,5126
61
69
  xpander_sdk/modules/tasks/sub_modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
- xpander_sdk/modules/tasks/sub_modules/task.py,sha256=RlYe4XAhWeUGk2JwlRC__SWP7OFoym8fnCTluYrhHLg,36135
70
+ xpander_sdk/modules/tasks/sub_modules/task.py,sha256=zRDHsE_LnYYa3OC79wVQqeRnpAogddHVI2R6-3IepJ4,37920
63
71
  xpander_sdk/modules/tasks/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
72
  xpander_sdk/modules/tasks/utils/files.py,sha256=KqqwSQSrwim2-H3XP5wOadDDfngAyEI034tA7Oon-vc,3631
65
73
  xpander_sdk/modules/tools_repository/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -70,17 +78,20 @@ xpander_sdk/modules/tools_repository/models/__init__.py,sha256=47DEQpj8HBSa-_TIm
70
78
  xpander_sdk/modules/tools_repository/models/mcp.py,sha256=qGpaiXKiuXw6gAcK8CW6ek6FkZNbBxDXUf1PWF6Tenw,1863
71
79
  xpander_sdk/modules/tools_repository/models/tool_invocation_result.py,sha256=Dhowt_fv8v8xWv7xMRJxo6hA8DawXKbWIrsJFMpt5H4,447
72
80
  xpander_sdk/modules/tools_repository/sub_modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
- xpander_sdk/modules/tools_repository/sub_modules/tool.py,sha256=YUf267PRXtctpPydpQTTnaO3aliSJwapM3WsdGG06Pw,22365
81
+ xpander_sdk/modules/tools_repository/sub_modules/tool.py,sha256=rivnznxi6CrrOWE1rukkBRmad2H-rthhrelC7ei1IXM,23617
74
82
  xpander_sdk/modules/tools_repository/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
- xpander_sdk/modules/tools_repository/utils/generic.py,sha256=m9FRaVGzRUj23tB52rP9K4O-nTsMSt9iwMxMcYsqfiY,1770
83
+ xpander_sdk/modules/tools_repository/utils/generic.py,sha256=bQ31-RoAq12lpDoIWsgmqAt7NL5YdzW1j3WKqZtYb2A,1904
76
84
  xpander_sdk/modules/tools_repository/utils/local_tools.py,sha256=zp5P8hVnRUJQb-w-2jCEMV5eUB_awmvYfY_rin5qvEw,1875
77
85
  xpander_sdk/modules/tools_repository/utils/schemas.py,sha256=EUi35h7CRrOVXV-TH-lyCpOdK5pu1uODDxvGB1JGDXY,13734
78
86
  xpander_sdk/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
87
  xpander_sdk/utils/env.py,sha256=U_zIhqWgKs5fk2-HXjAaODj4oWMc5dRQ0fvw6fqVcFk,1522
80
88
  xpander_sdk/utils/event_loop.py,sha256=kJrN0upgBhyI86tkTdfHeajznrIZl44Rl6WDiDG3GHE,2516
89
+ xpander_sdk/utils/generic.py,sha256=XrRj2-L8c0YWpfPdDyXE-pVL-6lKF9VpyZzKHQ4wuCc,127
81
90
  xpander_sdk/utils/tools.py,sha256=lyFkq2yP7DxBkyXYVlnFRwDhQCvf0fZZMDm5fBycze4,1244
82
- xpander_sdk-2.0.161.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
83
- xpander_sdk-2.0.161.dist-info/METADATA,sha256=I0vEmwVDjrE9TM2CKj1HTmCFU35l3Zm5nfhSWX_vMI4,15312
84
- xpander_sdk-2.0.161.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
85
- xpander_sdk-2.0.161.dist-info/top_level.txt,sha256=UCjnxQpsMy5Zoe7lmRuVDO6DI2V_6PgRFfm4oizRbVs,12
86
- xpander_sdk-2.0.161.dist-info/RECORD,,
91
+ xpander_sdk/utils/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
+ xpander_sdk/utils/agents/compactization_agent.py,sha256=S_U1dSmDC7I0JUsp_THUYjfutEI5QMBaMPJEXGp0_Sw,14389
93
+ xpander_sdk-2.0.192.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
94
+ xpander_sdk-2.0.192.dist-info/METADATA,sha256=NM6k5GsEGHR8qvT1GWi7H9s3C4R_5OvE-Pwm1eWnh0g,17945
95
+ xpander_sdk-2.0.192.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
96
+ xpander_sdk-2.0.192.dist-info/top_level.txt,sha256=UCjnxQpsMy5Zoe7lmRuVDO6DI2V_6PgRFfm4oizRbVs,12
97
+ xpander_sdk-2.0.192.dist-info/RECORD,,