xpander-sdk 2.0.415__tar.gz → 2.0.417__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 (179) hide show
  1. {xpander_sdk-2.0.415/src/xpander_sdk.egg-info → xpander_sdk-2.0.417}/PKG-INFO +1 -1
  2. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/setup.py +1 -1
  3. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/__init__.py +1 -1
  4. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/consts/api_routes.py +3 -0
  5. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/finalize_mode.py +2 -8
  6. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/models/frameworks.py +1 -1
  7. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/frameworks/agno.py +228 -44
  8. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/utils/schemas.py +1 -1
  9. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417/src/xpander_sdk.egg-info}/PKG-INFO +1 -1
  10. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/LICENSE +0 -0
  11. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/README.md +0 -0
  12. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/pyproject.toml +0 -0
  13. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/setup.cfg +0 -0
  14. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/consts/__init__.py +0 -0
  15. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/__init__.py +0 -0
  16. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/__init__.py +0 -0
  17. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/action_ledger.py +0 -0
  18. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/compact_retry_result.py +0 -0
  19. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/completion_evidence.py +0 -0
  20. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/constants.py +0 -0
  21. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/context_optimizer.py +0 -0
  22. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/encryption.py +0 -0
  23. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/error_patterns.py +0 -0
  24. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/helpers/__init__.py +0 -0
  25. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/helpers/chunking.py +0 -0
  26. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/helpers/recent_actions.py +0 -0
  27. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/helpers/secrets.py +0 -0
  28. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/helpers/tool_result.py +0 -0
  29. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/helpers/xml_safety.py +0 -0
  30. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/mixins/__init__.py +0 -0
  31. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/mixins/map_reduce.py +0 -0
  32. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/multimodal_error_patterns.py +0 -0
  33. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/prompts.py +0 -0
  34. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/search.py +0 -0
  35. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/context_optimizer/workspace_cache.py +0 -0
  36. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/module_base.py +0 -0
  37. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/state.py +0 -0
  38. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/core/xpander_api_client.py +0 -0
  39. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/exceptions/__init__.py +0 -0
  40. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/exceptions/module_exception.py +0 -0
  41. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/models/__init__.py +0 -0
  42. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/models/action_ledger.py +0 -0
  43. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/models/activity.py +0 -0
  44. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/models/compactization.py +0 -0
  45. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/models/configuration.py +0 -0
  46. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/models/context_status.py +0 -0
  47. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/models/deep_planning.py +0 -0
  48. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/models/events.py +0 -0
  49. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/models/generic.py +0 -0
  50. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/models/notifications.py +0 -0
  51. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/models/orchestrations.py +0 -0
  52. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/models/shared.py +0 -0
  53. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/models/user.py +0 -0
  54. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/__init__.py +0 -0
  55. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/agents/__init__.py +0 -0
  56. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/agents/agents_module.py +0 -0
  57. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/agents/models/__init__.py +0 -0
  58. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/agents/models/agent.py +0 -0
  59. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/agents/models/agent_list.py +0 -0
  60. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/agents/models/knowledge_bases.py +0 -0
  61. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/agents/sub_modules/__init__.py +0 -0
  62. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/agents/sub_modules/agent.py +0 -0
  63. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/agents/utils/__init__.py +0 -0
  64. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/agents/utils/generic.py +0 -0
  65. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/__init__.py +0 -0
  66. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/backend_module.py +0 -0
  67. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/decorators/__init__.py +0 -0
  68. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/decorators/on_auth_event.py +0 -0
  69. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/events_registry.py +0 -0
  70. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/frameworks/__init__.py +0 -0
  71. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/frameworks/_anthropic_cache.py +0 -0
  72. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/frameworks/_bedrock_cache.py +0 -0
  73. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/frameworks/dispatch.py +0 -0
  74. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/utils/__init__.py +0 -0
  75. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/utils/extra_headers.py +0 -0
  76. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/utils/mcp_connect.py +0 -0
  77. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/utils/mcp_oauth.py +0 -0
  78. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/backend/utils/tool_call_events.py +0 -0
  79. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/events/__init__.py +0 -0
  80. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/events/decorators/__init__.py +0 -0
  81. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/events/decorators/on_boot.py +0 -0
  82. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/events/decorators/on_shutdown.py +0 -0
  83. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/events/decorators/on_task.py +0 -0
  84. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/events/decorators/on_tool.py +0 -0
  85. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/events/events_module.py +0 -0
  86. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/events/models/__init__.py +0 -0
  87. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/events/models/deployments.py +0 -0
  88. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/events/models/events.py +0 -0
  89. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/events/streaming_server.py +0 -0
  90. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/events/utils/__init__.py +0 -0
  91. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/events/utils/generic.py +0 -0
  92. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/events/utils/git_init.py +0 -0
  93. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/knowledge_bases/__init__.py +0 -0
  94. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/knowledge_bases/knowledge_bases_module.py +0 -0
  95. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/knowledge_bases/models/__init__.py +0 -0
  96. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/knowledge_bases/models/knowledge_bases.py +0 -0
  97. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/knowledge_bases/sub_modules/__init__.py +0 -0
  98. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/knowledge_bases/sub_modules/knowledge_base.py +0 -0
  99. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/knowledge_bases/sub_modules/knowledge_base_document_item.py +0 -0
  100. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/knowledge_bases/utils/__init__.py +0 -0
  101. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tasks/__init__.py +0 -0
  102. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tasks/models/__init__.py +0 -0
  103. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tasks/models/task.py +0 -0
  104. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tasks/models/tasks_list.py +0 -0
  105. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tasks/sub_modules/__init__.py +0 -0
  106. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tasks/sub_modules/task.py +0 -0
  107. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tasks/tasks_module.py +0 -0
  108. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tasks/utils/__init__.py +0 -0
  109. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tasks/utils/files.py +0 -0
  110. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tasks/utils/media.py +0 -0
  111. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tasks/utils/model_capabilities.py +0 -0
  112. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/__init__.py +0 -0
  113. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/decorators/__init__.py +0 -0
  114. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/decorators/register_tool.py +0 -0
  115. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/models/__init__.py +0 -0
  116. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/models/mcp.py +0 -0
  117. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/models/tool_invocation_result.py +0 -0
  118. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/sub_modules/__init__.py +0 -0
  119. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/sub_modules/dynamic_tools.py +0 -0
  120. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/sub_modules/mcp_tool_proxy.py +0 -0
  121. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/sub_modules/tool.py +0 -0
  122. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/tools_repository_module.py +0 -0
  123. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/utils/__init__.py +0 -0
  124. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/utils/billing_context.py +0 -0
  125. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/utils/generic.py +0 -0
  126. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/utils/local_tools.py +0 -0
  127. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/modules/tools_repository/utils/workspace_payload.py +0 -0
  128. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/utils/__init__.py +0 -0
  129. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/utils/agents/__init__.py +0 -0
  130. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/utils/cache.py +0 -0
  131. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/utils/db/__init__.py +0 -0
  132. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/utils/db/engine_registry.py +0 -0
  133. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/utils/env.py +0 -0
  134. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/utils/event_loop.py +0 -0
  135. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/utils/generic.py +0 -0
  136. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/utils/json_parsing.py +0 -0
  137. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk/utils/tools.py +0 -0
  138. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk.egg-info/SOURCES.txt +0 -0
  139. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk.egg-info/dependency_links.txt +0 -0
  140. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk.egg-info/requires.txt +0 -0
  141. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/src/xpander_sdk.egg-info/top_level.txt +0 -0
  142. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_action_ledger_dedup.py +0 -0
  143. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_agent_instructions_render.py +0 -0
  144. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_aget_db_engine_registry.py +0 -0
  145. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_agno_cpu_hotpaths.py +0 -0
  146. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_anthropic_prompt_cache.py +0 -0
  147. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_auto_context_management_toggle.py +0 -0
  148. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_bedrock_prompt_cache.py +0 -0
  149. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_boot_shutdown_handlers.py +0 -0
  150. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_child_startup_perf.py +0 -0
  151. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_context_optimizer_chunked.py +0 -0
  152. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_context_optimizer_perf.py +0 -0
  153. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_context_optimizer_recent_actions.py +0 -0
  154. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_context_optimizer_status_events.py +0 -0
  155. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_context_optimizer_unwrap.py +0 -0
  156. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_context_optimizer_window.py +0 -0
  157. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_context_retrieve_reoffload.py +0 -0
  158. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_context_search.py +0 -0
  159. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_context_window_detection.py +0 -0
  160. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_cross_subexec_decrypt.py +0 -0
  161. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_emergency_connectivity_breaker.py +0 -0
  162. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_encryption.py +0 -0
  163. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_engine_registry.py +0 -0
  164. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_headroom_l0.py +0 -0
  165. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_layer_1_cache_integration.py +0 -0
  166. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_mcp_connect_probe.py +0 -0
  167. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_mcp_oauth_events.py +0 -0
  168. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_mcp_parallel_connect.py +0 -0
  169. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_mcp_preflight_tail.py +0 -0
  170. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_parent_update_deep_planning.py +0 -0
  171. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_planning_tools_visibility.py +0 -0
  172. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_reasoning_inline_gateway.py +0 -0
  173. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_reasoning_plan_task_id.py +0 -0
  174. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_skills_instructions.py +0 -0
  175. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_spawn_bg.py +0 -0
  176. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_tool_call_events.py +0 -0
  177. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_weak_model_reasoning.py +0 -0
  178. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_workspace_cache.py +0 -0
  179. {xpander_sdk-2.0.415 → xpander_sdk-2.0.417}/tests/test_workspace_tools_toggle.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xpander-sdk
