xpander-sdk 2.0.414__tar.gz → 2.0.415__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.414/src/xpander_sdk.egg-info → xpander_sdk-2.0.415}/PKG-INFO +1 -1
  2. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/setup.py +1 -1
  3. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/__init__.py +1 -1
  4. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/finalize_mode.py +45 -8
  5. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/frameworks/agno.py +44 -2
  6. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/utils/schemas.py +15 -13
  7. xpander_sdk-2.0.415/src/xpander_sdk/utils/json_parsing.py +35 -0
  8. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415/src/xpander_sdk.egg-info}/PKG-INFO +1 -1
  9. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk.egg-info/SOURCES.txt +1 -0
  10. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/LICENSE +0 -0
  11. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/README.md +0 -0
  12. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/pyproject.toml +0 -0
  13. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/setup.cfg +0 -0
  14. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/consts/__init__.py +0 -0
  15. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/consts/api_routes.py +0 -0
  16. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/__init__.py +0 -0
  17. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/__init__.py +0 -0
  18. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/action_ledger.py +0 -0
  19. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/compact_retry_result.py +0 -0
  20. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/completion_evidence.py +0 -0
  21. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/constants.py +0 -0
  22. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/context_optimizer.py +0 -0
  23. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/encryption.py +0 -0
  24. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/error_patterns.py +0 -0
  25. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/helpers/__init__.py +0 -0
  26. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/helpers/chunking.py +0 -0
  27. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/helpers/recent_actions.py +0 -0
  28. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/helpers/secrets.py +0 -0
  29. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/helpers/tool_result.py +0 -0
  30. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/helpers/xml_safety.py +0 -0
  31. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/mixins/__init__.py +0 -0
  32. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/mixins/map_reduce.py +0 -0
  33. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/multimodal_error_patterns.py +0 -0
  34. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/prompts.py +0 -0
  35. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/search.py +0 -0
  36. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/context_optimizer/workspace_cache.py +0 -0
  37. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/module_base.py +0 -0
  38. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/state.py +0 -0
  39. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/core/xpander_api_client.py +0 -0
  40. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/exceptions/__init__.py +0 -0
  41. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/exceptions/module_exception.py +0 -0
  42. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/models/__init__.py +0 -0
  43. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/models/action_ledger.py +0 -0
  44. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/models/activity.py +0 -0
  45. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/models/compactization.py +0 -0
  46. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/models/configuration.py +0 -0
  47. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/models/context_status.py +0 -0
  48. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/models/deep_planning.py +0 -0
  49. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/models/events.py +0 -0
  50. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/models/frameworks.py +0 -0
  51. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/models/generic.py +0 -0
  52. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/models/notifications.py +0 -0
  53. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/models/orchestrations.py +0 -0
  54. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/models/shared.py +0 -0
  55. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/models/user.py +0 -0
  56. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/__init__.py +0 -0
  57. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/agents/__init__.py +0 -0
  58. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/agents/agents_module.py +0 -0
  59. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/agents/models/__init__.py +0 -0
  60. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/agents/models/agent.py +0 -0
  61. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/agents/models/agent_list.py +0 -0
  62. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/agents/models/knowledge_bases.py +0 -0
  63. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/agents/sub_modules/__init__.py +0 -0
  64. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/agents/sub_modules/agent.py +0 -0
  65. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/agents/utils/__init__.py +0 -0
  66. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/agents/utils/generic.py +0 -0
  67. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/__init__.py +0 -0
  68. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/backend_module.py +0 -0
  69. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/decorators/__init__.py +0 -0
  70. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/decorators/on_auth_event.py +0 -0
  71. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/events_registry.py +0 -0
  72. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/frameworks/__init__.py +0 -0
  73. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/frameworks/_anthropic_cache.py +0 -0
  74. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/frameworks/_bedrock_cache.py +0 -0
  75. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/frameworks/dispatch.py +0 -0
  76. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/utils/__init__.py +0 -0
  77. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/utils/extra_headers.py +0 -0
  78. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/utils/mcp_connect.py +0 -0
  79. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/utils/mcp_oauth.py +0 -0
  80. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/backend/utils/tool_call_events.py +0 -0
  81. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/events/__init__.py +0 -0
  82. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/events/decorators/__init__.py +0 -0
  83. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/events/decorators/on_boot.py +0 -0
  84. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/events/decorators/on_shutdown.py +0 -0
  85. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/events/decorators/on_task.py +0 -0
  86. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/events/decorators/on_tool.py +0 -0
  87. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/events/events_module.py +0 -0
  88. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/events/models/__init__.py +0 -0
  89. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/events/models/deployments.py +0 -0
  90. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/events/models/events.py +0 -0
  91. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/events/streaming_server.py +0 -0
  92. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/events/utils/__init__.py +0 -0
  93. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/events/utils/generic.py +0 -0
  94. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/events/utils/git_init.py +0 -0
  95. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/knowledge_bases/__init__.py +0 -0
  96. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/knowledge_bases/knowledge_bases_module.py +0 -0
  97. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/knowledge_bases/models/__init__.py +0 -0
  98. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/knowledge_bases/models/knowledge_bases.py +0 -0
  99. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/knowledge_bases/sub_modules/__init__.py +0 -0
  100. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/knowledge_bases/sub_modules/knowledge_base.py +0 -0
  101. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/knowledge_bases/sub_modules/knowledge_base_document_item.py +0 -0
  102. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/knowledge_bases/utils/__init__.py +0 -0
  103. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tasks/__init__.py +0 -0
  104. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tasks/models/__init__.py +0 -0
  105. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tasks/models/task.py +0 -0
  106. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tasks/models/tasks_list.py +0 -0
  107. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tasks/sub_modules/__init__.py +0 -0
  108. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tasks/sub_modules/task.py +0 -0
  109. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tasks/tasks_module.py +0 -0
  110. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tasks/utils/__init__.py +0 -0
  111. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tasks/utils/files.py +0 -0
  112. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tasks/utils/media.py +0 -0
  113. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tasks/utils/model_capabilities.py +0 -0
  114. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/__init__.py +0 -0
  115. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/decorators/__init__.py +0 -0
  116. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/decorators/register_tool.py +0 -0
  117. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/models/__init__.py +0 -0
  118. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/models/mcp.py +0 -0
  119. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/models/tool_invocation_result.py +0 -0
  120. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/sub_modules/__init__.py +0 -0
  121. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/sub_modules/dynamic_tools.py +0 -0
  122. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/sub_modules/mcp_tool_proxy.py +0 -0
  123. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/sub_modules/tool.py +0 -0
  124. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/tools_repository_module.py +0 -0
  125. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/utils/__init__.py +0 -0
  126. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/utils/billing_context.py +0 -0
  127. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/utils/generic.py +0 -0
  128. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/utils/local_tools.py +0 -0
  129. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/modules/tools_repository/utils/workspace_payload.py +0 -0
  130. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/utils/__init__.py +0 -0
  131. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/utils/agents/__init__.py +0 -0
  132. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/utils/cache.py +0 -0
  133. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/utils/db/__init__.py +0 -0
  134. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/utils/db/engine_registry.py +0 -0
  135. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/utils/env.py +0 -0
  136. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/utils/event_loop.py +0 -0
  137. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/utils/generic.py +0 -0
  138. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk/utils/tools.py +0 -0
  139. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk.egg-info/dependency_links.txt +0 -0
  140. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk.egg-info/requires.txt +0 -0
  141. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/src/xpander_sdk.egg-info/top_level.txt +0 -0
  142. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_action_ledger_dedup.py +0 -0
  143. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_agent_instructions_render.py +0 -0
  144. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_aget_db_engine_registry.py +0 -0
  145. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_agno_cpu_hotpaths.py +0 -0
  146. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_anthropic_prompt_cache.py +0 -0
  147. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_auto_context_management_toggle.py +0 -0
  148. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_bedrock_prompt_cache.py +0 -0
  149. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_boot_shutdown_handlers.py +0 -0
  150. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_child_startup_perf.py +0 -0
  151. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_context_optimizer_chunked.py +0 -0
  152. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_context_optimizer_perf.py +0 -0
  153. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_context_optimizer_recent_actions.py +0 -0
  154. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_context_optimizer_status_events.py +0 -0
  155. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_context_optimizer_unwrap.py +0 -0
  156. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_context_optimizer_window.py +0 -0
  157. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_context_retrieve_reoffload.py +0 -0
  158. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_context_search.py +0 -0
  159. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_context_window_detection.py +0 -0
  160. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_cross_subexec_decrypt.py +0 -0
  161. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_emergency_connectivity_breaker.py +0 -0
  162. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_encryption.py +0 -0
  163. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_engine_registry.py +0 -0
  164. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_headroom_l0.py +0 -0
  165. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_layer_1_cache_integration.py +0 -0
  166. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_mcp_connect_probe.py +0 -0
  167. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_mcp_oauth_events.py +0 -0
  168. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_mcp_parallel_connect.py +0 -0
  169. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_mcp_preflight_tail.py +0 -0
  170. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_parent_update_deep_planning.py +0 -0
  171. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_planning_tools_visibility.py +0 -0
  172. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_reasoning_inline_gateway.py +0 -0
  173. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_reasoning_plan_task_id.py +0 -0
  174. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_skills_instructions.py +0 -0
  175. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_spawn_bg.py +0 -0
  176. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_tool_call_events.py +0 -0
  177. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_weak_model_reasoning.py +0 -0
  178. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/tests/test_workspace_cache.py +0 -0
  179. {xpander_sdk-2.0.414 → xpander_sdk-2.0.415}/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.414
