autobyteus 1.1.6__py3-none-any.whl → 1.1.7__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 +100 -88
- 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.7.dist-info/METADATA +204 -0
- {autobyteus-1.1.6.dist-info → autobyteus-1.1.7.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.7.dist-info}/WHEEL +0 -0
- {autobyteus-1.1.6.dist-info → autobyteus-1.1.7.dist-info}/licenses/LICENSE +0 -0
- {autobyteus-1.1.6.dist-info → autobyteus-1.1.7.dist-info}/top_level.txt +0 -0
|
@@ -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')
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# file: autobyteus/autobyteus/tools/usage/formatters/google_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
|
# Import for reuse of the intelligent example generation logic
|
|
7
8
|
from .default_json_example_formatter import DefaultJsonExampleFormatter
|
|
@@ -10,32 +11,64 @@ if TYPE_CHECKING:
|
|
|
10
11
|
from autobyteus.tools.registry import ToolDefinition
|
|
11
12
|
|
|
12
13
|
class GoogleJsonExampleFormatter(BaseExampleFormatter):
|
|
13
|
-
"""
|
|
14
|
+
"""
|
|
15
|
+
Formats a tool usage example into the Google JSON tool_calls format.
|
|
16
|
+
Provides both basic (required only) and advanced (all) examples if optional
|
|
17
|
+
parameters exist for the tool.
|
|
18
|
+
"""
|
|
14
19
|
|
|
15
|
-
def provide(self, tool_definition: 'ToolDefinition') ->
|
|
20
|
+
def provide(self, tool_definition: 'ToolDefinition') -> str:
|
|
21
|
+
"""
|
|
22
|
+
Generates a formatted string containing basic and optionally an advanced usage example for the tool.
|
|
23
|
+
"""
|
|
24
|
+
basic_example_dict = self._create_example_structure(tool_definition, mode='basic')
|
|
25
|
+
basic_example_str = "### Example 1: Basic Call (Required Arguments)\n"
|
|
26
|
+
basic_example_str += "```json\n"
|
|
27
|
+
basic_example_str += json.dumps(basic_example_dict, indent=2)
|
|
28
|
+
basic_example_str += "\n```"
|
|
29
|
+
|
|
30
|
+
if not self._schema_has_advanced_params(tool_definition.argument_schema):
|
|
31
|
+
return basic_example_str
|
|
32
|
+
|
|
33
|
+
advanced_example_dict = self._create_example_structure(tool_definition, mode='advanced')
|
|
34
|
+
advanced_example_str = "### Example 2: Advanced Call (With Optional Arguments)\n"
|
|
35
|
+
advanced_example_str += "```json\n"
|
|
36
|
+
advanced_example_str += json.dumps(advanced_example_dict, indent=2)
|
|
37
|
+
advanced_example_str += "\n```"
|
|
38
|
+
|
|
39
|
+
return f"{basic_example_str}\n\n{advanced_example_str}"
|
|
40
|
+
|
|
41
|
+
def _create_example_structure(self, tool_definition: 'ToolDefinition', mode: str) -> Dict:
|
|
42
|
+
"""Helper to create a single Google tool call example for a given mode."""
|
|
16
43
|
tool_name = tool_definition.name
|
|
17
44
|
arg_schema = tool_definition.argument_schema
|
|
18
45
|
arguments = {}
|
|
19
46
|
|
|
20
47
|
if arg_schema and arg_schema.parameters:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
48
|
+
params_to_render = arg_schema.parameters
|
|
49
|
+
if mode == 'basic':
|
|
50
|
+
params_to_render = [p for p in arg_schema.parameters if p.required]
|
|
51
|
+
|
|
52
|
+
for param_def in params_to_render:
|
|
53
|
+
# Use the intelligent placeholder generator from the default formatter
|
|
54
|
+
arguments[param_def.name] = DefaultJsonExampleFormatter._generate_example_from_schema(
|
|
55
|
+
param_def.object_schema or param_def.array_item_schema or param_def.param_type,
|
|
56
|
+
param_def.object_schema or arg_schema,
|
|
57
|
+
mode=mode
|
|
58
|
+
) if param_def.object_schema or param_def.array_item_schema else self._generate_simple_placeholder(param_def)
|
|
59
|
+
|
|
25
60
|
return {"name": tool_name, "args": arguments}
|
|
26
61
|
|
|
27
|
-
def
|
|
28
|
-
|
|
29
|
-
if
|
|
30
|
-
|
|
62
|
+
def _schema_has_advanced_params(self, schema: Optional[ParameterSchema]) -> bool:
|
|
63
|
+
"""Recursively checks if a schema or any of its sub-schemas have non-required parameters."""
|
|
64
|
+
if not schema: return False
|
|
65
|
+
for param in schema.parameters:
|
|
66
|
+
if not param.required: return True
|
|
67
|
+
if param.object_schema and self._schema_has_advanced_params(param.object_schema): return True
|
|
68
|
+
if isinstance(param.array_item_schema, ParameterSchema) and self._schema_has_advanced_params(param.array_item_schema): return True
|
|
69
|
+
return False
|
|
31
70
|
|
|
32
|
-
|
|
71
|
+
def _generate_simple_placeholder(self, param_def: ParameterDefinition) -> Any:
|
|
72
|
+
"""Generates a simple placeholder for primitive types."""
|
|
33
73
|
if param_def.default_value is not None: return param_def.default_value
|
|
34
|
-
|
|
35
|
-
if param_def.param_type == ParameterType.INTEGER: return 123
|
|
36
|
-
if param_def.param_type == ParameterType.FLOAT: return 123.45
|
|
37
|
-
if param_def.param_type == ParameterType.BOOLEAN: return True
|
|
38
|
-
if param_def.param_type == ParameterType.ENUM: return param_def.enum_values[0] if param_def.enum_values else "enum_val"
|
|
39
|
-
if param_def.param_type == ParameterType.OBJECT: return {"key": "value"}
|
|
40
|
-
if param_def.param_type == ParameterType.ARRAY: return ["item1", "item2"]
|
|
41
|
-
return "placeholder"
|
|
74
|
+
return DefaultJsonExampleFormatter._generate_example_from_schema(param_def.param_type, param_def.param_type, mode='basic')
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# file: autobyteus/autobyteus/tools/usage/formatters/openai_json_example_formatter.py
|
|
2
2
|
import json
|
|
3
|
-
from typing import Dict, Any, TYPE_CHECKING
|
|
3
|
+
from typing import Dict, Any, TYPE_CHECKING, Optional
|
|
4
4
|
|
|
5
|
-
from autobyteus.tools.parameter_schema import
|
|
5
|
+
from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition
|
|
6
6
|
from .base_formatter import BaseExampleFormatter
|
|
7
7
|
from .default_json_example_formatter import DefaultJsonExampleFormatter # Import for reuse
|
|
8
8
|
|
|
@@ -11,41 +11,71 @@ if TYPE_CHECKING:
|
|
|
11
11
|
|
|
12
12
|
class OpenAiJsonExampleFormatter(BaseExampleFormatter):
|
|
13
13
|
"""
|
|
14
|
-
Formats a tool usage example into
|
|
15
|
-
|
|
14
|
+
Formats a tool usage example into the OpenAI JSON 'tool_calls' format.
|
|
15
|
+
Provides both basic (required only) and advanced (all) examples if optional
|
|
16
|
+
parameters exist for the tool.
|
|
16
17
|
"""
|
|
18
|
+
|
|
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
|
|
17
31
|
|
|
18
|
-
|
|
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 OpenAI tool call example for a given mode."""
|
|
19
42
|
tool_name = tool_definition.name
|
|
20
43
|
arg_schema = tool_definition.argument_schema
|
|
21
44
|
arguments = {}
|
|
22
45
|
|
|
23
46
|
if arg_schema and arg_schema.parameters:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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)
|
|
27
58
|
|
|
28
59
|
function_call = {
|
|
29
60
|
"function": {
|
|
30
61
|
"name": tool_name,
|
|
31
|
-
|
|
62
|
+
# FIX: Keep arguments as a dictionary for clear examples in the prompt.
|
|
63
|
+
# Do NOT stringify it here.
|
|
64
|
+
"arguments": arguments,
|
|
32
65
|
},
|
|
33
66
|
}
|
|
34
|
-
|
|
35
67
|
return {"tool": function_call}
|
|
36
68
|
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
if
|
|
40
|
-
|
|
69
|
+
def _schema_has_advanced_params(self, schema: Optional[ParameterSchema]) -> bool:
|
|
70
|
+
"""Recursively checks if a schema or any of its sub-schemas have non-required parameters."""
|
|
71
|
+
if not schema: return False
|
|
72
|
+
for param in schema.parameters:
|
|
73
|
+
if not param.required: return True
|
|
74
|
+
if param.object_schema and self._schema_has_advanced_params(param.object_schema): return True
|
|
75
|
+
if isinstance(param.array_item_schema, ParameterSchema) and self._schema_has_advanced_params(param.array_item_schema): return True
|
|
76
|
+
return False
|
|
41
77
|
|
|
42
|
-
|
|
78
|
+
def _generate_simple_placeholder(self, param_def: ParameterDefinition) -> Any:
|
|
79
|
+
"""Generates a simple placeholder for primitive types."""
|
|
43
80
|
if param_def.default_value is not None: return param_def.default_value
|
|
44
|
-
|
|
45
|
-
if param_def.param_type == ParameterType.INTEGER: return 123
|
|
46
|
-
if param_def.param_type == ParameterType.FLOAT: return 123.45
|
|
47
|
-
if param_def.param_type == ParameterType.BOOLEAN: return True
|
|
48
|
-
if param_def.param_type == ParameterType.ENUM: return param_def.enum_values[0] if param_def.enum_values else "enum_val"
|
|
49
|
-
if param_def.param_type == ParameterType.OBJECT: return {"key": "value"}
|
|
50
|
-
if param_def.param_type == ParameterType.ARRAY: return ["item1", "item2"]
|
|
51
|
-
return "placeholder"
|
|
81
|
+
return DefaultJsonExampleFormatter._generate_example_from_schema(param_def.param_type, param_def.param_type, mode='basic')
|