convertTool method
Convert a Tool to Anthropic API format
Implementation
Map<String, dynamic> convertTool(Tool tool) {
try {
// Special handling for web_search tool
// According to https://docs.claude.com/en/docs/agents-and-tools/tool-use/web-search-tool
// web_search is a server-side tool with a different format
if (tool.function.name == 'web_search') {
final webSearchConfig =
config.getExtension<WebSearchConfig>('webSearchConfig');
// Base definition
final toolDef = <String, dynamic>{
'type': webSearchConfig?.mode ?? 'web_search_20250305',
'name': 'web_search',
};
// Add optional parameters if webSearchConfig exists
if (webSearchConfig != null) {
if (webSearchConfig.maxUses != null) {
toolDef['max_uses'] = webSearchConfig.maxUses;
}
if (webSearchConfig.allowedDomains != null &&
webSearchConfig.allowedDomains!.isNotEmpty) {
toolDef['allowed_domains'] = webSearchConfig.allowedDomains;
}
if (webSearchConfig.blockedDomains != null &&
webSearchConfig.blockedDomains!.isNotEmpty) {
toolDef['blocked_domains'] = webSearchConfig.blockedDomains;
}
if (webSearchConfig.location != null) {
toolDef['user_location'] = {
'type': 'approximate',
'city': webSearchConfig.location!.city,
'region': webSearchConfig.location!.region,
'country': webSearchConfig.location!.country,
if (webSearchConfig.location!.timezone != null)
'timezone': webSearchConfig.location!.timezone,
};
}
}
return toolDef;
}
// Regular tool handling
final schema = tool.function.parameters.toJson();
// Anthropic requires input_schema to be a valid JSON Schema object
// According to official docs, it should be type "object"
if (schema['type'] != 'object') {
// Provide helpful error message with suggestion
throw ArgumentError(
'Anthropic tools require input_schema to be of type "object". '
'Tool "${tool.function.name}" has type "${schema['type']}". '
'\n\nTo fix this, update your tool definition:\n'
'ParametersSchema(\n'
' schemaType: "object", // <- Change this to "object"\n'
' properties: {...},\n'
' required: [...],\n'
')\n\n'
'See: https://docs.anthropic.com/en/api/messages#tools');
}
// Ensure required fields are present
final inputSchema = Map<String, dynamic>.from(schema);
// Add properties if missing (empty object is valid)
if (!inputSchema.containsKey('properties')) {
inputSchema['properties'] = <String, dynamic>{};
}
return {
'name': tool.function.name,
'description': tool.function.description.isNotEmpty
? tool.function.description
: 'No description provided',
'input_schema': inputSchema,
};
} catch (e) {
// Re-throw with more context
throw ArgumentError(
'Failed to convert tool "${tool.function.name}" to Anthropic format: $e');
}
}