mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-05-01 23:32:39 +00:00
improving tool usage for crewai enterprise tools
This commit is contained in:
@@ -197,6 +197,42 @@ class CrewStructuredTool:
|
|||||||
validated_args = self.args_schema.model_validate(raw_args)
|
validated_args = self.args_schema.model_validate(raw_args)
|
||||||
return validated_args.model_dump()
|
return validated_args.model_dump()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
# Check if this is a "Field required" error and try to fix it
|
||||||
|
error_str = str(e)
|
||||||
|
if "Field required" in error_str:
|
||||||
|
# Try to parse missing fields from the error
|
||||||
|
import re
|
||||||
|
from pydantic import ValidationError
|
||||||
|
|
||||||
|
if isinstance(e, ValidationError):
|
||||||
|
# Extract missing fields from validation error
|
||||||
|
missing_fields = []
|
||||||
|
for error_detail in e.errors():
|
||||||
|
if error_detail.get('type') == 'missing':
|
||||||
|
field_path = error_detail.get('loc', ())
|
||||||
|
if field_path:
|
||||||
|
missing_fields.append(field_path[0])
|
||||||
|
|
||||||
|
if missing_fields:
|
||||||
|
# Create a copy of raw_args and add missing fields with None
|
||||||
|
fixed_args = dict(raw_args) if isinstance(raw_args, dict) else {}
|
||||||
|
for field in missing_fields:
|
||||||
|
if field not in fixed_args:
|
||||||
|
fixed_args[field] = None
|
||||||
|
|
||||||
|
# Try validation again with fixed args
|
||||||
|
try:
|
||||||
|
self._logger.log("debug", f"Auto-fixing missing fields: {missing_fields}")
|
||||||
|
validated_args = self.args_schema.model_validate(fixed_args)
|
||||||
|
return validated_args.model_dump()
|
||||||
|
except Exception as retry_e:
|
||||||
|
# If it still fails, raise the original error with additional context
|
||||||
|
raise ValueError(
|
||||||
|
f"Arguments validation failed: {e}\n"
|
||||||
|
f"Attempted to auto-fix missing fields {missing_fields} but still failed: {retry_e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# For other validation errors, raise as before
|
||||||
raise ValueError(f"Arguments validation failed: {e}")
|
raise ValueError(f"Arguments validation failed: {e}")
|
||||||
|
|
||||||
async def ainvoke(
|
async def ainvoke(
|
||||||
|
|||||||
@@ -250,9 +250,54 @@ class ToolUsage:
|
|||||||
self._run_attempts += 1
|
self._run_attempts += 1
|
||||||
if self._run_attempts > self._max_parsing_attempts:
|
if self._run_attempts > self._max_parsing_attempts:
|
||||||
self._telemetry.tool_usage_error(llm=self.function_calling_llm)
|
self._telemetry.tool_usage_error(llm=self.function_calling_llm)
|
||||||
|
|
||||||
|
# Check if this is a validation error with missing fields
|
||||||
|
error_str = str(e)
|
||||||
|
if "Arguments validation failed" in error_str and "Field required" in error_str:
|
||||||
|
# Extract the field name that's missing
|
||||||
|
import re
|
||||||
|
field_match = re.search(r'(\w+)\s*Field required', error_str)
|
||||||
|
if field_match:
|
||||||
|
missing_field = field_match.group(1)
|
||||||
|
|
||||||
|
# Create a more helpful error message
|
||||||
|
error_message = (
|
||||||
|
f"Tool validation error: The '{missing_field}' parameter is required but was not provided.\n\n"
|
||||||
|
f"SOLUTION: Include ALL parameters in your tool call, even optional ones (use null for optional parameters):\n"
|
||||||
|
f'{{"tool_name": "{tool.name}", "arguments": {{'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get all expected parameters from the tool schema
|
||||||
|
if hasattr(tool, 'args_schema'):
|
||||||
|
schema_props = tool.args_schema.model_json_schema().get('properties', {})
|
||||||
|
param_examples = []
|
||||||
|
for param_name, param_info in schema_props.items():
|
||||||
|
if param_name == missing_field:
|
||||||
|
param_examples.append(f'"{param_name}": "YOUR_VALUE_HERE"')
|
||||||
|
else:
|
||||||
|
# Check if it's optional by looking at required fields
|
||||||
|
is_required = param_name in tool.args_schema.model_json_schema().get('required', [])
|
||||||
|
if not is_required:
|
||||||
|
param_examples.append(f'"{param_name}": null')
|
||||||
|
else:
|
||||||
|
param_examples.append(f'"{param_name}": "value"')
|
||||||
|
|
||||||
|
error_message += ', '.join(param_examples)
|
||||||
|
error_message += '}}\n\n'
|
||||||
|
|
||||||
|
error_message += f"Original error: {e}\n"
|
||||||
|
error_message += f"Tool description: {tool.description}"
|
||||||
|
else:
|
||||||
|
# Use the original error message
|
||||||
error_message = self._i18n.errors("tool_usage_exception").format(
|
error_message = self._i18n.errors("tool_usage_exception").format(
|
||||||
error=e, tool=tool.name, tool_inputs=tool.description
|
error=e, tool=tool.name, tool_inputs=tool.description
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
# Use the original error message for non-validation errors
|
||||||
|
error_message = self._i18n.errors("tool_usage_exception").format(
|
||||||
|
error=e, tool=tool.name, tool_inputs=tool.description
|
||||||
|
)
|
||||||
|
|
||||||
error = ToolUsageErrorException(
|
error = ToolUsageErrorException(
|
||||||
f"\n{error_message}.\nMoving on then. {self._i18n.slice('format').format(tool_names=self.tools_names)}"
|
f"\n{error_message}.\nMoving on then. {self._i18n.slice('format').format(tool_names=self.tools_names)}"
|
||||||
).message
|
).message
|
||||||
|
|||||||
Reference in New Issue
Block a user