xpander-sdk 2.0.206__tar.gz → 2.0.207__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 (113) hide show
  1. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/PKG-INFO +1 -1
  2. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/setup.py +1 -1
  3. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tools_repository/tools_repository_module.py +65 -3
  4. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tools_repository/utils/schemas.py +20 -7
  5. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk.egg-info/PKG-INFO +1 -1
  6. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk.egg-info/SOURCES.txt +2 -0
  7. xpander_sdk-2.0.207/tests/test_final_validation.py +74 -0
  8. xpander_sdk-2.0.207/tests/test_tool_schema_enhancements.py +105 -0
  9. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/LICENSE +0 -0
  10. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/README.md +0 -0
  11. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/pyproject.toml +0 -0
  12. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/setup.cfg +0 -0
  13. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/__init__.py +0 -0
  14. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/consts/__init__.py +0 -0
  15. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/consts/api_routes.py +0 -0
  16. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/core/__init__.py +0 -0
  17. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/core/module_base.py +0 -0
  18. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/core/state.py +0 -0
  19. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/core/xpander_api_client.py +0 -0
  20. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/exceptions/__init__.py +0 -0
  21. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/exceptions/module_exception.py +0 -0
  22. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/models/__init__.py +0 -0
  23. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/models/activity.py +0 -0
  24. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/models/compactization.py +0 -0
  25. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/models/configuration.py +0 -0
  26. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/models/deep_planning.py +0 -0
  27. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/models/events.py +0 -0
  28. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/models/frameworks.py +0 -0
  29. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/models/generic.py +0 -0
  30. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/models/notifications.py +0 -0
  31. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/models/orchestrations.py +0 -0
  32. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/models/shared.py +0 -0
  33. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/models/user.py +0 -0
  34. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/__init__.py +0 -0
  35. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/agents/__init__.py +0 -0
  36. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/agents/agents_module.py +0 -0
  37. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/agents/models/__init__.py +0 -0
  38. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/agents/models/agent.py +0 -0
  39. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/agents/models/agent_list.py +0 -0
  40. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/agents/models/knowledge_bases.py +0 -0
  41. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/agents/sub_modules/__init__.py +0 -0
  42. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/agents/sub_modules/agent.py +0 -0
  43. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/agents/utils/__init__.py +0 -0
  44. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/agents/utils/generic.py +0 -0
  45. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/backend/__init__.py +0 -0
  46. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/backend/backend_module.py +0 -0
  47. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/backend/decorators/__init__.py +0 -0
  48. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/backend/decorators/on_auth_event.py +0 -0
  49. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/backend/events_registry.py +0 -0
  50. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/backend/frameworks/__init__.py +0 -0
  51. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/backend/frameworks/agno.py +0 -0
  52. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/backend/frameworks/dispatch.py +0 -0
  53. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/backend/utils/__init__.py +0 -0
  54. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/backend/utils/mcp_oauth.py +0 -0
  55. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/events/__init__.py +0 -0
  56. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/events/decorators/__init__.py +0 -0
  57. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/events/decorators/on_boot.py +0 -0
  58. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/events/decorators/on_shutdown.py +0 -0
  59. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/events/decorators/on_task.py +0 -0
  60. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/events/decorators/on_tool.py +0 -0
  61. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/events/events_module.py +0 -0
  62. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/events/models/__init__.py +0 -0
  63. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/events/models/deployments.py +0 -0
  64. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/events/models/events.py +0 -0
  65. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/events/utils/__init__.py +0 -0
  66. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/events/utils/generic.py +0 -0
  67. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/events/utils/git_init.py +0 -0
  68. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/knowledge_bases/__init__.py +0 -0
  69. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/knowledge_bases/knowledge_bases_module.py +0 -0
  70. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/knowledge_bases/models/__init__.py +0 -0
  71. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/knowledge_bases/models/knowledge_bases.py +0 -0
  72. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/knowledge_bases/sub_modules/__init__.py +0 -0
  73. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/knowledge_bases/sub_modules/knowledge_base.py +0 -0
  74. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/knowledge_bases/sub_modules/knowledge_base_document_item.py +0 -0
  75. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/knowledge_bases/utils/__init__.py +0 -0
  76. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tasks/__init__.py +0 -0
  77. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tasks/models/__init__.py +0 -0
  78. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tasks/models/task.py +0 -0
  79. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tasks/models/tasks_list.py +0 -0
  80. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tasks/sub_modules/__init__.py +0 -0
  81. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tasks/sub_modules/task.py +0 -0
  82. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tasks/tasks_module.py +0 -0
  83. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tasks/utils/__init__.py +0 -0
  84. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tasks/utils/files.py +0 -0
  85. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tools_repository/__init__.py +0 -0
  86. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tools_repository/decorators/__init__.py +0 -0
  87. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tools_repository/decorators/register_tool.py +0 -0
  88. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tools_repository/models/__init__.py +0 -0
  89. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tools_repository/models/mcp.py +0 -0
  90. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tools_repository/models/tool_invocation_result.py +0 -0
  91. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tools_repository/sub_modules/__init__.py +0 -0
  92. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tools_repository/sub_modules/tool.py +0 -0
  93. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tools_repository/utils/__init__.py +0 -0
  94. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tools_repository/utils/generic.py +0 -0
  95. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/modules/tools_repository/utils/local_tools.py +0 -0
  96. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/utils/__init__.py +0 -0
  97. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/utils/agents/__init__.py +0 -0
  98. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/utils/agents/compactization_agent.py +0 -0
  99. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/utils/env.py +0 -0
  100. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/utils/event_loop.py +0 -0
  101. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/utils/generic.py +0 -0
  102. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk/utils/tools.py +0 -0
  103. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk.egg-info/dependency_links.txt +0 -0
  104. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk.egg-info/requires.txt +0 -0
  105. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/src/xpander_sdk.egg-info/top_level.txt +0 -0
  106. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/tests/test_agents_module.py +0 -0
  107. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/tests/test_api_client.py +0 -0
  108. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/tests/test_backend_module.py +0 -0
  109. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/tests/test_boot_shutdown_handlers.py +0 -0
  110. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/tests/test_configuration.py +0 -0
  111. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/tests/test_knowledge_bases_module.py +0 -0
  112. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/tests/test_tasks_module.py +0 -0
  113. {xpander_sdk-2.0.206 → xpander_sdk-2.0.207}/tests/test_tools_repository.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xpander-sdk