3
+ Version: 2.0.415
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.414",
8
+ version="2.0.415",
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.414"
18
+ __version__ = "2.0.415"
19
19
 
20
20
  # Backend-related imports
21
21
  from .modules.backend.backend_module import Backend
@@ -18,10 +18,13 @@ already-large ``context_optimizer.py`` and out of the agno hook in
18
18
 
19
19
  from __future__ import annotations
20
20
 
21
- from typing import Any, Dict, List, Literal, Optional
21
+ from typing import Any, Dict, List, Literal, Optional, Union
22
22
 
23
23
  from loguru import logger
24
24
 
25
+ from xpander_sdk.core.context_optimizer.action_ledger import get_attached_ledger
26
+ from xpander_sdk.utils.json_parsing import parse_structured_string
27
+
25
28
  from xpander_sdk.models.action_ledger import (
26
29
  EvidenceReport,
27
30
  FinalizeOnlyState,
@@ -171,7 +174,15 @@ def build_finalize_tool(task: Any) -> Any:
171
174
  """
172
175
  from agno.tools.function import Function
173
176
 
174
- async def _entrypoint(payload: Optional[Dict[str, Any]] = None) -> str:
177
+ async def _entrypoint(
178
+ payload: Optional[Union[Dict[str, Any], str]] = None,
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.
183
+ if isinstance(payload, str):
184
+ parsed = parse_structured_string(payload)
185
+ payload = parsed if isinstance(parsed, dict) else {"final_answer": payload}
175
186
  data = payload or {}
176
187
  final_answer = data.get("final_answer", "") or ""
177
188
  completed_items = data.get("completed_items") or []
@@ -258,17 +269,43 @@ async def _run_finalize(
258
269
  # Mark plan items as completed via the deep_planning model (no
259
270
  # round-trip through xpcomplete_agent_plan_items needed; the SDK
260
271
  # serializes deep_planning back on the next status update).
272
+ evidence_note = ""
261
273
  try:
262
274
  if (
263
275
  completed_items
264
276
  and getattr(task, "deep_planning", None)
265
277
  and task.deep_planning.tasks
266
278
  ):
267
- wanted = set(completed_items)
268
- for item in task.deep_planning.tasks:
269
- if item.id in wanted and not item.completed:
270
- item.completed = True
271
- logger.info(f"[finalize-mode] marked {len(wanted)} plan item(s) complete")
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.
284
+ ledger = get_attached_ledger(task)
285
+ all_calls_failed = bool(
286
+ ledger
287
+ and ledger.entries
288
+ and all(entry.status != "ok" for entry in ledger.entries)
289
+ )
290
+ if all_calls_failed:
291
+ evidence_note = (
292
+ "\n\n⚠️ Plan items were NOT marked completed: every recorded "
293
+ "tool call in this run failed, so there is no evidence the "
294
+ "work happened."
295
+ )
296
+ logger.warning(
297
+ f"[finalize-mode] refused to mark {len(completed_items)} plan "
298
+ f"item(s) complete — ledger has {len(ledger.entries)} entries, "
299
+ "all failed"
300
+ )
301
+ else:
302
+ wanted = set(completed_items)
303
+ for item in task.deep_planning.tasks:
304
+ if item.id in wanted and not item.completed:
305
+ item.completed = True
306
+ logger.info(
307
+ f"[finalize-mode] marked {len(wanted)} plan item(s) complete"
308
+ )
272
309
  except Exception as exc:
273
310
  logger.warning(f"[finalize-mode] plan-item update failed: {exc}")
274
311
 
@@ -279,4 +316,4 @@ async def _run_finalize(
279
316
  except Exception as exc:
280
317
  logger.warning(f"[finalize-mode] failed to set task.result: {exc}")
281
318
 
282
- return final_answer or "Task finalized."
319
+ return (final_answer or "Task finalized.") + evidence_note
@@ -5,7 +5,7 @@ import shlex
5
5
  import uuid
6
6
  from collections import deque
7
7
  from os import getenv, environ
8
- from typing import Any, Callable, Dict, List, Optional, Tuple
8
+ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
9
9
 
10
10
  from loguru import logger
11
11
  from xpander_sdk import Configuration
@@ -76,6 +76,7 @@ from xpander_sdk.modules.backend.utils.mcp_connect import (
76
76
  probe_recently_ok,
77
77
  )
78
78
  from xpander_sdk.modules.backend.utils.mcp_oauth import authenticate_mcp_server
79
+ from xpander_sdk.utils.json_parsing import parse_structured_string
79
80
  from xpander_sdk.modules.backend.utils.tool_call_events import (
80
81
  coerce_json_like,
81
82
  DYNAMIC_META_TOOLS,
@@ -224,6 +225,9 @@ results/success table (rows like "applied", "updated", "created", "22/22 ✓") f
224
225
  execute — if you did not call the tool, say what you WOULD do, not that you did it.
225
226
  Never invent, quote, or attribute a prior user message or request that is not in the conversation
226
227
  above; if you are unsure whether something was asked, check or ask rather than assert it happened.
228
+ A tool result carrying an HTTP 4xx/5xx or error(...) is a FAILURE, not an empty result. Never report
229
+ it as "no results found" / "nothing matched" — say the lookup failed and why (quote the status), then
230
+ fix the call (e.g. correct the identifier) or surface the failure.
227
231
  </grounding>
228
232
  """
229
233
 
@@ -544,7 +548,12 @@ def _build_compact_tool():
544
548
  """
545
549
  from agno.tools.function import Function
546
550
 
547
- def _entrypoint(payload: Optional[Dict[str, Any]] = None) -> str:
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.
554
+ if isinstance(payload, str):
555
+ parsed = parse_structured_string(payload)
556
+ payload = parsed if isinstance(parsed, dict) else {}
548
557
  focus = (payload or {}).get("focus", "") or ""
549
558
  return f"Compaction scheduled with focus: {focus}"
550
559
 
@@ -596,6 +605,30 @@ def _build_compact_tool():
596
605
  )
597
606
 
598
607
 
608
+ def reenvelope_sibling_args(arguments: Dict[str, Any]) -> bool:
609
+ """Fold sibling keys of ``payload`` into the payload wrapper, in place.
610
+
611
+ Repository tools take a single ``payload`` model arg, but LLMs sometimes
612
+ emit args flat (``command='ls', toolcallplantaskid=''``) or float
613
+ ``headers``/``toolcall*`` out as siblings of ``payload``. validate_call
614
+ then fails with unexpected_keyword_argument / missing_argument before the
615
+ payload model's own before-validator can nest/backfill anything. Mutates
616
+ ``arguments`` in place (agno reads ``self.arguments`` directly) and returns
617
+ True when a fold happened. Skipped when ``payload`` is a non-dict value the
618
+ string-coercion step couldn't parse — nothing sane to merge into.
619
+ """
620
+ if not any(k != "payload" for k in arguments):
621
+ return False
622
+ payload_val = arguments.get("payload")
623
+ if payload_val is not None and not isinstance(payload_val, dict):
624
+ return False
625
+ envelope = dict(payload_val) if isinstance(payload_val, dict) else {}
626
+ for key in [k for k in list(arguments) if k != "payload"]:
627
+ envelope.setdefault(key, arguments.pop(key))
628
+ arguments["payload"] = envelope
629
+ return True
630
+
631
+
599
632
  def _classify_tool_error(error: Exception) -> str:
600
633
  """Classify a tool error as transient, auth, or client.
601
634
 
@@ -1403,6 +1436,15 @@ async def build_agent_args(
1403
1436
  except Exception:
1404
1437
  pass
1405
1438
 
1439
+ # Repository tools take a single `payload` model arg; sibling kwargs
1440
+ # would fail validate_call before the payload model's coercion runs.
1441
+ if matched_tool is not None and isinstance(arguments, dict):
1442
+ if reenvelope_sibling_args(arguments):
1443
+ logger.debug(
1444
+ f"[tool-hook] re-enveloped sibling args into payload for "
1445
+ f"{function_name}"
1446
+ )
1447
+
1406
1448
  # workspace_path payload resolution: when the LLM offloaded a large
1407
1449
  # tool payload to a workspace file, fetch it now and replace
1408
1450
  # `arguments` with the resolved dict. Runs *before* activity logging
@@ -8,6 +8,7 @@ from xpander_sdk.modules.tools_repository.utils.generic import (
8
8
  json_type_to_python,
9
9
  pascal_case,
10
10
  )
11
+ from xpander_sdk.utils.json_parsing import parse_structured_string
11
12
 
12
13
  from pydantic import BaseModel, create_model, ConfigDict
13
14
  from typing import Optional, Type, Dict, Any
@@ -29,14 +30,9 @@ class _CoercingPayloadBase(BaseModel):
29
30
  @classmethod
30
31
  def _coerce_string_payload(cls, data):
31
32
  if isinstance(data, str):
32
- s = data.strip()
33
- if s.startswith("{") and s.endswith("}"):
34
- try:
35
- parsed = json.loads(s)
36
- if isinstance(parsed, dict):
37
- data = parsed
38
- except json.JSONDecodeError:
39
- pass
33
+ parsed = parse_structured_string(data)
34
+ if isinstance(parsed, dict):
35
+ data = parsed
40
36
  if isinstance(data, dict):
41
37
  data = cls._nest_flat_body_params(data)
42
38
  data = cls._hoist_misplaced_reasoning_headers(data)
@@ -54,13 +50,19 @@ class _CoercingPayloadBase(BaseModel):
54
50
  call carries the arguments the model intended, merging with any partial
55
51
  body_params already present without overwriting its keys. No-op unless the
56
52
  model has a ``body_params`` field; skipped when query/path params are
57
- populated to avoid misrouting a genuinely different envelope."""
53
+ populated to avoid misrouting a genuinely different envelope — unless
54
+ ``body_params`` is required and absent, where bailing out guarantees a
55
+ "Field required" failure and nesting is the only viable read."""
58
56
  if "body_params" not in cls.model_fields:
59
57
  return data
60
- for envelope in ("query_params", "path_params"):
61
- val = data.get(envelope)
62
- if isinstance(val, dict) and val:
63
- return data
58
+ body_required_and_missing = cls.model_fields[
59
+ "body_params"
60
+ ].is_required() and not isinstance(data.get("body_params"), dict)
61
+ if not body_required_and_missing:
62
+ for envelope in ("query_params", "path_params"):
63
+ val = data.get(envelope)
64
+ if isinstance(val, dict) and val:
65
+ return data
64
66
  reserved = set(cls.model_fields) | {"headers", "workspace_path"}
65
67
  stray = {
66
68
  k: v
@@ -0,0 +1,35 @@
1
+ import ast
2
+ import json
3
+ from typing import Any, Optional
4
+
5
+
6
+ def parse_structured_string(value: str) -> Optional[Any]:
7
+ """Parse a string that plausibly encodes a dict/list, returning None on failure.
8
+
9
+ Three tiers, mirroring the leniency LLM tool-call payloads need in practice:
10
+ strict JSON first, then ``strict=False`` (payloads with literal newlines/tabs
11
+ inside string values, e.g. a file-write ``content`` field), then a Python
12
+ literal (single quotes). Plain text never parses and returns None.
13
+ """
14
+ stripped = value.strip()
15
+ if not (stripped.startswith(("{", "[")) and stripped.endswith(("}", "]"))):
16
+ return None
17
+ try:
18
+ parsed = json.loads(stripped)
19
+ if isinstance(parsed, (dict, list)):
20
+ return parsed
21
+ except Exception:
22
+ pass
23
+ try:
24
+ parsed = json.loads(stripped, strict=False)
25
+ if isinstance(parsed, (dict, list)):
26
+ return parsed
27
+ except Exception:
28
+ pass
29
+ try:
30
+ parsed = ast.literal_eval(stripped)
31
+ if isinstance(parsed, (dict, list, tuple)):
32
+ return list(parsed) if isinstance(parsed, tuple) else parsed
33
+ except Exception:
34
+ pass
35
+ return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xpander-sdk
3
- Version: 2.0.414
3
+ Version: 2.0.415
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
@@ -132,6 +132,7 @@ src/xpander_sdk/utils/cache.py
132
132
  src/xpander_sdk/utils/env.py
133
133
  src/xpander_sdk/utils/event_loop.py
134
134
  src/xpander_sdk/utils/generic.py
135
+ src/xpander_sdk/utils/json_parsing.py
135
136
  src/xpander_sdk/utils/tools.py
136
137
  src/xpander_sdk/utils/agents/__init__.py
137
138
  src/xpander_sdk/utils/db/__init__.py
File without changes
File without changes
File without changes