autobyteus 1.1.8__py3-none-any.whl → 1.1.9__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.
Files changed (108) hide show
  1. autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +6 -2
  2. autobyteus/agent/handlers/inter_agent_message_event_handler.py +17 -19
  3. autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +6 -3
  4. autobyteus/agent/handlers/tool_result_event_handler.py +61 -18
  5. autobyteus/agent/handlers/user_input_message_event_handler.py +19 -10
  6. autobyteus/agent/hooks/base_phase_hook.py +17 -0
  7. autobyteus/agent/hooks/hook_registry.py +15 -27
  8. autobyteus/agent/input_processor/base_user_input_processor.py +17 -1
  9. autobyteus/agent/input_processor/processor_registry.py +15 -27
  10. autobyteus/agent/llm_response_processor/base_processor.py +17 -1
  11. autobyteus/agent/llm_response_processor/processor_registry.py +15 -24
  12. autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +14 -0
  13. autobyteus/agent/message/agent_input_user_message.py +15 -2
  14. autobyteus/agent/message/send_message_to.py +1 -1
  15. autobyteus/agent/processor_option.py +17 -0
  16. autobyteus/agent/sender_type.py +1 -0
  17. autobyteus/agent/system_prompt_processor/base_processor.py +17 -1
  18. autobyteus/agent/system_prompt_processor/processor_registry.py +15 -27
  19. autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +10 -0
  20. autobyteus/agent/tool_execution_result_processor/base_processor.py +17 -1
  21. autobyteus/agent/tool_execution_result_processor/processor_registry.py +15 -1
  22. autobyteus/agent/workspace/base_workspace.py +1 -1
  23. autobyteus/agent/workspace/workspace_definition.py +1 -1
  24. autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +1 -1
  25. autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +2 -2
  26. autobyteus/agent_team/task_notification/__init__.py +4 -0
  27. autobyteus/agent_team/task_notification/activation_policy.py +70 -0
  28. autobyteus/agent_team/task_notification/system_event_driven_agent_task_notifier.py +56 -122
  29. autobyteus/agent_team/task_notification/task_activator.py +66 -0
  30. autobyteus/cli/agent_team_tui/state.py +17 -20
  31. autobyteus/cli/agent_team_tui/widgets/focus_pane.py +1 -1
  32. autobyteus/cli/agent_team_tui/widgets/task_board_panel.py +1 -1
  33. autobyteus/events/event_types.py +2 -2
  34. autobyteus/llm/api/gemini_llm.py +45 -54
  35. autobyteus/llm/api/qwen_llm.py +25 -0
  36. autobyteus/llm/autobyteus_provider.py +8 -2
  37. autobyteus/llm/llm_factory.py +16 -0
  38. autobyteus/multimedia/audio/api/autobyteus_audio_client.py +4 -1
  39. autobyteus/multimedia/audio/api/gemini_audio_client.py +84 -153
  40. autobyteus/multimedia/audio/audio_client_factory.py +47 -22
  41. autobyteus/multimedia/audio/audio_model.py +13 -6
  42. autobyteus/multimedia/audio/autobyteus_audio_provider.py +8 -2
  43. autobyteus/multimedia/audio/base_audio_client.py +3 -1
  44. autobyteus/multimedia/image/api/autobyteus_image_client.py +12 -5
  45. autobyteus/multimedia/image/api/gemini_image_client.py +72 -130
  46. autobyteus/multimedia/image/api/openai_image_client.py +4 -2
  47. autobyteus/multimedia/image/autobyteus_image_provider.py +8 -2
  48. autobyteus/multimedia/image/base_image_client.py +6 -2
  49. autobyteus/multimedia/image/image_client_factory.py +20 -19
  50. autobyteus/multimedia/image/image_model.py +13 -6
  51. autobyteus/multimedia/providers.py +1 -0
  52. autobyteus/task_management/__init__.py +9 -10
  53. autobyteus/task_management/base_task_board.py +14 -6
  54. autobyteus/task_management/converters/__init__.py +0 -2
  55. autobyteus/task_management/converters/task_board_converter.py +7 -16
  56. autobyteus/task_management/events.py +6 -6
  57. autobyteus/task_management/in_memory_task_board.py +48 -38
  58. autobyteus/task_management/schemas/__init__.py +2 -2
  59. autobyteus/task_management/schemas/{plan_definition.py → task_definition.py} +5 -6
  60. autobyteus/task_management/schemas/task_status_report.py +0 -1
  61. autobyteus/task_management/task.py +60 -0
  62. autobyteus/task_management/tools/__init__.py +4 -2
  63. autobyteus/task_management/tools/get_my_tasks.py +80 -0
  64. autobyteus/task_management/tools/get_task_board_status.py +3 -3
  65. autobyteus/task_management/tools/publish_task.py +77 -0
  66. autobyteus/task_management/tools/publish_tasks.py +74 -0
  67. autobyteus/task_management/tools/update_task_status.py +5 -5
  68. autobyteus/tools/__init__.py +3 -1
  69. autobyteus/tools/base_tool.py +4 -4
  70. autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +1 -1
  71. autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +1 -1
  72. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +1 -1
  73. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +1 -1
  74. autobyteus/tools/browser/standalone/navigate_to.py +1 -1
  75. autobyteus/tools/browser/standalone/web_page_pdf_generator.py +1 -1
  76. autobyteus/tools/browser/standalone/webpage_image_downloader.py +1 -1
  77. autobyteus/tools/browser/standalone/webpage_reader.py +1 -1
  78. autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +1 -1
  79. autobyteus/tools/functional_tool.py +1 -1
  80. autobyteus/tools/google_search.py +1 -1
  81. autobyteus/tools/image_downloader.py +1 -1
  82. autobyteus/tools/mcp/factory.py +1 -1
  83. autobyteus/tools/mcp/schema_mapper.py +1 -1
  84. autobyteus/tools/mcp/tool.py +1 -1
  85. autobyteus/tools/multimedia/__init__.py +2 -0
  86. autobyteus/tools/multimedia/audio_tools.py +10 -20
  87. autobyteus/tools/multimedia/image_tools.py +21 -22
  88. autobyteus/tools/multimedia/media_reader_tool.py +117 -0
  89. autobyteus/tools/pydantic_schema_converter.py +1 -1
  90. autobyteus/tools/registry/tool_definition.py +1 -1
  91. autobyteus/tools/timer.py +1 -1
  92. autobyteus/tools/tool_meta.py +1 -1
  93. autobyteus/tools/usage/formatters/default_json_example_formatter.py +1 -1
  94. autobyteus/tools/usage/formatters/default_xml_example_formatter.py +1 -1
  95. autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +59 -3
  96. autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +1 -1
  97. autobyteus/tools/usage/formatters/google_json_example_formatter.py +1 -1
  98. autobyteus/tools/usage/formatters/openai_json_example_formatter.py +1 -1
  99. autobyteus/{tools → utils}/parameter_schema.py +1 -1
  100. {autobyteus-1.1.8.dist-info → autobyteus-1.1.9.dist-info}/METADATA +2 -2
  101. {autobyteus-1.1.8.dist-info → autobyteus-1.1.9.dist-info}/RECORD +105 -99
  102. examples/run_poem_writer.py +1 -1
  103. autobyteus/task_management/converters/task_plan_converter.py +0 -48
  104. autobyteus/task_management/task_plan.py +0 -110
  105. autobyteus/task_management/tools/publish_task_plan.py +0 -101
  106. {autobyteus-1.1.8.dist-info → autobyteus-1.1.9.dist-info}/WHEEL +0 -0
  107. {autobyteus-1.1.8.dist-info → autobyteus-1.1.9.dist-info}/licenses/LICENSE +0 -0
  108. {autobyteus-1.1.8.dist-info → autobyteus-1.1.9.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,7 @@ from typing import Optional, TYPE_CHECKING, Any
5
5
  from autobyteus.tools.browser.session_aware.browser_session_aware_tool import BrowserSessionAwareTool
6
6
  from autobyteus.tools.browser.session_aware.shared_browser_session import SharedBrowserSession
7
7
  from autobyteus.tools.tool_config import ToolConfig
8
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
8
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
9
9
  from autobyteus.tools.tool_category import ToolCategory
10
10
  from autobyteus.utils.html_cleaner import clean, CleaningMode
11
11
 
@@ -6,7 +6,7 @@ from typing import Optional, TYPE_CHECKING, Any
6
6
  from autobyteus.tools.browser.session_aware.browser_session_aware_tool import BrowserSessionAwareTool
7
7
  from autobyteus.tools.browser.session_aware.shared_browser_session import SharedBrowserSession
8
8
  from autobyteus.tools.tool_config import ToolConfig
9
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
9
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
10
10
  from autobyteus.tools.tool_category import ToolCategory
11
11
 
12
12
  if TYPE_CHECKING:
@@ -6,7 +6,7 @@ from urllib.parse import urlparse
6
6
  from typing import Optional, TYPE_CHECKING, Any
7
7
  import logging
8
8
 
9
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
9
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
10
10
 
11
11
  if TYPE_CHECKING:
12
12
  from autobyteus.agent.context import AgentContext
@@ -7,7 +7,7 @@ import logging
7
7
  from typing import Optional, TYPE_CHECKING, Any
8
8
  from urllib.parse import urlparse
9
9
 
10
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
10
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from autobyteus.agent.context import AgentContext
@@ -7,7 +7,7 @@ import logging
7
7
  from urllib.parse import urljoin, urlparse
8
8
  from typing import Optional, TYPE_CHECKING, Any, List
9
9
 
10
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
10
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from autobyteus.agent.context import AgentContext
@@ -7,7 +7,7 @@ import logging
7
7
  from typing import Optional, TYPE_CHECKING, Any
8
8
  from autobyteus.tools.base_tool import BaseTool
9
9
  from autobyteus.tools.tool_config import ToolConfig
10
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
10
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
11
11
  from autobyteus.tools.tool_category import ToolCategory
12
12
  from brui_core.ui_integrator import UIIntegrator
13
13
  from autobyteus.utils.html_cleaner import clean, CleaningMode
@@ -1,7 +1,7 @@
1
1
  from typing import Optional, TYPE_CHECKING, Any
2
2
  from autobyteus.tools.base_tool import BaseTool
3
3
  from autobyteus.tools.tool_config import ToolConfig
4
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
4
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
5
5
  from autobyteus.tools.tool_category import ToolCategory
6
6
  from brui_core.ui_integrator import UIIntegrator
7
7
  import logging
@@ -5,7 +5,7 @@ import asyncio
5
5
  from typing import Callable, Optional, Any, Dict, Tuple, Union, get_origin, get_args, List as TypingList, TYPE_CHECKING, Type
6
6
 
7
7
  from autobyteus.tools.base_tool import BaseTool
8
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
8
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
9
9
  from autobyteus.tools.tool_config import ToolConfig
10
10
  from autobyteus.tools.registry import default_tool_registry, ToolDefinition
11
11
  from autobyteus.tools.tool_origin import ToolOrigin
@@ -6,7 +6,7 @@ from typing import Optional, TYPE_CHECKING, Any, Dict, List
6
6
 
7
7
  from autobyteus.tools.base_tool import BaseTool
8
8
  from autobyteus.tools.tool_config import ToolConfig
9
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
9
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
10
10
  from autobyteus.tools.tool_category import ToolCategory
11
11
 
12
12
  if TYPE_CHECKING:
@@ -6,7 +6,7 @@ from typing import Optional, TYPE_CHECKING, Any
6
6
 
7
7
  from autobyteus.tools.base_tool import BaseTool
8
8
  from autobyteus.tools.tool_config import ToolConfig
9
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
9
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
10
10
  from autobyteus.tools.tool_category import ToolCategory
11
11
  from PIL import Image
12
12
  from io import BytesIO
@@ -6,7 +6,7 @@ from .tool import GenericMcpTool
6
6
  from autobyteus.tools.factory.tool_factory import ToolFactory
7
7
 
8
8
  if TYPE_CHECKING:
9
- from autobyteus.tools.parameter_schema import ParameterSchema
9
+ from autobyteus.utils.parameter_schema import ParameterSchema
10
10
  from autobyteus.tools.tool_config import ToolConfig
11
11
  from autobyteus.tools.base_tool import BaseTool
12
12
 
@@ -2,7 +2,7 @@
2
2
  import logging
3
3
  from typing import Dict, Any, List, Optional
4
4
 
5
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
5
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
6
6
 
7
7
  logger = logging.getLogger(__name__)
8
8
 
@@ -3,7 +3,7 @@ import logging
3
3
  from typing import Any, Optional, TYPE_CHECKING
4
4
 
5
5
  from autobyteus.tools.base_tool import BaseTool
6
- from autobyteus.tools.parameter_schema import ParameterSchema
6
+ from autobyteus.utils.parameter_schema import ParameterSchema
7
7
  from .server.proxy import McpServerProxy
8
8
 
9
9
  if TYPE_CHECKING:
@@ -1,8 +1,10 @@
1
1
  from .image_tools import GenerateImageTool, EditImageTool
2
2
  from .audio_tools import GenerateSpeechTool
3
+ from .media_reader_tool import ReadMediaFile
3
4
 
4
5
  __all__ = [
5
6
  "GenerateImageTool",
6
7
  "EditImageTool",
7
8
  "GenerateSpeechTool",
9
+ "ReadMediaFile",
8
10
  ]
@@ -3,7 +3,7 @@ import logging
3
3
  from typing import Optional, List
4
4
 
5
5
  from autobyteus.tools.base_tool import BaseTool
6
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
6
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
7
7
  from autobyteus.tools.tool_category import ToolCategory
8
8
  from autobyteus.multimedia.audio import audio_client_factory, AudioModel, AudioClientFactory
9
9
 
@@ -34,24 +34,8 @@ def _build_dynamic_audio_schema(base_params: List[ParameterDefinition], model_en
34
34
  logger.error(f"Cannot generate audio tool schema. Check environment and model registry. Error: {e}")
35
35
  raise RuntimeError(f"Failed to configure audio tool. Error: {e}")
36
36
 
37
- config_schema = ParameterSchema()
38
- if model.parameter_schema:
39
- for name, meta in model.parameter_schema.items():
40
- param_type_str = meta.get("type", "string").upper()
41
- param_type = getattr(ParameterType, param_type_str, ParameterType.STRING)
42
-
43
- allowed_values = meta.get("allowed_values")
44
- if param_type == ParameterType.STRING and allowed_values:
45
- param_type = ParameterType.ENUM
46
-
47
- config_schema.add_parameter(ParameterDefinition(
48
- name=name,
49
- param_type=param_type,
50
- description=meta.get("description", ""),
51
- required=False,
52
- default_value=meta.get("default"),
53
- enum_values=allowed_values
54
- ))
37
+ # The model's parameter schema is now a ParameterSchema object, so we can use it directly.
38
+ config_schema = model.parameter_schema
55
39
 
56
40
  schema = ParameterSchema()
57
41
  for param in base_params:
@@ -70,6 +54,7 @@ def _build_dynamic_audio_schema(base_params: List[ParameterDefinition], model_en
70
54
 
71
55
  class GenerateSpeechTool(BaseTool):
72
56
  """
57
+
73
58
  An agent tool for generating speech from text using a Text-to-Speech (TTS) model.
74
59
  """
75
60
  CATEGORY = ToolCategory.MULTIMEDIA
@@ -93,7 +78,12 @@ class GenerateSpeechTool(BaseTool):
93
78
  ParameterDefinition(
94
79
  name="prompt",
95
80
  param_type=ParameterType.STRING,
96
- description="The text to be converted into spoken audio.",
81
+ description=(
82
+ "The text to be converted into spoken audio. For multi-speaker mode, you must format the prompt "
83
+ "with speaker labels that match the speakers defined in 'speaker_mapping'. "
84
+ "CRITICAL: Each speaker's dialogue MUST be on a new line. "
85
+ "Example: 'Joe: Hello Jane.\\nJane: Hi Joe, how are you?'"
86
+ ),
97
87
  required=True
98
88
  )
99
89
  ]
@@ -3,7 +3,7 @@ import logging
3
3
  from typing import Optional, List
4
4
 
5
5
  from autobyteus.tools.base_tool import BaseTool
6
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
6
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
7
7
  from autobyteus.tools.tool_category import ToolCategory
8
8
  from autobyteus.multimedia.image import image_client_factory, ImageModel, ImageClientFactory
9
9
 
@@ -34,24 +34,8 @@ def _build_dynamic_image_schema(base_params: List[ParameterDefinition], model_en
34
34
  logger.error(f"Cannot generate image tool schema. Check environment and model registry. Error: {e}")
35
35
  raise RuntimeError(f"Failed to configure image tool. Error: {e}")
36
36
 
37
- config_schema = ParameterSchema()
38
- if model.parameter_schema:
39
- for name, meta in model.parameter_schema.items():
40
- param_type_str = meta.get("type", "string").upper()
41
- param_type = getattr(ParameterType, param_type_str, ParameterType.STRING)
42
-
43
- allowed_values = meta.get("allowed_values")
44
- if param_type == ParameterType.STRING and allowed_values:
45
- param_type = ParameterType.ENUM
46
-
47
- config_schema.add_parameter(ParameterDefinition(
48
- name=name,
49
- param_type=param_type,
50
- description=meta.get("description", ""),
51
- required=False,
52
- default_value=meta.get("default"),
53
- enum_values=allowed_values
54
- ))
37
+ # The model's parameter schema is now a ParameterSchema object, so we can use it directly.
38
+ config_schema = model.parameter_schema
55
39
 
56
40
  schema = ParameterSchema()
57
41
  for param in base_params:
@@ -84,6 +68,7 @@ class GenerateImageTool(BaseTool):
84
68
  def get_description(cls) -> str:
85
69
  return (
86
70
  "Generates one or more images based on a textual description (prompt) using the system's default image model. "
71
+ "Can optionally accept reference images to influence the style or content. "
87
72
  "Returns a list of URLs to the generated images upon success."
88
73
  )
89
74
 
@@ -95,17 +80,31 @@ class GenerateImageTool(BaseTool):
95
80
  param_type=ParameterType.STRING,
96
81
  description="A detailed textual description of the image to generate.",
97
82
  required=True
83
+ ),
84
+ ParameterDefinition(
85
+ name="input_image_urls",
86
+ param_type=ParameterType.STRING,
87
+ description="Optional. A comma-separated string of URLs to reference images. The generated image will try to match the style or content of these images.",
88
+ required=False
98
89
  )
99
90
  ]
100
91
  return _build_dynamic_image_schema(base_params, cls.MODEL_ENV_VAR, cls.DEFAULT_MODEL)
101
92
 
102
- async def _execute(self, context, prompt: str, generation_config: Optional[dict] = None) -> List[str]:
93
+ async def _execute(self, context, prompt: str, input_image_urls: Optional[str] = None, generation_config: Optional[dict] = None) -> List[str]:
103
94
  model_identifier = _get_configured_model_identifier(self.MODEL_ENV_VAR, self.DEFAULT_MODEL)
104
95
  logger.info(f"GenerateImageTool executing with configured model '{model_identifier}'.")
105
96
  client = None
106
97
  try:
98
+ urls_list = None
99
+ if input_image_urls:
100
+ urls_list = [url.strip() for url in input_image_urls.split(',') if url.strip()]
101
+
107
102
  client = image_client_factory.create_image_client(model_identifier=model_identifier)
108
- response = await client.generate_image(prompt=prompt, generation_config=generation_config)
103
+ response = await client.generate_image(
104
+ prompt=prompt,
105
+ input_image_urls=urls_list,
106
+ generation_config=generation_config
107
+ )
109
108
 
110
109
  if not response.image_urls:
111
110
  raise ValueError("Image generation failed to return any image URLs.")
@@ -121,7 +120,7 @@ class EditImageTool(BaseTool):
121
120
  An agent tool for editing an existing image using a text prompt and a pre-configured model.
122
121
  """
123
122
  CATEGORY = ToolCategory.MULTIMEDIA
124
- MODEL_ENV_VAR = "DEFAULT_IMAGE_GENERATION_MODEL"
123
+ MODEL_ENV_VAR = "DEFAULT_IMAGE_EDIT_MODEL"
125
124
  DEFAULT_MODEL = "gpt-image-1"
126
125
 
127
126
  @classmethod
@@ -0,0 +1,117 @@
1
+ # file: autobyteus/autobyteus/tools/multimedia/media_reader_tool.py
2
+ import logging
3
+ import os
4
+ from typing import TYPE_CHECKING, Optional
5
+
6
+ from autobyteus.tools.base_tool import BaseTool
7
+ from autobyteus.tools.tool_category import ToolCategory
8
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
9
+ from autobyteus.agent.message.context_file import ContextFile
10
+
11
+ if TYPE_CHECKING:
12
+ from autobyteus.agent.context import AgentContext
13
+ from autobyteus.agent.workspace.base_workspace import BaseAgentWorkspace
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class ReadMediaFile(BaseTool):
18
+ """
19
+ A tool that loads a media file (image, audio, video) into the context for
20
+ the next LLM turn. This allows a multimodal LLM to directly 'see' or 'hear'
21
+ the file's content. The tool's result is a structured object that the system
22
+ uses to construct a multimodal prompt, not plain text.
23
+ """
24
+ TOOL_NAME = "ReadMediaFile"
25
+ CATEGORY = ToolCategory.MULTIMEDIA
26
+
27
+ @classmethod
28
+ def get_name(cls) -> str:
29
+ return cls.TOOL_NAME
30
+
31
+ @classmethod
32
+ def get_description(cls) -> str:
33
+ return (
34
+ "Loads a media file (image, audio, video) into the context for the next turn, "
35
+ "allowing the LLM to directly analyze its content. Use this when you need to 'see' an image, "
36
+ "'listen' to audio, or 'watch' a video that you know exists in the workspace or file system."
37
+ )
38
+
39
+ @classmethod
40
+ def get_argument_schema(cls) -> Optional[ParameterSchema]:
41
+ schema = ParameterSchema()
42
+ schema.add_parameter(ParameterDefinition(
43
+ name="file_path",
44
+ param_type=ParameterType.STRING,
45
+ description="The absolute path or workspace-relative path to the media file.",
46
+ required=True
47
+ ))
48
+ return schema
49
+
50
+ async def _execute(self,
51
+ context: 'AgentContext',
52
+ file_path: str) -> 'ContextFile':
53
+ """
54
+ Resolves the file path and returns a ContextFile object, which signals
55
+ the system to include this file in the next multimodal LLM prompt.
56
+ It handles both absolute paths and paths relative to the agent's workspace.
57
+ """
58
+ logger.debug(f"Tool '{self.get_name()}': Received request to read media file at '{file_path}'.")
59
+
60
+ absolute_path: str
61
+ workspace: Optional['BaseAgentWorkspace'] = context.workspace
62
+
63
+ if os.path.isabs(file_path):
64
+ absolute_path = os.path.normpath(file_path)
65
+ logger.debug(f"Path '{file_path}' is absolute. Using resolved path: '{absolute_path}'.")
66
+
67
+ # Security Note: This allows reading from outside the workspace.
68
+ # We log a warning if this occurs.
69
+ if workspace and hasattr(workspace, 'get_base_path'):
70
+ try:
71
+ workspace_root = os.path.abspath(workspace.get_base_path())
72
+ resolved_target = os.path.abspath(absolute_path)
73
+ if not os.path.commonpath([workspace_root]) == os.path.commonpath([workspace_root, resolved_target]):
74
+ logger.warning(
75
+ f"Security Note: Tool '{self.get_name()}' is accessing an absolute path "
76
+ f"'{absolute_path}' which is outside the agent's workspace '{workspace_root}'."
77
+ )
78
+ except Exception:
79
+ # Failsafe if get_base_path has an issue.
80
+ pass
81
+ else:
82
+ # Handle relative paths, which MUST be resolved against a workspace that supports file paths.
83
+ if not (workspace and hasattr(workspace, 'get_base_path') and callable(getattr(workspace, 'get_base_path'))):
84
+ raise ValueError(
85
+ f"A relative path '{file_path}' was provided, but the agent's workspace does not support "
86
+ "file system path resolution. Please provide an absolute path or configure a suitable workspace."
87
+ )
88
+
89
+ try:
90
+ base_path = os.path.abspath(workspace.get_base_path())
91
+ # Securely join the path and resolve it to a final absolute path
92
+ absolute_path = os.path.abspath(os.path.join(base_path, file_path))
93
+
94
+ # Security Check: Ensure the resolved path is still within the workspace directory.
95
+ if os.path.commonpath([base_path]) != os.path.commonpath([base_path, absolute_path]):
96
+ raise ValueError(f"Security error: Path '{file_path}' attempts to access files outside the agent's workspace.")
97
+
98
+ logger.debug(f"Path '{file_path}' is relative. Resolved against workspace to '{absolute_path}'.")
99
+
100
+ except ValueError as e:
101
+ # Re-raise security errors with more context.
102
+ logger.error(f"Tool '{self.get_name()}': Security error resolving relative path '{file_path}': {e}")
103
+ raise
104
+
105
+ try:
106
+ if not os.path.exists(absolute_path) or not os.path.isfile(absolute_path):
107
+ raise FileNotFoundError(f"The file '{file_path}' does not exist or is not a regular file at the resolved path '{absolute_path}'.")
108
+
109
+ logger.info(f"Tool '{self.get_name()}': Staging file '{absolute_path}' for next LLM turn.")
110
+
111
+ # The ContextFile constructor will automatically infer file_type from the path.
112
+ # This is the special object that the ToolResultEventHandler will look for.
113
+ return ContextFile(uri=absolute_path)
114
+
115
+ except (ValueError, FileNotFoundError) as e:
116
+ logger.error(f"Tool '{self.get_name()}': Error processing path '{file_path}': {e}")
117
+ raise
@@ -2,7 +2,7 @@
2
2
  import logging
3
3
  from typing import Type, get_origin, get_args, Union, List, Dict
4
4
  from pydantic import BaseModel
5
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
5
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
6
6
 
7
7
  logger = logging.getLogger(__name__)
8
8
 
@@ -5,7 +5,7 @@ from typing import Dict, Any, List as TypingList, Type, TYPE_CHECKING, Optional,
5
5
 
6
6
  from autobyteus.llm.providers import LLMProvider
7
7
  from autobyteus.tools.tool_config import ToolConfig
8
- from autobyteus.tools.parameter_schema import ParameterSchema
8
+ from autobyteus.utils.parameter_schema import ParameterSchema
9
9
  from autobyteus.tools.tool_origin import ToolOrigin
10
10
  # Import default formatters directly to provide convenience methods
11
11
  from autobyteus.tools.usage.formatters import (
autobyteus/tools/timer.py CHANGED
@@ -2,7 +2,7 @@ import asyncio
2
2
  from typing import Optional, TYPE_CHECKING, Any
3
3
  from autobyteus.tools.base_tool import BaseTool
4
4
  from autobyteus.tools.tool_config import ToolConfig
5
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
5
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
6
6
  from autobyteus.tools.tool_category import ToolCategory
7
7
  from autobyteus.events.event_emitter import EventEmitter
8
8
  from autobyteus.events.event_types import EventType
@@ -4,7 +4,7 @@ from abc import ABCMeta
4
4
  from typing import Dict, Any
5
5
 
6
6
  from autobyteus.tools.registry import default_tool_registry, ToolDefinition
7
- from autobyteus.tools.parameter_schema import ParameterSchema
7
+ from autobyteus.utils.parameter_schema import ParameterSchema
8
8
  from autobyteus.tools.tool_origin import ToolOrigin
9
9
  from autobyteus.tools.tool_category import ToolCategory
10
10
 
@@ -2,7 +2,7 @@
2
2
  import json
3
3
  from typing import Dict, Any, TYPE_CHECKING, List, Optional, Union
4
4
 
5
- from autobyteus.tools.parameter_schema import ParameterType, ParameterDefinition, ParameterSchema
5
+ from autobyteus.utils.parameter_schema import ParameterType, ParameterDefinition, ParameterSchema
6
6
  from .base_formatter import BaseExampleFormatter
7
7
 
8
8
  if TYPE_CHECKING:
@@ -3,7 +3,7 @@ import xml.sax.saxutils
3
3
  import re
4
4
  from typing import Any, TYPE_CHECKING, List, Optional
5
5
 
6
- from autobyteus.tools.parameter_schema import ParameterType, ParameterDefinition, ParameterSchema
6
+ from autobyteus.utils.parameter_schema import ParameterType, ParameterDefinition, ParameterSchema
7
7
  from .base_formatter import BaseExampleFormatter
8
8
 
9
9
  if TYPE_CHECKING:
@@ -1,8 +1,8 @@
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, List
3
+ from typing import TYPE_CHECKING, List, Dict
4
4
 
5
- from autobyteus.tools.parameter_schema import ParameterType, ParameterDefinition, ParameterSchema
5
+ from autobyteus.utils.parameter_schema import ParameterType, ParameterDefinition, ParameterSchema
6
6
  from .base_formatter import BaseSchemaFormatter
7
7
 
8
8
  if TYPE_CHECKING:
@@ -30,6 +30,49 @@ class DefaultXmlSchemaFormatter(BaseSchemaFormatter):
30
30
  xml_parts.append("</tool>")
31
31
  return "\n".join(xml_parts)
32
32
 
33
+ def _json_schema_props_to_param_defs(self, schema_dict: Dict) -> List[ParameterDefinition]:
34
+ """
35
+ Converts a JSON schema's 'properties' dictionary into a list of ParameterDefinition objects.
36
+ This is used to bridge raw JSON schemas with the internal formatting logic.
37
+ """
38
+ param_defs = []
39
+ properties = schema_dict.get("properties", {})
40
+ required_fields = schema_dict.get("required", [])
41
+
42
+ for prop_name, prop_schema in properties.items():
43
+ if not isinstance(prop_schema, dict):
44
+ continue
45
+
46
+ param_type_str = prop_schema.get("type", "string").upper()
47
+ param_type = getattr(ParameterType, param_type_str, ParameterType.STRING)
48
+
49
+ # JSON Schema uses 'enum' key for enumerations
50
+ allowed_values = prop_schema.get("enum")
51
+ if param_type == ParameterType.STRING and allowed_values:
52
+ param_type = ParameterType.ENUM
53
+
54
+ object_schema = None
55
+ if param_type == ParameterType.OBJECT and "properties" in prop_schema:
56
+ # Recursively build a ParameterSchema for nested objects
57
+ nested_param_defs = self._json_schema_props_to_param_defs(prop_schema)
58
+ object_schema = ParameterSchema(parameters=nested_param_defs)
59
+
60
+ array_item_schema = None
61
+ if param_type == ParameterType.ARRAY and "items" in prop_schema:
62
+ # Pass the nested schema down; it will be handled by the next recursive call
63
+ array_item_schema = prop_schema["items"]
64
+
65
+ param_defs.append(ParameterDefinition(
66
+ name=prop_name,
67
+ param_type=param_type,
68
+ description=prop_schema.get("description", ""),
69
+ required=(prop_name in required_fields),
70
+ enum_values=allowed_values,
71
+ object_schema=object_schema,
72
+ array_item_schema=array_item_schema
73
+ ))
74
+ return param_defs
75
+
33
76
  def _format_params_recursively(self, params: List[ParameterDefinition], indent_level: int) -> List[str]:
34
77
  """Recursively formats parameter definitions into XML strings."""
35
78
  xml_lines = []
@@ -61,13 +104,26 @@ class DefaultXmlSchemaFormatter(BaseSchemaFormatter):
61
104
  elif is_array:
62
105
  xml_lines.append(f'{indent}<arg {" ".join(attrs)}>')
63
106
  if isinstance(param.array_item_schema, ParameterSchema):
64
- # Array of objects
107
+ # Array of objects defined with our internal ParameterSchema
65
108
  xml_lines.append(f'{indent} <items type="object">')
66
109
  xml_lines.extend(self._format_params_recursively(param.array_item_schema.parameters, indent_level + 2))
67
110
  xml_lines.append(f'{indent} </items>')
68
111
  elif isinstance(param.array_item_schema, ParameterType):
69
112
  # Array of primitives
70
113
  xml_lines.append(f'{indent} <items type="{param.array_item_schema.value}" />')
114
+ elif isinstance(param.array_item_schema, dict):
115
+ # FIX: Handle array of objects defined with a raw JSON schema dict
116
+ item_schema_dict = param.array_item_schema
117
+ item_type = item_schema_dict.get("type", "string")
118
+
119
+ xml_lines.append(f'{indent} <items type="{item_type}">')
120
+
121
+ if item_type == "object":
122
+ # Convert the JSON schema properties to our internal ParameterDefinition list
123
+ param_defs = self._json_schema_props_to_param_defs(item_schema_dict)
124
+ xml_lines.extend(self._format_params_recursively(param_defs, indent_level + 2))
125
+
126
+ xml_lines.append(f'{indent} </items>')
71
127
  xml_lines.append(f'{indent}</arg>')
72
128
  else:
73
129
  # This is a simple/primitive type or a generic array
@@ -2,7 +2,7 @@
2
2
  import json
3
3
  from typing import Dict, Any, TYPE_CHECKING, Optional
4
4
 
5
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition
5
+ from autobyteus.utils.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
 
@@ -2,7 +2,7 @@
2
2
  import json
3
3
  from typing import Dict, Any, TYPE_CHECKING, Optional
4
4
 
5
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition
5
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition
6
6
  from .base_formatter import BaseExampleFormatter
7
7
  # Import for reuse of the intelligent example generation logic
8
8
  from .default_json_example_formatter import DefaultJsonExampleFormatter
@@ -2,7 +2,7 @@
2
2
  import json
3
3
  from typing import Dict, Any, TYPE_CHECKING, Optional
4
4
 
5
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition
5
+ from autobyteus.utils.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
 
@@ -1,4 +1,4 @@
1
- # file: autobyteus/autobyteus/tools/parameter_schema.py
1
+ # file: autobyteus/autobyteus/utils/parameter_schema.py
2
2
  from __future__ import annotations
3
3
  import logging
4
4
  from typing import Dict, Any, List, Optional, Union, Type
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autobyteus
3
- Version: 1.1.8
3
+ Version: 1.1.9
4
4
  Summary: Multi-Agent framework
5
5
  Home-page: https://github.com/AutoByteus/autobyteus
6
6
  Author: Ryan Zheng
@@ -23,7 +23,7 @@ Requires-Dist: botocore
23
23
  Requires-Dist: brui-core==1.0.9
24
24
  Requires-Dist: certifi==2025.4.26
25
25
  Requires-Dist: google-api-python-client
26
- Requires-Dist: google-generativeai
26
+ Requires-Dist: google-genai==1.38.0
27
27
  Requires-Dist: Jinja2
28
28
  Requires-Dist: mcp[cli]
29
29
  Requires-Dist: mistral_common