3
- Version: 2.0.206
3
+ Version: 2.0.207
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.206",
8
+ version="2.0.207",
9
9
  author="xpanderAI",
10
10
  author_email="dev@xpander.ai",
11
11
  description="xpander.ai Backend-as-a-service for AI Agents - SDK",
@@ -159,8 +159,33 @@ class ToolsRepository(XPanderSharedModel):
159
159
 
160
160
  for tool in self.list:
161
161
 
162
- # add json schema to the model doc
163
- tool.schema.__doc__ = "Pay attention to the schema, dont miss. " + json.dumps(tool.schema.model_json_schema(mode="serialization"))
162
+ # add json schema to the model doc with enhanced guidance
163
+ schema_json = tool.schema.model_json_schema(mode="serialization")
164
+
165
+ # Build example with actual schema structure
166
+ example_payload = {}
167
+ if 'properties' in schema_json:
168
+ for prop_name, prop_def in schema_json['properties'].items():
169
+ if prop_def.get('type') == 'object':
170
+ if prop_def.get('properties'):
171
+ # Show one example nested field
172
+ first_nested = list(prop_def['properties'].keys())[0]
173
+ example_payload[prop_name] = {first_nested: "<value>"}
174
+ else:
175
+ example_payload[prop_name] = {}
176
+ else:
177
+ example_payload[prop_name] = f"<{prop_def.get('type', 'value')}>"
178
+
179
+ tool.schema.__doc__ = f"""CRITICAL: This entire schema must be wrapped in a 'payload' parameter.
180
+
181
+ Call this function as: function_name(payload={{...}})
182
+ DO NOT call as: function_name(body_params={{...}}, headers={{...}}, ...)
183
+
184
+ Example correct call:
185
+ {json.dumps({"payload": example_payload}, indent=2)}
186
+
187
+ Full schema: {json.dumps(schema_json, indent=2)}
188
+ """
164
189
 
165
190
  schema_cls: Type[BaseModel] = tool.schema
166
191
 
@@ -208,7 +233,44 @@ class ToolsRepository(XPanderSharedModel):
208
233
 
209
234
  # --- Metadata ---
210
235
  tool_function.__name__ = tool_ref.id
