autobyteus 1.1.6__py3-none-any.whl → 1.1.8__py3-none-any.whl
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.
- autobyteus/agent/context/agent_runtime_state.py +7 -1
- autobyteus/agent/handlers/tool_result_event_handler.py +121 -89
- autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +7 -1
- autobyteus/agent/tool_invocation.py +25 -1
- autobyteus/agent_team/agent_team_builder.py +22 -1
- autobyteus/agent_team/context/agent_team_runtime_state.py +0 -2
- autobyteus/llm/llm_factory.py +25 -57
- autobyteus/llm/ollama_provider_resolver.py +1 -0
- autobyteus/llm/providers.py +1 -0
- autobyteus/llm/token_counter/token_counter_factory.py +2 -0
- autobyteus/multimedia/audio/audio_model.py +2 -1
- autobyteus/multimedia/image/image_model.py +2 -1
- autobyteus/task_management/tools/publish_task_plan.py +4 -16
- autobyteus/task_management/tools/update_task_status.py +4 -19
- autobyteus/tools/__init__.py +2 -4
- autobyteus/tools/base_tool.py +98 -29
- autobyteus/tools/browser/standalone/__init__.py +0 -1
- autobyteus/tools/google_search.py +149 -0
- autobyteus/tools/mcp/schema_mapper.py +29 -71
- autobyteus/tools/multimedia/audio_tools.py +3 -3
- autobyteus/tools/multimedia/image_tools.py +5 -5
- autobyteus/tools/parameter_schema.py +82 -89
- autobyteus/tools/pydantic_schema_converter.py +81 -0
- autobyteus/tools/usage/formatters/default_json_example_formatter.py +89 -20
- autobyteus/tools/usage/formatters/default_xml_example_formatter.py +115 -41
- autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +50 -20
- autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +55 -22
- autobyteus/tools/usage/formatters/google_json_example_formatter.py +54 -21
- autobyteus/tools/usage/formatters/openai_json_example_formatter.py +53 -23
- autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +270 -94
- autobyteus/tools/usage/providers/tool_manifest_provider.py +39 -14
- autobyteus-1.1.8.dist-info/METADATA +204 -0
- {autobyteus-1.1.6.dist-info → autobyteus-1.1.8.dist-info}/RECORD +39 -40
- examples/run_google_slides_agent.py +2 -2
- examples/run_mcp_google_slides_client.py +1 -1
- examples/run_sqlite_agent.py +1 -1
- autobyteus/tools/ask_user_input.py +0 -40
- autobyteus/tools/browser/standalone/factory/google_search_factory.py +0 -25
- autobyteus/tools/browser/standalone/google_search_ui.py +0 -126
- autobyteus-1.1.6.dist-info/METADATA +0 -161
- {autobyteus-1.1.6.dist-info → autobyteus-1.1.8.dist-info}/WHEEL +0 -0
- {autobyteus-1.1.6.dist-info → autobyteus-1.1.8.dist-info}/licenses/LICENSE +0 -0
- {autobyteus-1.1.6.dist-info → autobyteus-1.1.8.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# file: autobyteus/autobyteus/tools/usage/formatters/default_json_example_formatter.py
|
|
2
|
-
|
|
2
|
+
import json
|
|
3
|
+
from typing import Dict, Any, TYPE_CHECKING, List, Optional, Union
|
|
3
4
|
|
|
4
|
-
from autobyteus.tools.parameter_schema import ParameterType, ParameterDefinition
|
|
5
|
+
from autobyteus.tools.parameter_schema import ParameterType, ParameterDefinition, ParameterSchema
|
|
5
6
|
from .base_formatter import BaseExampleFormatter
|
|
6
7
|
|
|
7
8
|
if TYPE_CHECKING:
|
|
@@ -10,20 +11,47 @@ if TYPE_CHECKING:
|
|
|
10
11
|
class DefaultJsonExampleFormatter(BaseExampleFormatter):
|
|
11
12
|
"""
|
|
12
13
|
Formats a tool usage example into a generic JSON format.
|
|
13
|
-
It intelligently generates detailed examples for complex object schemas
|
|
14
|
+
It intelligently generates detailed examples for complex object schemas, providing
|
|
15
|
+
both a basic (required parameters only) and an advanced (all parameters) example
|
|
16
|
+
if optional parameters are available.
|
|
14
17
|
"""
|
|
15
18
|
|
|
16
|
-
def provide(self, tool_definition: 'ToolDefinition') ->
|
|
19
|
+
def provide(self, tool_definition: 'ToolDefinition') -> str:
|
|
20
|
+
"""
|
|
21
|
+
Generates a formatted string containing basic and optionally an advanced usage example for the tool.
|
|
22
|
+
"""
|
|
23
|
+
basic_example_dict = self._create_example_structure(tool_definition, mode='basic')
|
|
24
|
+
basic_example_str = "### Example 1: Basic Call (Required Arguments)\n"
|
|
25
|
+
basic_example_str += "```json\n"
|
|
26
|
+
basic_example_str += json.dumps(basic_example_dict, indent=2)
|
|
27
|
+
basic_example_str += "\n```"
|
|
28
|
+
|
|
29
|
+
if not self._schema_has_advanced_params(tool_definition.argument_schema):
|
|
30
|
+
return basic_example_str
|
|
31
|
+
|
|
32
|
+
advanced_example_dict = self._create_example_structure(tool_definition, mode='advanced')
|
|
33
|
+
advanced_example_str = "### Example 2: Advanced Call (With Optional Arguments)\n"
|
|
34
|
+
advanced_example_str += "```json\n"
|
|
35
|
+
advanced_example_str += json.dumps(advanced_example_dict, indent=2)
|
|
36
|
+
advanced_example_str += "\n```"
|
|
37
|
+
|
|
38
|
+
return f"{basic_example_str}\n\n{advanced_example_str}"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _create_example_structure(self, tool_definition: 'ToolDefinition', mode: str) -> Dict:
|
|
42
|
+
"""Helper to create the full tool call example structure for a given mode."""
|
|
17
43
|
tool_name = tool_definition.name
|
|
18
44
|
arg_schema = tool_definition.argument_schema
|
|
19
45
|
arguments = {}
|
|
20
46
|
|
|
21
47
|
if arg_schema and arg_schema.parameters:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
#
|
|
25
|
-
|
|
26
|
-
|
|
48
|
+
params_to_render = arg_schema.parameters
|
|
49
|
+
if mode == 'basic':
|
|
50
|
+
# In basic mode, we only render required parameters.
|
|
51
|
+
params_to_render = [p for p in arg_schema.parameters if p.required]
|
|
52
|
+
|
|
53
|
+
for param_def in params_to_render:
|
|
54
|
+
arguments[param_def.name] = self._generate_placeholder_value(param_def, mode=mode)
|
|
27
55
|
|
|
28
56
|
return {
|
|
29
57
|
"tool": {
|
|
@@ -32,12 +60,34 @@ class DefaultJsonExampleFormatter(BaseExampleFormatter):
|
|
|
32
60
|
},
|
|
33
61
|
}
|
|
34
62
|
|
|
35
|
-
def
|
|
63
|
+
def _schema_has_advanced_params(self, schema: Optional[ParameterSchema]) -> bool:
|
|
64
|
+
"""Recursively checks if a schema or any of its sub-schemas have non-required parameters."""
|
|
65
|
+
if not schema:
|
|
66
|
+
return False
|
|
67
|
+
for param in schema.parameters:
|
|
68
|
+
if not param.required:
|
|
69
|
+
return True # Found an optional param at this level
|
|
70
|
+
if param.object_schema and self._schema_has_advanced_params(param.object_schema):
|
|
71
|
+
return True # Found an optional param in a nested object
|
|
72
|
+
if isinstance(param.array_item_schema, ParameterSchema) and self._schema_has_advanced_params(param.array_item_schema):
|
|
73
|
+
return True # Found an optional param in an array of objects
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
def _generate_placeholder_value(self, param_def: ParameterDefinition, mode: str = 'basic') -> Any:
|
|
77
|
+
"""
|
|
78
|
+
Generates a placeholder value for a parameter, recursing for complex types.
|
|
79
|
+
The mode determines whether to include optional fields in nested structures.
|
|
80
|
+
"""
|
|
36
81
|
# If an object parameter has a detailed schema, generate a structured example from it.
|
|
37
82
|
if param_def.param_type == ParameterType.OBJECT and param_def.object_schema:
|
|
38
|
-
|
|
39
|
-
return DefaultJsonExampleFormatter._generate_example_from_schema(param_def.object_schema, param_def.object_schema)
|
|
83
|
+
return DefaultJsonExampleFormatter._generate_example_from_schema(param_def.object_schema, param_def.object_schema, mode=mode)
|
|
40
84
|
|
|
85
|
+
# Handle arrays with a detailed item schema.
|
|
86
|
+
if param_def.param_type == ParameterType.ARRAY and param_def.array_item_schema:
|
|
87
|
+
# Generate one example item for the array to keep it concise.
|
|
88
|
+
example_item = DefaultJsonExampleFormatter._generate_example_from_schema(param_def.array_item_schema, param_def.array_item_schema, mode=mode)
|
|
89
|
+
return [example_item]
|
|
90
|
+
|
|
41
91
|
# Fallback to simple placeholder generation for primitives or objects without schemas.
|
|
42
92
|
if param_def.default_value is not None: return param_def.default_value
|
|
43
93
|
if param_def.param_type == ParameterType.STRING: return f"example_{param_def.name}"
|
|
@@ -46,15 +96,34 @@ class DefaultJsonExampleFormatter(BaseExampleFormatter):
|
|
|
46
96
|
if param_def.param_type == ParameterType.BOOLEAN: return True
|
|
47
97
|
if param_def.param_type == ParameterType.ENUM: return param_def.enum_values[0] if param_def.enum_values else "enum_val"
|
|
48
98
|
if param_def.param_type == ParameterType.OBJECT: return {"key": "value"}
|
|
49
|
-
if param_def.param_type == ParameterType.ARRAY: return ["item1", "item2"]
|
|
99
|
+
if param_def.param_type == ParameterType.ARRAY: return ["item1", "item2"] # This now only applies to generic arrays
|
|
50
100
|
return "placeholder"
|
|
51
101
|
|
|
52
102
|
@staticmethod
|
|
53
|
-
def _generate_example_from_schema(
|
|
103
|
+
def _generate_example_from_schema(
|
|
104
|
+
sub_schema: Union[Dict[str, Any], 'ParameterSchema', 'ParameterType'],
|
|
105
|
+
full_schema: Union[Dict[str, Any], 'ParameterSchema', 'ParameterType'],
|
|
106
|
+
mode: str = 'basic'
|
|
107
|
+
) -> Any:
|
|
54
108
|
"""
|
|
55
109
|
Recursively generates an example value from a JSON schema dictionary.
|
|
56
110
|
This is a static method so it can be reused by other formatters.
|
|
111
|
+
The 'mode' parameter controls whether optional fields are included in nested objects.
|
|
112
|
+
The default mode is 'basic' to maintain backward compatibility.
|
|
57
113
|
"""
|
|
114
|
+
# FIX: Handle primitive ParameterType for array items directly.
|
|
115
|
+
if isinstance(sub_schema, ParameterType):
|
|
116
|
+
if sub_schema == ParameterType.STRING: return "example_string"
|
|
117
|
+
if sub_schema == ParameterType.INTEGER: return 1
|
|
118
|
+
if sub_schema == ParameterType.FLOAT: return 1.1
|
|
119
|
+
if sub_schema == ParameterType.BOOLEAN: return True
|
|
120
|
+
return "unknown_primitive"
|
|
121
|
+
|
|
122
|
+
if isinstance(sub_schema, ParameterSchema):
|
|
123
|
+
sub_schema = sub_schema.to_json_schema_dict()
|
|
124
|
+
if isinstance(full_schema, ParameterSchema):
|
|
125
|
+
full_schema = full_schema.to_json_schema_dict()
|
|
126
|
+
|
|
58
127
|
if "$ref" in sub_schema:
|
|
59
128
|
ref_path = sub_schema["$ref"]
|
|
60
129
|
try:
|
|
@@ -63,7 +132,7 @@ class DefaultJsonExampleFormatter(BaseExampleFormatter):
|
|
|
63
132
|
resolved_schema = full_schema
|
|
64
133
|
for part in parts:
|
|
65
134
|
resolved_schema = resolved_schema[part]
|
|
66
|
-
return DefaultJsonExampleFormatter._generate_example_from_schema(resolved_schema, full_schema)
|
|
135
|
+
return DefaultJsonExampleFormatter._generate_example_from_schema(resolved_schema, full_schema, mode=mode)
|
|
67
136
|
except (KeyError, IndexError):
|
|
68
137
|
return {"error": f"Could not resolve schema reference: {ref_path}"}
|
|
69
138
|
|
|
@@ -80,16 +149,16 @@ class DefaultJsonExampleFormatter(BaseExampleFormatter):
|
|
|
80
149
|
properties = sub_schema.get("properties", {})
|
|
81
150
|
required_fields = sub_schema.get("required", [])
|
|
82
151
|
for prop_name, prop_schema in properties.items():
|
|
83
|
-
# Include
|
|
84
|
-
if prop_name in required_fields:
|
|
85
|
-
example_obj[prop_name] = DefaultJsonExampleFormatter._generate_example_from_schema(prop_schema, full_schema)
|
|
152
|
+
# Include fields if in 'advanced' mode or if they are required.
|
|
153
|
+
if mode == 'advanced' or prop_name in required_fields:
|
|
154
|
+
example_obj[prop_name] = DefaultJsonExampleFormatter._generate_example_from_schema(prop_schema, full_schema, mode=mode)
|
|
86
155
|
return example_obj
|
|
87
156
|
|
|
88
157
|
elif schema_type == "array":
|
|
89
158
|
items_schema = sub_schema.get("items")
|
|
90
159
|
if isinstance(items_schema, dict):
|
|
91
|
-
# Generate one example item for the array to keep it concise
|
|
92
|
-
return [DefaultJsonExampleFormatter._generate_example_from_schema(items_schema, full_schema)]
|
|
160
|
+
# Generate one example item for the array to keep it concise.
|
|
161
|
+
return [DefaultJsonExampleFormatter._generate_example_from_schema(items_schema, full_schema, mode=mode)]
|
|
93
162
|
else:
|
|
94
163
|
return ["example_item_1"]
|
|
95
164
|
|
|
@@ -1,65 +1,103 @@
|
|
|
1
1
|
# file: autobyteus/autobyteus/tools/usage/formatters/default_xml_example_formatter.py
|
|
2
2
|
import xml.sax.saxutils
|
|
3
|
-
import
|
|
4
|
-
from typing import Any, TYPE_CHECKING
|
|
3
|
+
import re
|
|
4
|
+
from typing import Any, TYPE_CHECKING, List, Optional
|
|
5
5
|
|
|
6
|
-
from autobyteus.tools.parameter_schema import ParameterType, ParameterDefinition
|
|
6
|
+
from autobyteus.tools.parameter_schema import ParameterType, ParameterDefinition, ParameterSchema
|
|
7
7
|
from .base_formatter import BaseExampleFormatter
|
|
8
|
-
from .default_json_example_formatter import DefaultJsonExampleFormatter # Import for reuse
|
|
9
8
|
|
|
10
9
|
if TYPE_CHECKING:
|
|
11
10
|
from autobyteus.tools.registry import ToolDefinition
|
|
12
11
|
|
|
13
12
|
class DefaultXmlExampleFormatter(BaseExampleFormatter):
|
|
14
|
-
"""Formats a tool usage example into a standardized XML <tool> string."""
|
|
13
|
+
"""Formats a tool usage example into a standardized, nested XML <tool> string."""
|
|
15
14
|
|
|
16
15
|
def provide(self, tool_definition: 'ToolDefinition') -> str:
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
"""
|
|
17
|
+
Generates a multi-shot example string for the given tool, including
|
|
18
|
+
a basic and an advanced usage case.
|
|
19
|
+
"""
|
|
20
|
+
basic_example = self._generate_basic_example(tool_definition)
|
|
21
|
+
advanced_example = self._generate_advanced_example(tool_definition)
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
examples = [basic_example]
|
|
24
|
+
if advanced_example:
|
|
25
|
+
examples.append(advanced_example)
|
|
26
|
+
|
|
27
|
+
return "\n\n".join(examples)
|
|
22
28
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
29
|
+
def _schema_has_advanced_params(self, schema: Optional[ParameterSchema]) -> bool:
|
|
30
|
+
"""Recursively checks if a schema or any of its sub-schemas have non-required parameters."""
|
|
31
|
+
if not schema:
|
|
32
|
+
return False
|
|
33
|
+
for param in schema.parameters:
|
|
34
|
+
if not param.required:
|
|
35
|
+
return True # Found an optional param at this level
|
|
36
|
+
if param.object_schema and self._schema_has_advanced_params(param.object_schema):
|
|
37
|
+
return True # Found an optional param in a nested object
|
|
38
|
+
if isinstance(param.array_item_schema, ParameterSchema) and self._schema_has_advanced_params(param.array_item_schema):
|
|
39
|
+
return True # Found an optional param in an array of objects
|
|
40
|
+
return False
|
|
41
|
+
|
|
42
|
+
def _generate_basic_example(self, tool_def: 'ToolDefinition') -> str:
|
|
43
|
+
"""Generates an XML example including only the required parameters."""
|
|
44
|
+
tool_name = tool_def.name
|
|
45
|
+
arg_schema = tool_def.argument_schema
|
|
46
|
+
|
|
47
|
+
example_xml_parts = [
|
|
48
|
+
"### Example 1: Basic Call (Required Arguments)",
|
|
49
|
+
f'<tool name="{tool_name}">'
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
if arg_schema and any(p.required for p in arg_schema.parameters):
|
|
44
53
|
example_xml_parts.append(" <arguments>")
|
|
54
|
+
arguments_part = self._generate_arguments_xml(arg_schema.parameters, 2, mode='basic')
|
|
45
55
|
example_xml_parts.extend(arguments_part)
|
|
46
56
|
example_xml_parts.append(" </arguments>")
|
|
47
57
|
else:
|
|
48
|
-
example_xml_parts.append(" <!-- This tool
|
|
58
|
+
example_xml_parts.append(" <!-- This tool has no required arguments. -->")
|
|
49
59
|
|
|
50
60
|
example_xml_parts.append("</tool>")
|
|
51
61
|
return "\n".join(example_xml_parts)
|
|
52
62
|
|
|
53
|
-
def
|
|
54
|
-
|
|
55
|
-
if
|
|
56
|
-
|
|
63
|
+
def _generate_advanced_example(self, tool_def: 'ToolDefinition') -> Optional[str]:
|
|
64
|
+
"""
|
|
65
|
+
Generates a more complex example if the schema has any optional parameters
|
|
66
|
+
at any level of nesting.
|
|
67
|
+
"""
|
|
68
|
+
arg_schema = tool_def.argument_schema
|
|
69
|
+
if not self._schema_has_advanced_params(arg_schema):
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
tool_name = tool_def.name
|
|
73
|
+
example_xml_parts = [
|
|
74
|
+
"### Example 2: Advanced Call (With Optional & Nested Arguments)",
|
|
75
|
+
f'<tool name="{tool_name}">'
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
if arg_schema and arg_schema.parameters:
|
|
79
|
+
example_xml_parts.append(" <arguments>")
|
|
80
|
+
arguments_part = self._generate_arguments_xml(arg_schema.parameters, 2, mode='advanced')
|
|
81
|
+
example_xml_parts.extend(arguments_part)
|
|
82
|
+
example_xml_parts.append(" </arguments>")
|
|
83
|
+
else:
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
example_xml_parts.append("</tool>")
|
|
87
|
+
return "\n".join(example_xml_parts)
|
|
57
88
|
|
|
58
|
-
|
|
89
|
+
def _generate_placeholder_value(self, param_def: ParameterDefinition) -> Any:
|
|
90
|
+
"""Generates a descriptive placeholder value."""
|
|
59
91
|
if param_def.default_value is not None:
|
|
60
92
|
return param_def.default_value
|
|
93
|
+
|
|
94
|
+
if param_def.description:
|
|
95
|
+
match = re.search(r"e\.g\.,?\s*[`']([^`']+)[`']", param_def.description)
|
|
96
|
+
if match:
|
|
97
|
+
return match.group(1)
|
|
98
|
+
|
|
61
99
|
if param_def.param_type == ParameterType.STRING:
|
|
62
|
-
return f"
|
|
100
|
+
return f"A valid string for '{param_def.name}'"
|
|
63
101
|
if param_def.param_type == ParameterType.INTEGER:
|
|
64
102
|
return 123
|
|
65
103
|
if param_def.param_type == ParameterType.FLOAT:
|
|
@@ -68,8 +106,44 @@ class DefaultXmlExampleFormatter(BaseExampleFormatter):
|
|
|
68
106
|
return True
|
|
69
107
|
if param_def.param_type == ParameterType.ENUM:
|
|
70
108
|
return param_def.enum_values[0] if param_def.enum_values else "enum_val"
|
|
71
|
-
if param_def.param_type == ParameterType.OBJECT:
|
|
72
|
-
return {"key": "value"} # Fallback if no schema
|
|
73
|
-
if param_def.param_type == ParameterType.ARRAY:
|
|
74
|
-
return ["item1", "item2"]
|
|
75
109
|
return "placeholder"
|
|
110
|
+
|
|
111
|
+
def _generate_arguments_xml(self, params: List[ParameterDefinition], indent_level: int, mode: str) -> List[str]:
|
|
112
|
+
"""Recursively generates XML for a list of parameter definitions based on the mode."""
|
|
113
|
+
xml_lines = []
|
|
114
|
+
indent = " " * indent_level
|
|
115
|
+
|
|
116
|
+
params_to_render = params
|
|
117
|
+
if mode == 'basic':
|
|
118
|
+
params_to_render = [p for p in params if p.required]
|
|
119
|
+
|
|
120
|
+
for param_def in params_to_render:
|
|
121
|
+
param_name = param_def.name
|
|
122
|
+
|
|
123
|
+
if param_def.param_type == ParameterType.OBJECT and param_def.object_schema:
|
|
124
|
+
xml_lines.append(f'{indent}<arg name="{param_name}">')
|
|
125
|
+
xml_lines.extend(self._generate_arguments_xml(param_def.object_schema.parameters, indent_level + 1, mode=mode))
|
|
126
|
+
xml_lines.append(f'{indent}</arg>')
|
|
127
|
+
|
|
128
|
+
elif param_def.param_type == ParameterType.ARRAY:
|
|
129
|
+
xml_lines.append(f'{indent}<arg name="{param_name}">')
|
|
130
|
+
|
|
131
|
+
if isinstance(param_def.array_item_schema, ParameterSchema): # Array of objects
|
|
132
|
+
xml_lines.append(f'{indent} <item>')
|
|
133
|
+
xml_lines.extend(self._generate_arguments_xml(param_def.array_item_schema.parameters, indent_level + 2, mode=mode))
|
|
134
|
+
xml_lines.append(f'{indent} </item>')
|
|
135
|
+
xml_lines.append(f'{indent} <!-- (more items as needed) -->')
|
|
136
|
+
else: # Array of primitives
|
|
137
|
+
placeholder_1 = self._generate_placeholder_value(ParameterDefinition(name=f"{param_name}_item_1", param_type=ParameterType.STRING, description="An item from the list."))
|
|
138
|
+
placeholder_2 = self._generate_placeholder_value(ParameterDefinition(name=f"{param_name}_item_2", param_type=ParameterType.STRING, description="An item from the list."))
|
|
139
|
+
xml_lines.append(f'{indent} <item>{xml.sax.saxutils.escape(str(placeholder_1))}</item>')
|
|
140
|
+
xml_lines.append(f'{indent} <item>{xml.sax.saxutils.escape(str(placeholder_2))}</item>')
|
|
141
|
+
|
|
142
|
+
xml_lines.append(f'{indent}</arg>')
|
|
143
|
+
|
|
144
|
+
else: # Primitive types
|
|
145
|
+
placeholder_value = self._generate_placeholder_value(param_def)
|
|
146
|
+
escaped_value = xml.sax.saxutils.escape(str(placeholder_value))
|
|
147
|
+
xml_lines.append(f'{indent}<arg name="{param_name}">{escaped_value}</arg>')
|
|
148
|
+
|
|
149
|
+
return xml_lines
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# file: autobyteus/autobyteus/tools/usage/formatters/default_xml_schema_formatter.py
|
|
2
2
|
import xml.sax.saxutils
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING, List
|
|
4
4
|
|
|
5
|
-
from autobyteus.tools.parameter_schema import ParameterType
|
|
5
|
+
from autobyteus.tools.parameter_schema import ParameterType, ParameterDefinition, ParameterSchema
|
|
6
6
|
from .base_formatter import BaseSchemaFormatter
|
|
7
7
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
9
|
from autobyteus.tools.registry import ToolDefinition
|
|
10
10
|
|
|
11
11
|
class DefaultXmlSchemaFormatter(BaseSchemaFormatter):
|
|
12
|
-
"""Formats a tool's schema into a standardized XML string."""
|
|
12
|
+
"""Formats a tool's schema into a standardized, potentially nested, XML string."""
|
|
13
13
|
|
|
14
14
|
def provide(self, tool_definition: 'ToolDefinition') -> str:
|
|
15
|
-
arg_schema = tool_definition.argument_schema
|
|
16
15
|
tool_name = tool_definition.name
|
|
17
16
|
description = tool_definition.description
|
|
17
|
+
arg_schema = tool_definition.argument_schema
|
|
18
18
|
|
|
19
19
|
escaped_description = xml.sax.saxutils.escape(description) if description else ""
|
|
20
20
|
tool_tag = f'<tool name="{tool_name}" description="{escaped_description}">'
|
|
@@ -22,25 +22,55 @@ class DefaultXmlSchemaFormatter(BaseSchemaFormatter):
|
|
|
22
22
|
|
|
23
23
|
if arg_schema and arg_schema.parameters:
|
|
24
24
|
xml_parts.append(" <arguments>")
|
|
25
|
-
|
|
26
|
-
arg_tag = f' <arg name="{param.name}"'
|
|
27
|
-
arg_tag += f' type="{param.param_type.value}"'
|
|
28
|
-
if param.description:
|
|
29
|
-
escaped_param_desc = xml.sax.saxutils.escape(param.description)
|
|
30
|
-
arg_tag += f' description="{escaped_param_desc}"'
|
|
31
|
-
arg_tag += f" required=\"{'true' if param.required else 'false'}\""
|
|
32
|
-
|
|
33
|
-
if param.default_value is not None:
|
|
34
|
-
arg_tag += f' default="{xml.sax.saxutils.escape(str(param.default_value))}"'
|
|
35
|
-
if param.param_type == ParameterType.ENUM and param.enum_values:
|
|
36
|
-
escaped_enum_values = [xml.sax.saxutils.escape(ev) for ev in param.enum_values]
|
|
37
|
-
arg_tag += f' enum_values="{",".join(escaped_enum_values)}"'
|
|
38
|
-
|
|
39
|
-
arg_tag += " />"
|
|
40
|
-
xml_parts.append(arg_tag)
|
|
25
|
+
xml_parts.extend(self._format_params_recursively(arg_schema.parameters, 2))
|
|
41
26
|
xml_parts.append(" </arguments>")
|
|
42
27
|
else:
|
|
43
28
|
xml_parts.append(" <!-- This tool takes no arguments -->")
|
|
44
29
|
|
|
45
30
|
xml_parts.append("</tool>")
|
|
46
31
|
return "\n".join(xml_parts)
|
|
32
|
+
|
|
33
|
+
def _format_params_recursively(self, params: List[ParameterDefinition], indent_level: int) -> List[str]:
|
|
34
|
+
"""Recursively formats parameter definitions into XML strings."""
|
|
35
|
+
xml_lines = []
|
|
36
|
+
indent = " " * indent_level
|
|
37
|
+
|
|
38
|
+
for param in params:
|
|
39
|
+
attrs = [
|
|
40
|
+
f'name="{param.name}"',
|
|
41
|
+
f'type="{param.param_type.value}"'
|
|
42
|
+
]
|
|
43
|
+
if param.description:
|
|
44
|
+
attrs.append(f'description="{xml.sax.saxutils.escape(param.description)}"')
|
|
45
|
+
|
|
46
|
+
attrs.append(f"required=\"{'true' if param.required else 'false'}\"")
|
|
47
|
+
|
|
48
|
+
if param.default_value is not None:
|
|
49
|
+
attrs.append(f'default="{xml.sax.saxutils.escape(str(param.default_value))}"')
|
|
50
|
+
if param.param_type == ParameterType.ENUM and param.enum_values:
|
|
51
|
+
escaped_enum = [xml.sax.saxutils.escape(ev) for ev in param.enum_values]
|
|
52
|
+
attrs.append(f'enum_values="{",".join(escaped_enum)}"')
|
|
53
|
+
|
|
54
|
+
is_object = param.param_type == ParameterType.OBJECT and param.object_schema
|
|
55
|
+
is_array = param.param_type == ParameterType.ARRAY and param.array_item_schema
|
|
56
|
+
|
|
57
|
+
if is_object:
|
|
58
|
+
xml_lines.append(f'{indent}<arg {" ".join(attrs)}>')
|
|
59
|
+
xml_lines.extend(self._format_params_recursively(param.object_schema.parameters, indent_level + 1))
|
|
60
|
+
xml_lines.append(f'{indent}</arg>')
|
|
61
|
+
elif is_array:
|
|
62
|
+
xml_lines.append(f'{indent}<arg {" ".join(attrs)}>')
|
|
63
|
+
if isinstance(param.array_item_schema, ParameterSchema):
|
|
64
|
+
# Array of objects
|
|
65
|
+
xml_lines.append(f'{indent} <items type="object">')
|
|
66
|
+
xml_lines.extend(self._format_params_recursively(param.array_item_schema.parameters, indent_level + 2))
|
|
67
|
+
xml_lines.append(f'{indent} </items>')
|
|
68
|
+
elif isinstance(param.array_item_schema, ParameterType):
|
|
69
|
+
# Array of primitives
|
|
70
|
+
xml_lines.append(f'{indent} <items type="{param.array_item_schema.value}" />')
|
|
71
|
+
xml_lines.append(f'{indent}</arg>')
|
|
72
|
+
else:
|
|
73
|
+
# This is a simple/primitive type or a generic array
|
|
74
|
+
xml_lines.append(f'{indent}<arg {" ".join(attrs)} />')
|
|
75
|
+
|
|
76
|
+
return xml_lines
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# file: autobyteus/autobyteus/tools/usage/formatters/gemini_json_example_formatter.py
|
|
2
|
-
|
|
2
|
+
import json
|
|
3
|
+
from typing import Dict, Any, TYPE_CHECKING, Optional
|
|
3
4
|
|
|
4
|
-
from autobyteus.tools.parameter_schema import
|
|
5
|
+
from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition
|
|
5
6
|
from .base_formatter import BaseExampleFormatter
|
|
6
7
|
from .default_json_example_formatter import DefaultJsonExampleFormatter # Import for reuse
|
|
7
8
|
|
|
@@ -9,32 +10,64 @@ if TYPE_CHECKING:
|
|
|
9
10
|
from autobyteus.tools.registry import ToolDefinition
|
|
10
11
|
|
|
11
12
|
class GeminiJsonExampleFormatter(BaseExampleFormatter):
|
|
12
|
-
"""
|
|
13
|
+
"""
|
|
14
|
+
Formats a tool usage example into the Google Gemini tool_calls format.
|
|
15
|
+
Provides both basic (required only) and advanced (all) examples if optional
|
|
16
|
+
parameters exist for the tool.
|
|
17
|
+
"""
|
|
13
18
|
|
|
14
|
-
def provide(self, tool_definition: 'ToolDefinition') ->
|
|
19
|
+
def provide(self, tool_definition: 'ToolDefinition') -> str:
|
|
20
|
+
"""
|
|
21
|
+
Generates a formatted string containing basic and optionally an advanced usage example for the tool.
|
|
22
|
+
"""
|
|
23
|
+
basic_example_dict = self._create_example_structure(tool_definition, mode='basic')
|
|
24
|
+
basic_example_str = "### Example 1: Basic Call (Required Arguments)\n"
|
|
25
|
+
basic_example_str += "```json\n"
|
|
26
|
+
basic_example_str += json.dumps(basic_example_dict, indent=2)
|
|
27
|
+
basic_example_str += "\n```"
|
|
28
|
+
|
|
29
|
+
if not self._schema_has_advanced_params(tool_definition.argument_schema):
|
|
30
|
+
return basic_example_str
|
|
31
|
+
|
|
32
|
+
advanced_example_dict = self._create_example_structure(tool_definition, mode='advanced')
|
|
33
|
+
advanced_example_str = "### Example 2: Advanced Call (With Optional Arguments)\n"
|
|
34
|
+
advanced_example_str += "```json\n"
|
|
35
|
+
advanced_example_str += json.dumps(advanced_example_dict, indent=2)
|
|
36
|
+
advanced_example_str += "\n```"
|
|
37
|
+
|
|
38
|
+
return f"{basic_example_str}\n\n{advanced_example_str}"
|
|
39
|
+
|
|
40
|
+
def _create_example_structure(self, tool_definition: 'ToolDefinition', mode: str) -> Dict:
|
|
41
|
+
"""Helper to create a single Gemini tool call example for a given mode."""
|
|
15
42
|
tool_name = tool_definition.name
|
|
16
43
|
arg_schema = tool_definition.argument_schema
|
|
17
44
|
arguments = {}
|
|
18
45
|
|
|
19
46
|
if arg_schema and arg_schema.parameters:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
47
|
+
params_to_render = arg_schema.parameters
|
|
48
|
+
if mode == 'basic':
|
|
49
|
+
params_to_render = [p for p in arg_schema.parameters if p.required]
|
|
50
|
+
|
|
51
|
+
for param_def in params_to_render:
|
|
52
|
+
# Use the intelligent placeholder generator from the default formatter
|
|
53
|
+
arguments[param_def.name] = DefaultJsonExampleFormatter._generate_example_from_schema(
|
|
54
|
+
param_def.object_schema or param_def.array_item_schema or param_def.param_type,
|
|
55
|
+
param_def.object_schema or arg_schema,
|
|
56
|
+
mode=mode
|
|
57
|
+
) if param_def.object_schema or param_def.array_item_schema else self._generate_simple_placeholder(param_def)
|
|
58
|
+
|
|
24
59
|
return {"name": tool_name, "args": arguments}
|
|
25
60
|
|
|
26
|
-
def
|
|
27
|
-
|
|
28
|
-
if
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
61
|
+
def _schema_has_advanced_params(self, schema: Optional[ParameterSchema]) -> bool:
|
|
62
|
+
"""Recursively checks if a schema or any of its sub-schemas have non-required parameters."""
|
|
63
|
+
if not schema: return False
|
|
64
|
+
for param in schema.parameters:
|
|
65
|
+
if not param.required: return True
|
|
66
|
+
if param.object_schema and self._schema_has_advanced_params(param.object_schema): return True
|
|
67
|
+
if isinstance(param.array_item_schema, ParameterSchema) and self._schema_has_advanced_params(param.array_item_schema): return True
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
def _generate_simple_placeholder(self, param_def: ParameterDefinition) -> Any:
|
|
71
|
+
"""Generates a simple placeholder for primitive types."""
|
|
32
72
|
if param_def.default_value is not None: return param_def.default_value
|
|
33
|
-
|
|
34
|
-
if param_def.param_type == ParameterType.INTEGER: return 123
|
|
35
|
-
if param_def.param_type == ParameterType.FLOAT: return 123.45
|
|
36
|
-
if param_def.param_type == ParameterType.BOOLEAN: return True
|
|
37
|
-
if param_def.param_type == ParameterType.ENUM: return param_def.enum_values[0] if param_def.enum_values else "enum_val"
|
|
38
|
-
if param_def.param_type == ParameterType.OBJECT: return {"key": "value"}
|
|
39
|
-
if param_def.param_type == ParameterType.ARRAY: return ["item1", "item2"]
|
|
40
|
-
return "placeholder"
|
|
73
|
+
return DefaultJsonExampleFormatter._generate_example_from_schema(param_def.param_type, param_def.param_type, mode='basic')
|