3
- Version: 2.0.415
3
+ Version: 2.0.417
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
@@ -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.415",
8
+ version="2.0.417",
9
9
  author="xpanderAI",
10
10
  author_email="dev@xpander.ai",
11
11
  description="xpander.ai Backend-as-a-service for AI Agents - SDK",
@@ -15,7 +15,7 @@ Main Components:
15
15
  For more information, visit: https://xpander.ai
16
16
  """
17
17
 
18
- __version__ = "2.0.415"
18
+ __version__ = "2.0.417"
19
19
 
20
20
  # Backend-related imports
21
21
  from .modules.backend.backend_module import Backend
@@ -72,6 +72,9 @@ class APIRoute(str, Enum):
72
72
  # Agentic context
73
73
  GetOrSetAgenticContext = "/agentic_context/{agent_id}"
74
74
 
75
+ # User/agent memories
76
+ UserMemories = "/memories/{agent_id}"
77
+
75
78
  # Workspace
76
79
  WorkspaceToolInvoke = "/workspace/{agent_id}/tools/{tool_name}"
77
80
 
@@ -177,9 +177,7 @@ def build_finalize_tool(task: Any) -> Any:
177
177
  async def _entrypoint(
178
178
  payload: Optional[Union[Dict[str, Any], str]] = None,
179
179
  ) -> str:
180
- # LLMs sometimes emit the payload as a JSON string; validate_call
181
- # accepts it via the Union, we parse here. An unparseable string is
182
- # kept as the final answer — finalize must terminate, never bounce.
180
+ """Finalize the task; string payloads are parsed, unparseable ones become the final answer (finalize must terminate, never bounce)."""
183
181
  if isinstance(payload, str):
184
182
  parsed = parse_structured_string(payload)
185
183
  payload = parsed if isinstance(parsed, dict) else {"final_answer": payload}
@@ -276,11 +274,7 @@ async def _run_finalize(
276
274
  and getattr(task, "deep_planning", None)
277
275
  and task.deep_planning.tasks
278
276
  ):
279
- # Soft evidence gate: when the ledger recorded tool calls and every
280
- # single one failed, the LLM's completed_items claim is fabricated —
281
- # keep the items open and say so instead of rendering a green plan.
282
- # An absent/empty ledger can't distinguish "no tools needed" from
283
- # "ledger disabled", so it never blocks.
277
+ # Soft gate: every recorded call failed -> the completion claim is fabricated; an absent/empty ledger never blocks.
284
278
  ledger = get_attached_ledger(task)
285
279
  all_calls_failed = bool(
286
280
  ledger
@@ -43,9 +43,9 @@ class AgnoSettings(BaseModel):
43
43
 
44
44
  learning: Optional[bool] = False
45
45
 
46
+ # deprecated: agno memory machinery replaced by the xpander memory layer; kept for wire compat, ignored at runtime
46
47
  user_memories: Optional[bool] = False
47
48
  agentic_memory: Optional[bool] = False
48
-
49
49
  agent_memories: Optional[bool] = False
50
50
  agentic_culture: Optional[bool] = False
51
51
 
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  import hashlib
3
3
  import json
4
+ import re
4
5
  import shlex
5
6
  import uuid
6
7
  from collections import deque
@@ -123,7 +124,6 @@ from xpander_sdk.modules.tools_repository.utils.workspace_payload import (
123
124
  )
124
125
  from agno.agent import Agent as AgnoAgent
125
126
  from agno.team import Team as AgnoTeam
126
- from agno.memory import MemoryManager
127
127
  from agno.guardrails import PIIDetectionGuardrail
128
128
  from agno.guardrails import PromptInjectionGuardrail
129
129
  from agno.guardrails import OpenAIModerationGuardrail
@@ -549,8 +549,7 @@ def _build_compact_tool():
549
549
  from agno.tools.function import Function
550
550
 
551
551
  def _entrypoint(payload: Optional[Union[Dict[str, Any], str]] = None) -> str:
552
- # Stringified payloads are accepted (Union) and parsed here so a
553
- # malformed emission never fails the compaction request itself.
552
+ """Schedule compaction; stringified payloads are parsed so a malformed emission never fails the request."""
554
553
  if isinstance(payload, str):
555
554
  parsed = parse_structured_string(payload)
556
555
  payload = parsed if isinstance(parsed, dict) else {}
@@ -624,7 +623,10 @@ def reenvelope_sibling_args(arguments: Dict[str, Any]) -> bool:
624
623
  return False
625
624
  envelope = dict(payload_val) if isinstance(payload_val, dict) else {}
626
625
  for key in [k for k in list(arguments) if k != "payload"]:
627
- envelope.setdefault(key, arguments.pop(key))
626
+ sibling = arguments.pop(key)
627
+ # A real payload value wins; an empty placeholder ({}/None/"") loses to a non-empty sibling.
628
+ if key not in envelope or (not envelope.get(key) and sibling):
629
+ envelope[key] = sibling
628
630
  arguments["payload"] = envelope
629
631
  return True
630
632
 
@@ -992,13 +994,13 @@ async def build_agent_args(
992
994
 
993
995
  _configure_output(args=args, agent=xpander_agent, task=task)
994
996
  _configure_session_storage(args=args, agent=xpander_agent, task=task)
995
- _configure_agentic_memory(args=args, agent=xpander_agent, task=task)
996
997
  _configure_context_optimizer(args=args, agent=xpander_agent, task=task, model=model)
997
998
 
998
999
  # The deps leg (DB fetch + the sync configures that override its args keys —
999
1000
  # order preserved) is independent of tool/MCP resolution, so overlap them: on a
1000
1001
  # cold agent this runs the conn-string fetch concurrently with the MCP probes.
1001
1002
  async def _attach_deps_leg() -> None:
1003
+ await _configure_user_memories(args=args, agent=xpander_agent, task=task)
1002
1004
  await _attach_async_dependencies(
1003
1005
  args=args, agent=xpander_agent, task=task, model=model, is_async=is_async
1004
1006
  )
@@ -1040,6 +1042,11 @@ async def build_agent_args(
1040
1042
  if tools and len(tools) != 0:
1041
1043
  args["tools"].extend(tools)
1042
1044
 
1045
+ _mem_user = task.input.user if task and task.input else None
1046
+ _mem_enabled = args.pop("_xpander_memory_enabled", True)
1047
+ if task and _mem_user and _mem_user.id and not xpander_agent.is_a_team and _mem_enabled:
1048
+ args["tools"].append(_build_memory_tool(xpander_agent, task))
1049
+
1043
1050
  # Inline agent-gateway children (and any non-DP task) must not see the planning
1044
1051
  # tool family — hide it so the agent can't call it.
1045
1052
  _strip_planning_tools_if_inactive(args=args, agent=xpander_agent, task=task)
@@ -3220,42 +3227,229 @@ def _configure_session_storage(
3220
3227
  args["max_tool_calls_from_history"] = max_tool_calls
3221
3228
 
3222
3229
 
3223
- def _configure_agentic_memory(
3224
- args: Dict[str, Any], agent: Agent, task: Optional[Task]
3225
- ) -> None:
3226
- learning_enabled = True if agent.agno_settings.learning else False
3227
- user = task.input.user if task and task.input and task.input.user else None
3228
- # omni and autonomous agents get user memories automatically, no explicit opt-in needed
3229
- memories_requested = (
3230
- agent.agno_settings.user_memories or agent.is_omni or agent.is_autonomous
3231
- )
3232
- user_memories_enabled = True if memories_requested and user and user.id else False
3233
- agent_memories_enabled = True if agent.agno_settings.agent_memories else False
3230
+ MEMORY_MAX_CHARS = 300
3231
+ _MEMORY_FETCH_TIMEOUT_S = 1.5
3232
+ _MEMORY_PERSIST_TIMEOUT_S = 10
3233
+ _MEMORY_SCOPES = {"user", "agent"}
3234
+ _MEMORY_ACTIONS = {"save": "Saved.", "update": "Updated.", "delete": "Deleted."}
3234
3235
 
3235
- if learning_enabled:
3236
- args["learning"] = True
3237
3236
 
3238
- # fully agentic: the LLM manages memories via the agno memory tool; no automatic
3239
- # post-run extraction (enable_user_memories / update_memory_on_run is intentionally off)
3240
- if user_memories_enabled:
3241
- args["memory_manager"] = MemoryManager(
3242
- delete_memories=True, clear_memories=True
3243
- )
3237
+ def _sanitize_memory(text: Any) -> str:
3238
+ """One-line, tag-free memory text: a stored `</memories>` would otherwise close the
3239
+ context block and turn a memory into free-standing instructions for every later run."""
3240
+ cleaned = re.sub(r"[<>]", "", str(text or ""))
3241
+ return re.sub(r"\s+", " ", cleaned).strip()[:MEMORY_MAX_CHARS]
3244
3242
 
3245
- if (user_memories_enabled or agent_memories_enabled) and not agent.is_a_team:
3246
- args["enable_agentic_memory"] = True
3247
3243
 
3248
- if agent_memories_enabled and not agent.is_a_team:
3249
- args["add_culture_to_context"] = True
3244
+ def _render_memories_block(bundle: Dict[str, Any]) -> str:
3245
+ """Render the xpander memories bundle as the context block, or "" when empty."""
3246
+ if not bool((bundle.get("settings") or {}).get("enabled", True)):
3247
+ return ""
3248
+ user_rows = bundle.get("user") or []
3249
+ agent_rows = bundle.get("agent") or []
3250
+ if not user_rows and not agent_rows:
3251
+ return ""
3250
3252
 
3251
- if agent.agno_settings.agentic_culture:
3252
- args["enable_agentic_culture"] = True
3253
- else:
3254
- args["update_cultural_knowledge"] = True
3253
+ def _lines(rows: List[Dict[str, Any]], with_writer: bool) -> List[str]:
3254
+ out = []
3255
+ for row in rows:
3256
+ mem_id = str(row.get("memory_id", ""))[:8]
3257
+ date = str(row.get("updated_at", ""))[:10]
3258
+ writer = _sanitize_memory(row.get("writer_agent_name"))
3259
+ meta = f"by {writer}, {date}" if with_writer and writer else date
3260
+ out.append(f"- [{mem_id}] ({meta}) {_sanitize_memory(row.get('memory'))}")
3261
+ return out
3262
+
3263
+ parts = [
3264
+ '<memories note="Durable memories. Do not re-save facts already listed; '
3265
+ 'use manage_memory with the id to update or delete.">'
3266
+ ]
3267
+ if user_rows:
3268
+ parts.append("USER (about this user, shared across all agents):")
3269
+ parts.extend(_lines(user_rows, with_writer=True))
3270
+ if agent_rows:
3271
+ parts.append("AGENT (this agent's own knowledge, all users):")
3272
+ parts.extend(_lines(agent_rows, with_writer=False))
3273
+ parts.append("</memories>")
3274
+ return "\n".join(parts)
3275
+
3276
+
3277
+ def _build_memory_tool(agent: Agent, task: Task) -> Any:
3278
+ """Build the ``manage_memory`` agno Function (save/update/delete, fire-and-forget)."""
3279
+ from agno.tools.function import Function
3280
+
3281
+ from xpander_sdk.consts.api_routes import APIRoute
3282
+ from xpander_sdk.core.xpander_api_client import APIClient
3283
+
3284
+ user = task.input.user if task.input else None
3285
+ user_id = user.id if user else None
3286
+ path = APIRoute.UserMemories.value.format(agent_id=agent.id)
3255
3287
 
3256
- if user: # add user details to the agent
3288
+ async def _persist(body: Dict[str, Any]) -> None:
3289
+ # contained + bounded: an unretrieved raise_for_status would otherwise surface as
3290
+ # "Task exception was never retrieved", and the client default timeout is 20 min
3291
+ try:
3292
+ client = APIClient(configuration=agent.configuration)
3293
+ await asyncio.wait_for(
3294
+ client.make_request(path=path, method="POST", payload=body),
3295
+ timeout=_MEMORY_PERSIST_TIMEOUT_S,
3296
+ )
3297
+ except Exception as e:
3298
+ logger.debug(f"[memories] persist failed for agent {agent.id}: {e}")
3299
+
3300
+ def _entrypoint(payload: Optional[Union[Dict[str, Any], str]] = None) -> str:
3301
+ """Persist a memory operation in the background and return immediately."""
3302
+ if isinstance(payload, str):
3303
+ parsed = parse_structured_string(payload)
3304
+ payload = parsed if isinstance(parsed, dict) else {}
3305
+ payload = payload or {}
3306
+ action = str(payload.get("action", "")).lower()
3307
+ scope = str(payload.get("scope", "user")).lower()
3308
+ memory = _sanitize_memory(payload.get("memory"))
3309
+ memory_id = str(payload.get("memory_id") or "").strip()
3310
+
3311
+ if action not in _MEMORY_ACTIONS:
3312
+ return "Invalid action: use save, update or delete."
3313
+ if scope not in _MEMORY_SCOPES:
3314
+ return "Invalid scope: use user or agent."
3315
+ if action in {"save", "update"} and not memory:
3316
+ return "Missing memory text."
3317
+ if action in {"update", "delete"} and not memory_id:
3318
+ return "Missing memory_id (use the id shown in <memories>)."
3319
+ if scope == "user" and not user_id:
3320
+ return "No user on this run; only agent scope is available."
3321
+
3322
+ body = {
3323
+ "action": action,
3324
+ "scope": scope,
3325
+ "memory": memory or None,
3326
+ "memory_id": memory_id or None,
3327
+ "user_id": user_id,
3328
+ "writer_agent_id": agent.id,
3329
+ "writer_agent_name": getattr(agent, "name", None) or agent.id,
3330
+ }
3331
+ coro = _persist(body)
3332
+ try:
3333
+ _spawn_bg(coro)
3334
+ except RuntimeError:
3335
+ # sync entrypoint path (backend.get_args + Agent.run): no running loop here
3336
+ run_sync(coro)
3337
+ return _MEMORY_ACTIONS[action]
3338
+
3339
+ return Function(
3340
+ name="manage_memory",
3341
+ description=(
3342
+ "Persist durable memories without being asked. save: the user reveals a stable "
3343
+ "fact or preference (scope 'user': about the person, shared across ALL their "
3344
+ "agents - role, team, how they like answers) or you learn user-agnostic knowledge "
3345
+ "this agent should keep (scope 'agent', visible to every user of this agent). "
3346
+ "ESPECIALLY save scope 'agent' when you overcome an issue: after failed attempts "
3347
+ "you found the approach that works (right flag, endpoint, workaround, ordering) - "
3348
+ "save the lesson so future runs skip the dead ends. "
3349
+ "update/delete: a listed memory changed or the user asks to forget it - pass its "
3350
+ "memory_id from <memories>. BEFORE saving, reason whether it is WORTH saving: "
3351
+ "would this still matter in a month, on unrelated tasks? If not, do not save. "
3352
+ "The current request itself is NEVER a memory - 'save/export my memories to a "
3353
+ "file', 'summarize this doc', 'send this email' are tasks to PERFORM, not facts "
3354
+ "to remember. Keep memories short (one concise sentence, max "
3355
+ f"{MEMORY_MAX_CHARS} chars). Never store secrets, credentials, or one-off task "
3356
+ "details. Do not re-save facts already listed in <memories>. "
3357
+ "Wrap arguments in a `payload` object."
3358
+ ),
3359
+ parameters={
3360
+ "type": "object",
3361
+ "properties": {
3362
+ "payload": {
3363
+ "type": "object",
3364
+ "properties": {
3365
+ "action": {
3366
+ "type": "string",
3367
+ "enum": ["save", "update", "delete"],
3368
+ },
3369
+ "scope": {
3370
+ "type": "string",
3371
+ "enum": ["user", "agent"],
3372
+ "description": "user = about this person, cross-agent. agent = this agent's own knowledge, all users.",
3373
+ },
3374
+ "memory": {
3375
+ "type": "string",
3376
+ "description": "The memory text (save/update). One short sentence.",
3377
+ },
3378
+ "memory_id": {
3379
+ "type": "string",
3380
+ "description": "Id from the <memories> block (update/delete).",
3381
+ },
3382
+ "headers": {
3383
+ "type": "object",
3384
+ "properties": {
3385
+ "toolcallreasoningtitle": {
3386
+ "type": "string",
3387
+ "description": 'Action-oriented title (max 5 words). Example: "Remember user preference".',
3388
+ },
3389
+ "toolcallreasoningdescription": {
3390
+ "type": "string",
3391
+ "description": 'One-sentence summary (max 100 characters). Example: "Save that the user prefers Hebrew answers."',
3392
+ },
3393
+ },
3394
+ "required": [
3395
+ "toolcallreasoningtitle",
3396
+ "toolcallreasoningdescription",
3397
+ ],
3398
+ },
3399
+ },
3400
+ "required": ["action", "scope", "headers"],
3401
+ },
3402
+ },
3403
+ "required": ["payload"],
3404
+ },
3405
+ entrypoint=_entrypoint,
3406
+ )
3407
+
3408
+
3409
+ async def _configure_user_memories(
3410
+ args: Dict[str, Any], agent: Agent, task: Optional[Task]
3411
+ ) -> None:
3412
+ """Wire the xpander memory layer: prepend the <memories> block + inject manage_memory."""
3413
+ if agent.agno_settings.learning:
3414
+ args["learning"] = True
3415
+
3416
+ user = task.input.user if task and task.input and task.input.user else None
3417
+ if user:
3257
3418
  args["additional_context"] = f"User details: {user.model_dump_json()}"
3258
3419
 
3420
+ if not task or agent.is_a_team:
3421
+ return
3422
+
3423
+ block = ""
3424
+ # the gateway prepends the block into dispatched children's additional_context;
3425
+ # fetching again would duplicate it and waste a round-trip
3426
+ gateway_passed = "<memories note=" in (task.additional_context or "")
3427
+ if not gateway_passed and (user and user.id):
3428
+ try:
3429
+ from xpander_sdk.consts.api_routes import APIRoute
3430
+ from xpander_sdk.core.xpander_api_client import APIClient
3431
+
3432
+ client = APIClient(configuration=agent.configuration)
3433
+ bundle = await asyncio.wait_for(
3434
+ client.make_request(
3435
+ path=APIRoute.UserMemories.value.format(agent_id=agent.id),
3436
+ query={"user_id": user.id},
3437
+ ),
3438
+ timeout=_MEMORY_FETCH_TIMEOUT_S,
3439
+ )
3440
+ if isinstance(bundle, dict):
3441
+ block = _render_memories_block(bundle)
3442
+ # honor the user's master toggle: no block AND no save tool when off
3443
+ args["_xpander_memory_enabled"] = bool(
3444
+ (bundle.get("settings") or {}).get("enabled", True)
3445
+ )
3446
+ except Exception as e:
3447
+ logger.debug(f"[memories] fetch skipped for agent {agent.id}: {e}")
3448
+
3449
+ if block:
3450
+ existing = args.get("additional_context", "")
3451
+ args["additional_context"] = f"{block}\n\n{existing}" if existing else block
3452
+
3259
3453
 
3260
3454
  async def _attach_async_dependencies(
3261
3455
  args: Dict[str, Any],
@@ -3264,17 +3458,7 @@ async def _attach_async_dependencies(
3264
3458
  model: Any,
3265
3459
  is_async: Optional[bool] = True,
3266
3460
  ) -> None:
3267
- user = task.input.user if task and task.input and task.input.user else None
3268
- memories_requested = (
3269
- agent.agno_settings.user_memories or agent.is_omni or agent.is_autonomous
3270
- )
3271
- should_use_db = (
3272
- True
3273
- if (memories_requested and user and user.id)
3274
- or agent.agno_settings.agent_memories
3275
- else False
3276
- )
3277
- if agent.agno_settings.session_storage or should_use_db:
3461
+ if agent.agno_settings.session_storage:
3278
3462
  args["db"] = await agent.aget_db(async_db=is_async)
3279
3463
 
3280
3464
 
@@ -28,7 +28,7 @@ class _CoercingPayloadBase(BaseModel):
28
28
 
29
29
  @model_validator(mode="before")
30
30
  @classmethod
31
- def _coerce_string_payload(cls, data):
31
+ def _coerce_string_payload(cls, data: Any) -> Any:
32
32
  if isinstance(data, str):
33
33
  parsed = parse_structured_string(data)
34
34
  if isinstance(parsed, dict):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xpander-sdk
3
- Version: 2.0.415
3
+ Version: 2.0.417
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
File without changes
File without changes
File without changes