211
- tool_function.__doc__ = tool_ref.description or tool_ref.name
236
+
237
+ # Build comprehensive docstring with parameter structure guidance
238
+ base_doc = tool_ref.description or tool_ref.name
239
+
240
+ # Extract schema properties for examples
241
+ schema_props = schema_ref.model_json_schema().get('properties', {})
242
+ param_names = list(schema_props.keys())
243
+
244
+ # Create example structure
245
+ example_parts = []
246
+ for prop_name in param_names:
247
+ prop_info = schema_props.get(prop_name, {})
248
+ if prop_info.get('type') == 'object' and prop_info.get('properties'):
249
+ # Show nested structure
250
+ nested_props = list(prop_info['properties'].keys())
251
+ if nested_props:
252
+ example_parts.append(f'"{prop_name}": {{"{nested_props[0]}": ...}}')
253
+ else:
254
+ example_parts.append(f'"{prop_name}": {{}}')
255
+ else:
256
+ example_parts.append(f'"{prop_name}": ...')
257
+
258
+ example_json = "{" + ", ".join(example_parts) + "}"
259
+
260
+ tool_function.__doc__ = f"""{base_doc}
261
+
262
+ IMPORTANT - Parameter Structure:
263
+ All parameters must be passed as a single 'payload' object containing the required fields.
264
+
265
+ Correct usage example:
266
+ {{
267
+ "payload": {example_json}
268
+ }}
269
+
270
+ DO NOT pass parameters as separate top-level arguments.
271
+ DO NOT use: {{"{param_names[0] if param_names else 'param'}": ..., "{param_names[1] if len(param_names) > 1 else 'param2'}": ...}}
272
+ USE: {{"payload": {{"{param_names[0] if param_names else 'param'}": ..., "{param_names[1] if len(param_names) > 1 else 'param2'}": ..., ...}}}}
273
+ """
212
274
 
213
275
  # --- Signature ---
214
276
  payload_param = Parameter(
@@ -98,20 +98,24 @@ def build_model_from_schema(
98
98
 
99
99
  field_args = {}
100
100
 
101
- # Enhance description to clarify optional vs required status
101
+ # Enhance description to clarify optional vs required status AND nesting
102
102
  enhanced_description = description or f"Parameter: {prop_name}"
103
+
104
+ # Add payload wrapper reminder for top-level params
105
+ wrapper_note = " (must be inside payload object)"
106
+
103
107
  if is_empty_param_container:
104
- enhanced_description = f"[OPTIONAL - empty container] {enhanced_description} (default: empty object)"
108
+ enhanced_description = f"[OPTIONAL - empty container] {enhanced_description} (default: empty object){wrapper_note}"
105
109
  elif prop_name in required:
106
110
  if default is not None:
107
- enhanced_description = f"[REQUIRED with default] {enhanced_description} (default: {default})"
111
+ enhanced_description = f"[REQUIRED with default] {enhanced_description} (default: {default}){wrapper_note}"
108
112
  else:
109
- enhanced_description = f"[REQUIRED] {enhanced_description}"
113
+ enhanced_description = f"[REQUIRED] {enhanced_description}{wrapper_note}"
110
114
  else:
111
115
  if default is not None:
112
- enhanced_description = f"[OPTIONAL with default] {enhanced_description} (default: {default})"
116
+ enhanced_description = f"[OPTIONAL with default] {enhanced_description} (default: {default}){wrapper_note}"
113
117
  else:
114
- enhanced_description = f"[OPTIONAL] {enhanced_description} - can be omitted or set to null"
118
+ enhanced_description = f"[OPTIONAL] {enhanced_description} - can be omitted or set to null{wrapper_note}"
115
119
 
116
120
  field_args["description"] = enhanced_description
117
121
 
@@ -169,7 +173,16 @@ def build_model_from_schema(
169
173
  strict=False, # Allow flexibility with types to handle AI agent inputs better
170
174
  extra="allow",
171
175
  title=model_name,
172
- description="IMPORTANT: Required fields must be provided. Optional fields can be omitted entirely or set to null. All parameters with defaults will use those defaults if not provided. Check the 'required' array in the schema to see which fields are mandatory."
176
+ description="""CRITICAL - This schema must be wrapped in a 'payload' parameter.
177
+
178
+ CORRECT: Call function with {"payload": {<this_schema>}}
179
+ INCORRECT: Call function with {<this_schema>} directly
180
+
181
+ All fields shown below must be nested inside a 'payload' object when calling the function.
182
+
183
+ Required fields must be provided. Optional fields can be omitted entirely or set to null.
184
+ All parameters with defaults will use those defaults if not provided.
185
+ Check the 'required' array in the schema to see which fields are mandatory."""
173
186
  )
174
187
  return create_model(
175
188
  model_name,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xpander-sdk
3
- Version: 2.0.206
3
+ Version: 2.0.207
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
@@ -104,6 +104,8 @@ tests/test_api_client.py
104
104
  tests/test_backend_module.py
105
105
  tests/test_boot_shutdown_handlers.py
106
106
  tests/test_configuration.py
107
+ tests/test_final_validation.py
107
108
  tests/test_knowledge_bases_module.py
108
109
  tests/test_tasks_module.py
110
+ tests/test_tool_schema_enhancements.py
109
111
  tests/test_tools_repository.py
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Final validation that Option 2 + 3 enhancements are working correctly.
4
+ """
5
+
6
+ import json
7
+ from xpander_sdk import Configuration
8
+ from xpander_sdk.modules.agents.agents_module import Agents
9
+
10
+ def main():
11
+ config = Configuration(
12
+ api_key="A02tKVpMd58Z3gAIDsQ7C8dh7oIRBYBc8Vu6cGFJ",
13
+ organization_id="6f3a8d1a-00e4-4ae7-bb1f-907b8704d4e2",
14
+ base_url="https://inbound.stg.xpander.ai"
15
+ )
16
+
17
+ print("=" * 80)
18
+ print("TESTING OPTION 2 + 3 ENHANCEMENTS")
19
+ print("=" * 80)
20
+
21
+ agents = Agents(configuration=config)
22
+ agent = agents.get(agent_id="cb0fa205-96a8-4f43-ad99-881fb87f374a")
23
+
24
+ # Access functions to trigger schema enhancements
25
+ functions = agent.tools.functions
26
+ tool = agent.tools.list[0]
27
+
28
+ print("\n✅ OPTION 3: Schema Model Description")
29
+ print("-" * 80)
30
+ model_config_desc = tool.schema.model_config.get('description', '')
31
+ print(model_config_desc)
32
+
33
+ if 'CRITICAL' in model_config_desc and 'payload' in model_config_desc.lower():
34
+ print("\n✓ Schema description contains CRITICAL warning")
35
+ print("✓ Schema description mentions 'payload' wrapper")
36
+
37
+ print("\n✅ OPTION 3: Field Descriptions with 'payload' hints")
38
+ print("-" * 80)
39
+ schema_json = tool.schema.model_json_schema()
40
+ for field_name, field_def in schema_json.get('properties', {}).items():
41
+ desc = field_def.get('description', '')
42
+ has_payload_hint = 'payload' in desc.lower()
43
+ status = "✓" if has_payload_hint else "✗"
44
+ print(f"{status} {field_name}: {desc[:80]}...")
45
+
46
+ print("\n✅ OPTION 2: Function Docstring with Examples")
47
+ print("-" * 80)
48
+ func = functions[0]
49
+ doc = func.__doc__
50
+ print(doc)
51
+
52
+ if 'IMPORTANT' in doc and 'payload' in doc.lower():
53
+ print("\n✓ Function docstring has IMPORTANT section")
54
+ print("✓ Function docstring mentions payload structure")
55
+ print("✓ Function docstring includes examples")
56
+
57
+ print("\n✅ FULL JSON SCHEMA (sent to LLM)")
58
+ print("-" * 80)
59
+ print(json.dumps(schema_json, indent=2))
60
+
61
+ print("\n" + "=" * 80)
62
+ print("✅ ALL ENHANCEMENTS SUCCESSFULLY APPLIED!")
63
+ print("=" * 80)
64
+ print("\nSummary:")
65
+ print("1. ✓ Schema model description has CRITICAL payload wrapper warning")
66
+ print("2. ✓ All field descriptions mention '(must be inside payload object)'")
67
+ print("3. ✓ Function docstring has detailed parameter structure guidance")
68
+ print("4. ✓ Function docstring includes correct/incorrect usage examples")
69
+ print("\nThese enhancements guide the LLM to pass parameters correctly:")
70
+ print(" CORRECT: function_name(payload={...})")
71
+ print(" INCORRECT: function_name(body_params={...}, headers={...})")
72
+
73
+ if __name__ == "__main__":
74
+ main()
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test script to verify that Option 2 + 3 enhancements work correctly.
4
+ This tests that the schema and docstring improvements help guide LLMs to pass parameters correctly.
5
+ """
6
+
7
+ import json
8
+ import sys
9
+ from xpander_sdk import Configuration
10
+ from xpander_sdk.modules.agents.agents_module import Agents
11
+
12
+ def test_schema_enhancements():
13
+ """Test that tool schemas now have enhanced descriptions and examples."""
14
+
15
+ # Setup configuration for staging
16
+ config = Configuration(
17
+ api_key="A02tKVpMd58Z3gAIDsQ7C8dh7oIRBYBc8Vu6cGFJ",
18
+ organization_id="6f3a8d1a-00e4-4ae7-bb1f-907b8704d4e2",
19
+ base_url="https://inbound.stg.xpander.ai"
20
+ )
21
+
22
+ print("🔍 Fetching agent and tools...")
23
+ agents = Agents(configuration=config)
24
+ agent = agents.get(agent_id="cb0fa205-96a8-4f43-ad99-881fb87f374a")
25
+
26
+ print(f"✅ Agent loaded: {agent.name}")
27
+ print(f"📊 Number of tools: {len(agent.tools.list)}\n")
28
+
29
+ # Test each tool's schema and function
30
+ for tool in agent.tools.list:
31
+ print("=" * 80)
32
+ print(f"🔧 Tool: {tool.name} (ID: {tool.id})")
33
+ print("=" * 80)
34
+
35
+ # Check schema documentation
36
+ print("\n📝 Schema Documentation:")
37
+ print("-" * 80)
38
+ if hasattr(tool.schema, '__doc__') and tool.schema.__doc__:
39
+ doc_lines = tool.schema.__doc__.split('\n')
40
+ for line in doc_lines[:20]: # Show first 20 lines
41
+ print(line)
42
+ if len(doc_lines) > 20:
43
+ print(f"... ({len(doc_lines) - 20} more lines)")
44
+ else:
45
+ print("⚠️ No schema documentation found")
46
+
47
+ # Check if critical keywords are present in schema doc
48
+ if tool.schema.__doc__:
49
+ has_payload = 'payload' in tool.schema.__doc__.lower()
50
+ has_example = 'example' in tool.schema.__doc__.lower()
51
+ has_critical = 'critical' in tool.schema.__doc__.lower()
52
+
53
+ print(f"\n✓ Contains 'payload' guidance: {has_payload}")
54
+ print(f"✓ Contains example: {has_example}")
55
+ print(f"✓ Has CRITICAL warning: {has_critical}")
56
+
57
+ # Check field descriptions
58
+ print("\n📋 Field Descriptions:")
59
+ print("-" * 80)
60
+ schema_json = tool.schema.model_json_schema()
61
+ if 'properties' in schema_json:
62
+ for field_name, field_def in schema_json['properties'].items():
63
+ desc = field_def.get('description', 'No description')
64
+ has_wrapper_note = 'payload' in desc.lower()
65
+ status = "✅" if has_wrapper_note else "⚠️ "
66
+ print(f"{status} {field_name}: {desc[:100]}...")
67
+
68
+ # Check function documentation
69
+ print("\n🔨 Function Documentation:")
70
+ print("-" * 80)
71
+ functions = agent.tools.functions
72
+ if functions:
73
+ func = functions[0] # Get first function
74
+ if hasattr(func, '__doc__') and func.__doc__:
75
+ doc_lines = func.__doc__.split('\n')
76
+ for line in doc_lines[:25]: # Show first 25 lines
77
+ print(line)
78
+ if len(doc_lines) > 25:
79
+ print(f"... ({len(doc_lines) - 25} more lines)")
80
+
81
+ # Check function signature
82
+ import inspect
83
+ sig = inspect.signature(func)
84
+ print(f"\n📌 Function Signature: {func.__name__}{sig}")
85
+
86
+ # Check if function has payload parameter
87
+ params = list(sig.parameters.keys())
88
+ if 'payload' in params:
89
+ print("✅ Function has 'payload' parameter")
90
+ else:
91
+ print(f"⚠️ Function parameters: {params}")
92
+
93
+ print("\n")
94
+
95
+ if __name__ == "__main__":
96
+ try:
97
+ test_schema_enhancements()
98
+ print("\n" + "=" * 80)
99
+ print("✅ Test completed successfully!")
100
+ print("=" * 80)
101
+ except Exception as e:
102
+ print(f"\n❌ Error: {e}", file=sys.stderr)
103
+ import traceback
104
+ traceback.print_exc()
105
+ sys.exit(1)
File without changes
File without changes
File without changes