autobyteus 1.1.5__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.
Files changed (103) hide show
  1. autobyteus/agent/context/agent_config.py +6 -1
  2. autobyteus/agent/context/agent_runtime_state.py +7 -1
  3. autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +30 -7
  4. autobyteus/agent/handlers/tool_result_event_handler.py +100 -88
  5. autobyteus/agent/handlers/user_input_message_event_handler.py +22 -25
  6. autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +7 -1
  7. autobyteus/agent/message/__init__.py +7 -5
  8. autobyteus/agent/message/agent_input_user_message.py +6 -16
  9. autobyteus/agent/message/context_file.py +24 -24
  10. autobyteus/agent/message/context_file_type.py +29 -8
  11. autobyteus/agent/message/multimodal_message_builder.py +47 -0
  12. autobyteus/agent/streaming/stream_event_payloads.py +23 -4
  13. autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +6 -2
  14. autobyteus/agent/tool_invocation.py +27 -2
  15. autobyteus/agent_team/agent_team_builder.py +22 -1
  16. autobyteus/agent_team/bootstrap_steps/agent_configuration_preparation_step.py +9 -2
  17. autobyteus/agent_team/context/agent_team_config.py +1 -0
  18. autobyteus/agent_team/context/agent_team_runtime_state.py +0 -2
  19. autobyteus/llm/api/autobyteus_llm.py +33 -33
  20. autobyteus/llm/api/bedrock_llm.py +13 -5
  21. autobyteus/llm/api/claude_llm.py +13 -27
  22. autobyteus/llm/api/gemini_llm.py +108 -42
  23. autobyteus/llm/api/groq_llm.py +4 -3
  24. autobyteus/llm/api/mistral_llm.py +97 -51
  25. autobyteus/llm/api/nvidia_llm.py +6 -5
  26. autobyteus/llm/api/ollama_llm.py +37 -12
  27. autobyteus/llm/api/openai_compatible_llm.py +91 -91
  28. autobyteus/llm/autobyteus_provider.py +1 -1
  29. autobyteus/llm/base_llm.py +42 -139
  30. autobyteus/llm/extensions/base_extension.py +6 -6
  31. autobyteus/llm/extensions/token_usage_tracking_extension.py +3 -2
  32. autobyteus/llm/llm_factory.py +131 -61
  33. autobyteus/llm/ollama_provider_resolver.py +1 -0
  34. autobyteus/llm/providers.py +1 -0
  35. autobyteus/llm/token_counter/token_counter_factory.py +3 -1
  36. autobyteus/llm/user_message.py +43 -35
  37. autobyteus/llm/utils/llm_config.py +34 -18
  38. autobyteus/llm/utils/media_payload_formatter.py +99 -0
  39. autobyteus/llm/utils/messages.py +32 -25
  40. autobyteus/llm/utils/response_types.py +9 -3
  41. autobyteus/llm/utils/token_usage.py +6 -5
  42. autobyteus/multimedia/__init__.py +31 -0
  43. autobyteus/multimedia/audio/__init__.py +11 -0
  44. autobyteus/multimedia/audio/api/__init__.py +4 -0
  45. autobyteus/multimedia/audio/api/autobyteus_audio_client.py +59 -0
  46. autobyteus/multimedia/audio/api/gemini_audio_client.py +219 -0
  47. autobyteus/multimedia/audio/audio_client_factory.py +120 -0
  48. autobyteus/multimedia/audio/audio_model.py +97 -0
  49. autobyteus/multimedia/audio/autobyteus_audio_provider.py +108 -0
  50. autobyteus/multimedia/audio/base_audio_client.py +40 -0
  51. autobyteus/multimedia/image/__init__.py +11 -0
  52. autobyteus/multimedia/image/api/__init__.py +9 -0
  53. autobyteus/multimedia/image/api/autobyteus_image_client.py +97 -0
  54. autobyteus/multimedia/image/api/gemini_image_client.py +188 -0
  55. autobyteus/multimedia/image/api/openai_image_client.py +142 -0
  56. autobyteus/multimedia/image/autobyteus_image_provider.py +109 -0
  57. autobyteus/multimedia/image/base_image_client.py +67 -0
  58. autobyteus/multimedia/image/image_client_factory.py +118 -0
  59. autobyteus/multimedia/image/image_model.py +97 -0
  60. autobyteus/multimedia/providers.py +5 -0
  61. autobyteus/multimedia/runtimes.py +8 -0
  62. autobyteus/multimedia/utils/__init__.py +10 -0
  63. autobyteus/multimedia/utils/api_utils.py +19 -0
  64. autobyteus/multimedia/utils/multimedia_config.py +29 -0
  65. autobyteus/multimedia/utils/response_types.py +13 -0
  66. autobyteus/task_management/tools/publish_task_plan.py +4 -16
  67. autobyteus/task_management/tools/update_task_status.py +4 -19
  68. autobyteus/tools/__init__.py +5 -4
  69. autobyteus/tools/base_tool.py +98 -29
  70. autobyteus/tools/browser/standalone/__init__.py +0 -1
  71. autobyteus/tools/google_search.py +149 -0
  72. autobyteus/tools/mcp/schema_mapper.py +29 -71
  73. autobyteus/tools/multimedia/__init__.py +8 -0
  74. autobyteus/tools/multimedia/audio_tools.py +116 -0
  75. autobyteus/tools/multimedia/image_tools.py +186 -0
  76. autobyteus/tools/parameter_schema.py +82 -89
  77. autobyteus/tools/pydantic_schema_converter.py +81 -0
  78. autobyteus/tools/tool_category.py +1 -0
  79. autobyteus/tools/usage/formatters/default_json_example_formatter.py +89 -20
  80. autobyteus/tools/usage/formatters/default_xml_example_formatter.py +115 -41
  81. autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +50 -20
  82. autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +55 -22
  83. autobyteus/tools/usage/formatters/google_json_example_formatter.py +54 -21
  84. autobyteus/tools/usage/formatters/openai_json_example_formatter.py +53 -23
  85. autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +270 -94
  86. autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +5 -2
  87. autobyteus/tools/usage/providers/tool_manifest_provider.py +43 -16
  88. autobyteus/tools/usage/registries/tool_formatting_registry.py +9 -2
  89. autobyteus/tools/usage/registries/tool_usage_parser_registry.py +9 -2
  90. autobyteus-1.1.7.dist-info/METADATA +204 -0
  91. {autobyteus-1.1.5.dist-info → autobyteus-1.1.7.dist-info}/RECORD +98 -71
  92. examples/run_browser_agent.py +1 -1
  93. examples/run_google_slides_agent.py +2 -2
  94. examples/run_mcp_google_slides_client.py +1 -1
  95. examples/run_sqlite_agent.py +1 -1
  96. autobyteus/llm/utils/image_payload_formatter.py +0 -89
  97. autobyteus/tools/ask_user_input.py +0 -40
  98. autobyteus/tools/browser/standalone/factory/google_search_factory.py +0 -25
  99. autobyteus/tools/browser/standalone/google_search_ui.py +0 -126
  100. autobyteus-1.1.5.dist-info/METADATA +0 -161
  101. {autobyteus-1.1.5.dist-info → autobyteus-1.1.7.dist-info}/WHEEL +0 -0
  102. {autobyteus-1.1.5.dist-info → autobyteus-1.1.7.dist-info}/licenses/LICENSE +0 -0
  103. {autobyteus-1.1.5.dist-info → autobyteus-1.1.7.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,118 @@
1
+ import logging
2
+ from typing import Dict, Optional
3
+ from autobyteus.multimedia.image.autobyteus_image_provider import AutobyteusImageModelProvider
4
+ from autobyteus.multimedia.image.base_image_client import BaseImageClient
5
+ from autobyteus.multimedia.image.image_model import ImageModel
6
+ from autobyteus.multimedia.providers import MultimediaProvider
7
+ from autobyteus.multimedia.image.api.openai_image_client import OpenAIImageClient
8
+ from autobyteus.multimedia.image.api.gemini_image_client import GeminiImageClient
9
+ from autobyteus.multimedia.utils.multimedia_config import MultimediaConfig
10
+ from autobyteus.utils.singleton import SingletonMeta
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ class ImageClientFactory(metaclass=SingletonMeta):
15
+ """
16
+ A factory for creating instances of image generation clients based on registered ImageModels.
17
+ """
18
+ _models_by_identifier: Dict[str, ImageModel] = {}
19
+ _initialized = False
20
+
21
+ @staticmethod
22
+ def ensure_initialized():
23
+ """Ensures the factory is initialized before use."""
24
+ if not ImageClientFactory._initialized:
25
+ ImageClientFactory._initialize_registry()
26
+ ImageClientFactory._initialized = True
27
+
28
+ @staticmethod
29
+ def reinitialize():
30
+ """Reinitializes the model registry, clearing all models and re-discovering them."""
31
+ logger.info("Reinitializing Image model registry...")
32
+ ImageClientFactory._initialized = False
33
+ ImageClientFactory._models_by_identifier.clear()
34
+ ImageClientFactory.ensure_initialized()
35
+ logger.info("Image model registry reinitialized successfully.")
36
+
37
+ @staticmethod
38
+ def _initialize_registry():
39
+ """Initializes the registry with built-in image models and discovers remote ones."""
40
+
41
+ # OpenAI Models
42
+ gpt_image_1_model = ImageModel(
43
+ name="gpt-image-1",
44
+ value="dall-e-3",
45
+ provider=MultimediaProvider.OPENAI,
46
+ client_class=OpenAIImageClient,
47
+ parameter_schema={
48
+ "n": {"type": "integer", "default": 1, "allowed_values": [1], "description": "The number of images to generate."},
49
+ "size": {"type": "string", "default": "1024x1024", "allowed_values": ["1024x1024", "1792x1024", "1024x1792"], "description": "The size of the generated images."},
50
+ "quality": {"type": "string", "default": "hd", "allowed_values": ["standard", "hd"], "description": "The quality of the image that will be generated."},
51
+ "style": {"type": "string", "default": "vivid", "allowed_values": ["vivid", "natural"], "description": "The style of the generated images."}
52
+ }
53
+ )
54
+
55
+ dall_e_2_model = ImageModel(
56
+ name="dall-e-2",
57
+ value="dall-e-2",
58
+ provider=MultimediaProvider.OPENAI,
59
+ client_class=OpenAIImageClient,
60
+ parameter_schema={
61
+ "n": {"type": "integer", "default": 1, "description": "The number of images to generate."},
62
+ "size": {"type": "string", "default": "1024x1024", "allowed_values": ["256x256", "512x512", "1024x1024"], "description": "The size of the generated images."}
63
+ }
64
+ )
65
+
66
+ # Google Imagen Models (via Gemini API)
67
+ imagen_model = ImageModel(
68
+ name="imagen-4",
69
+ value="imagen-4.0-generate-001",
70
+ provider=MultimediaProvider.GOOGLE,
71
+ client_class=GeminiImageClient,
72
+ parameter_schema={} # The genai library doesn't expose these as simple params
73
+ )
74
+
75
+ models_to_register = [
76
+ gpt_image_1_model,
77
+ dall_e_2_model,
78
+ imagen_model,
79
+ ]
80
+
81
+ for model in models_to_register:
82
+ ImageClientFactory.register_model(model)
83
+
84
+ logger.info("Default API-based image models registered.")
85
+
86
+ # Discover models from remote Autobyteus servers
87
+ AutobyteusImageModelProvider.discover_and_register()
88
+
89
+ @staticmethod
90
+ def register_model(model: ImageModel):
91
+ """Registers a new image model."""
92
+ identifier = model.model_identifier
93
+ if identifier in ImageClientFactory._models_by_identifier:
94
+ logger.warning(f"Image model '{identifier}' is already registered. Overwriting.")
95
+
96
+ if not isinstance(model.provider, MultimediaProvider):
97
+ try:
98
+ model.provider = MultimediaProvider(model.provider)
99
+ except ValueError:
100
+ logger.error(f"Cannot register model '{identifier}' with unknown provider '{model.provider}'.")
101
+ return
102
+
103
+ ImageClientFactory._models_by_identifier[identifier] = model
104
+
105
+ @staticmethod
106
+ def create_image_client(model_identifier: str, config_override: Optional[MultimediaConfig] = None) -> BaseImageClient:
107
+ """Creates an instance of a registered image client for a specific model."""
108
+ ImageClientFactory.ensure_initialized()
109
+
110
+ model = ImageClientFactory._models_by_identifier.get(model_identifier)
111
+ if not model:
112
+ raise ValueError(f"No image model registered with the name '{model_identifier}'. "
113
+ f"Available models: {list(ImageClientFactory._models_by_identifier.keys())}")
114
+
115
+ logger.info(f"Creating instance of image client for model '{model_identifier}'.")
116
+ return model.create_client(config_override)
117
+
118
+ image_client_factory = ImageClientFactory()
@@ -0,0 +1,97 @@
1
+ from __future__ import annotations
2
+ import logging
3
+ from typing import TYPE_CHECKING, Type, Optional, Iterator, Dict, Any
4
+ from urllib.parse import urlparse
5
+
6
+ from autobyteus.multimedia.providers import MultimediaProvider
7
+ from autobyteus.multimedia.runtimes import MultimediaRuntime
8
+ from autobyteus.multimedia.utils.multimedia_config import MultimediaConfig
9
+
10
+ if TYPE_CHECKING:
11
+ from autobyteus.multimedia.image.base_image_client import BaseImageClient
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ class ImageModelMeta(type):
16
+ """
17
+ Metaclass for ImageModel to allow discovery and access like an Enum.
18
+ """
19
+ def __iter__(cls) -> Iterator[ImageModel]:
20
+ from autobyteus.multimedia.image.image_client_factory import ImageClientFactory
21
+ ImageClientFactory.ensure_initialized()
22
+ for model in ImageClientFactory._models_by_identifier.values():
23
+ yield model
24
+
25
+ def __getitem__(cls, name_or_identifier: str) -> ImageModel:
26
+ from autobyteus.multimedia.image.image_client_factory import ImageClientFactory
27
+ ImageClientFactory.ensure_initialized()
28
+ model = ImageClientFactory._models_by_identifier.get(name_or_identifier)
29
+ if model:
30
+ return model
31
+ available_models = list(ImageClientFactory._models_by_identifier.keys())
32
+ raise KeyError(f"Image model '{name_or_identifier}' not found. Available models: {available_models}")
33
+
34
+ def __len__(cls) -> int:
35
+ from autobyteus.multimedia.image.image_client_factory import ImageClientFactory
36
+ ImageClientFactory.ensure_initialized()
37
+ return len(ImageClientFactory._models_by_identifier)
38
+
39
+
40
+ class ImageModel(metaclass=ImageModelMeta):
41
+ """
42
+ Represents a single image model's metadata.
43
+ """
44
+ def __init__(
45
+ self,
46
+ name: str,
47
+ value: str,
48
+ provider: MultimediaProvider,
49
+ client_class: Type["BaseImageClient"],
50
+ parameter_schema: Optional[Dict[str, Any]] = None,
51
+ runtime: MultimediaRuntime = MultimediaRuntime.API,
52
+ host_url: Optional[str] = None
53
+ ):
54
+ self.name = name
55
+ self.value = value
56
+ self.provider = provider
57
+ self.client_class = client_class
58
+ self.runtime = runtime
59
+ self.host_url = host_url
60
+ self.parameter_schema = parameter_schema if parameter_schema else {}
61
+
62
+ # Automatically build default_config from the schema's default values
63
+ default_params = {
64
+ key: meta.get("default")
65
+ for key, meta in self.parameter_schema.items()
66
+ if "default" in meta
67
+ }
68
+ self.default_config = MultimediaConfig(params=default_params)
69
+
70
+ @property
71
+ def model_identifier(self) -> str:
72
+ """Returns the unique identifier for the model."""
73
+ if self.runtime == MultimediaRuntime.AUTOBYTEUS and self.host_url:
74
+ try:
75
+ host = urlparse(self.host_url).hostname
76
+ return f"{self.name}@{host}"
77
+ except Exception:
78
+ return f"{self.name}@{self.host_url}" # Fallback
79
+ return self.name
80
+
81
+ def create_client(self, config_override: Optional[MultimediaConfig] = None) -> "BaseImageClient":
82
+ """
83
+ Instantiates the client class for this model.
84
+ """
85
+ config_to_use = self.default_config
86
+ if config_override:
87
+ from copy import deepcopy
88
+ config_to_use = deepcopy(self.default_config)
89
+ config_to_use.merge_with(config_override)
90
+
91
+ return self.client_class(model=self, config=config_to_use)
92
+
93
+ def __repr__(self):
94
+ return (
95
+ f"ImageModel(identifier='{self.model_identifier}', "
96
+ f"provider='{self.provider.name}', runtime='{self.runtime.value}')"
97
+ )
@@ -0,0 +1,5 @@
1
+ from enum import Enum
2
+
3
+ class MultimediaProvider(Enum):
4
+ OPENAI = "OPENAI"
5
+ GOOGLE = "GOOGLE"
@@ -0,0 +1,8 @@
1
+ from enum import Enum
2
+
3
+ class MultimediaRuntime(Enum):
4
+ """
5
+ Specifies the execution environment for a multimedia model.
6
+ """
7
+ API = "api"
8
+ AUTOBYTEUS = "autobyteus"
@@ -0,0 +1,10 @@
1
+ from .multimedia_config import MultimediaConfig
2
+ from .response_types import ImageGenerationResponse, SpeechGenerationResponse
3
+ from .api_utils import load_image_from_url
4
+
5
+ __all__ = [
6
+ "MultimediaConfig",
7
+ "ImageGenerationResponse",
8
+ "SpeechGenerationResponse",
9
+ "load_image_from_url",
10
+ ]
@@ -0,0 +1,19 @@
1
+ import logging
2
+ from PIL import Image
3
+ import requests
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+ def load_image_from_url(url: str) -> Image.Image:
8
+ """Loads an image from a URL (http, https, or file path)."""
9
+ try:
10
+ if url.startswith(('http://', 'https://')):
11
+ response = requests.get(url, stream=True)
12
+ response.raise_for_status()
13
+ return Image.open(response.raw)
14
+ else:
15
+ # Assume it's a local file path
16
+ return Image.open(url)
17
+ except Exception as e:
18
+ logger.error(f"Failed to load image from URL/path '{url}': {e}")
19
+ raise
@@ -0,0 +1,29 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Optional, Dict, Any
3
+
4
+ @dataclass
5
+ class MultimediaConfig:
6
+ """
7
+ Configuration for multimedia generation, using a flexible dictionary for parameters.
8
+ """
9
+ params: Dict[str, Any] = field(default_factory=dict)
10
+
11
+ def merge_with(self, override_config: Optional['MultimediaConfig']):
12
+ """
13
+ Merges parameters from an override config into this one.
14
+ """
15
+ if override_config and override_config.params:
16
+ self.params.update(override_config.params)
17
+
18
+ @classmethod
19
+ def from_dict(cls, data: Dict[str, Any]) -> 'MultimediaConfig':
20
+ """
21
+ Creates a MultimediaConfig instance from a dictionary of parameters.
22
+ """
23
+ return cls(params=data if data is not None else {})
24
+
25
+ def to_dict(self) -> Dict[str, Any]:
26
+ """
27
+ Returns the configuration parameters as a dictionary.
28
+ """
29
+ return self.params
@@ -0,0 +1,13 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional, List
3
+
4
+ @dataclass
5
+ class ImageGenerationResponse:
6
+ """Response for image generation or editing."""
7
+ image_urls: List[str]
8
+ revised_prompt: Optional[str] = None
9
+
10
+ @dataclass
11
+ class SpeechGenerationResponse:
12
+ """Response for speech generation (Text-to-Speech)."""
13
+ audio_urls: List[str]
@@ -4,12 +4,11 @@ import logging
4
4
  from typing import TYPE_CHECKING, Optional, Dict, Any
5
5
 
6
6
  from pydantic import ValidationError
7
- # No longer need GenerateJsonSchema from pydantic.json_schema
8
- # from pydantic.json_schema import GenerateJsonSchema
9
7
 
10
8
  from autobyteus.tools.base_tool import BaseTool
11
9
  from autobyteus.tools.tool_category import ToolCategory
12
10
  from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
11
+ from autobyteus.tools.pydantic_schema_converter import pydantic_to_parameter_schema
13
12
  from autobyteus.task_management.schemas import TaskPlanDefinitionSchema
14
13
  from autobyteus.task_management.converters import TaskPlanConverter, TaskBoardConverter
15
14
 
@@ -24,8 +23,6 @@ class PublishTaskPlan(BaseTool):
24
23
 
25
24
  CATEGORY = ToolCategory.TASK_MANAGEMENT
26
25
 
27
- # The failing custom InlineSchemaGenerator has been removed.
28
-
29
26
  @classmethod
30
27
  def get_name(cls) -> str:
31
28
  return "PublishTaskPlan"
@@ -44,11 +41,8 @@ class PublishTaskPlan(BaseTool):
44
41
  def get_argument_schema(cls) -> Optional[ParameterSchema]:
45
42
  schema = ParameterSchema()
46
43
 
47
- # CORRECTED IMPLEMENTATION:
48
- # A direct, standard call to model_json_schema(). This generates a valid
49
- # JSON schema with $refs, which the framework handles correctly.
50
- # This completely avoids the TypeError caused by the unsupported 'ref_strategy' argument.
51
- object_json_schema = TaskPlanDefinitionSchema.model_json_schema()
44
+ # Convert the Pydantic model to our native ParameterSchema for the nested object
45
+ plan_object_schema = pydantic_to_parameter_schema(TaskPlanDefinitionSchema)
52
46
 
53
47
  schema.add_parameter(ParameterDefinition(
54
48
  name="plan",
@@ -59,7 +53,7 @@ class PublishTaskPlan(BaseTool):
59
53
  "Each task must have a unique name within the plan."
60
54
  ),
61
55
  required=True,
62
- object_schema=object_json_schema
56
+ object_schema=plan_object_schema
63
57
  ))
64
58
  return schema
65
59
 
@@ -83,12 +77,8 @@ class PublishTaskPlan(BaseTool):
83
77
  return error_msg
84
78
 
85
79
  try:
86
- # Step 1: The input is now a dictionary, so we can directly validate it.
87
80
  plan_definition_schema = TaskPlanDefinitionSchema(**plan)
88
-
89
- # Step 2: Use the dedicated converter to create the internal TaskPlan object.
90
81
  final_plan = TaskPlanConverter.from_schema(plan_definition_schema)
91
-
92
82
  except (ValidationError, ValueError) as e:
93
83
  error_msg = f"Invalid or inconsistent task plan provided: {e}"
94
84
  logger.warning(f"Agent '{context.agent_id}' provided an invalid plan for PublishTaskPlan: {error_msg}")
@@ -100,12 +90,10 @@ class PublishTaskPlan(BaseTool):
100
90
 
101
91
  if task_board.load_task_plan(final_plan):
102
92
  logger.info(f"Agent '{context.agent_id}': Task plan published successfully. Returning new board status.")
103
- # Convert the new state of the board back to an LLM-friendly schema and return it.
104
93
  status_report_schema = TaskBoardConverter.to_schema(task_board)
105
94
  if status_report_schema:
106
95
  return status_report_schema.model_dump_json(indent=2)
107
96
  else:
108
- # This is a fallback case, shouldn't happen right after a successful load.
109
97
  return "Task plan published successfully, but could not generate status report."
110
98
  else:
111
99
  error_msg = "Failed to load task plan onto the board. This can happen if the board implementation rejects the plan."
@@ -6,6 +6,7 @@ from pydantic import ValidationError
6
6
  from autobyteus.tools.base_tool import BaseTool
7
7
  from autobyteus.tools.tool_category import ToolCategory
8
8
  from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
9
+ from autobyteus.tools.pydantic_schema_converter import pydantic_to_parameter_schema
9
10
  from autobyteus.task_management.base_task_board import TaskStatus
10
11
  from autobyteus.task_management.deliverable import FileDeliverable
11
12
  from autobyteus.task_management.schemas import FileDeliverableSchema
@@ -53,14 +54,11 @@ class UpdateTaskStatus(BaseTool):
53
54
  param_type=ParameterType.ARRAY,
54
55
  description="Optional. A list of file deliverables to submit for this task, typically when status is 'completed'. Each deliverable must include a file_path and a summary.",
55
56
  required=False,
56
- array_item_schema=FileDeliverableSchema.model_json_schema()
57
+ array_item_schema=pydantic_to_parameter_schema(FileDeliverableSchema)
57
58
  ))
58
59
  return schema
59
60
 
60
61
  async def _execute(self, context: 'AgentContext', task_name: str, status: str, deliverables: Optional[List[Dict[str, Any]]] = None) -> str:
61
- """
62
- Executes the tool to update a task's status and optionally submit deliverables.
63
- """
64
62
  agent_name = context.config.name
65
63
  log_msg = f"Agent '{agent_name}' is executing UpdateTaskStatus for task '{task_name}' to status '{status}'"
66
64
  if deliverables:
@@ -84,12 +82,7 @@ class UpdateTaskStatus(BaseTool):
84
82
  logger.warning(f"Agent '{agent_name}' tried to update task status, but no plan is loaded.")
85
83
  return error_msg
86
84
 
87
- # Find the task by name
88
- target_task = None
89
- for task in task_board.current_plan.tasks:
90
- if task.task_name == task_name:
91
- target_task = task
92
- break
85
+ target_task = next((t for t in task_board.current_plan.tasks if t.task_name == task_name), None)
93
86
 
94
87
  if not target_task:
95
88
  error_msg = f"Failed to update status for task '{task_name}'. The task name does not exist on the current plan."
@@ -103,17 +96,11 @@ class UpdateTaskStatus(BaseTool):
103
96
  logger.warning(f"Agent '{agent_name}' provided invalid status for UpdateTaskStatus: {status}")
104
97
  return f"Error: {error_msg}"
105
98
 
106
- # --- Process Deliverables FIRST --- (CORRECTED ORDER)
107
99
  if deliverables:
108
100
  try:
109
101
  for d_data in deliverables:
110
- # Validate and create the internal deliverable object
111
102
  deliverable_schema = FileDeliverableSchema(**d_data)
112
- full_deliverable = FileDeliverable(
113
- **deliverable_schema.model_dump(),
114
- author_agent_name=agent_name
115
- )
116
- # Append to the task object
103
+ full_deliverable = FileDeliverable(**deliverable_schema.model_dump(), author_agent_name=agent_name)
117
104
  target_task.file_deliverables.append(full_deliverable)
118
105
  logger.info(f"Agent '{agent_name}' successfully processed and added {len(deliverables)} deliverables to task '{task_name}'.")
119
106
  except (ValidationError, TypeError) as e:
@@ -121,8 +108,6 @@ class UpdateTaskStatus(BaseTool):
121
108
  logger.warning(f"Agent '{agent_name}': {error_msg}")
122
109
  return f"Error: {error_msg}"
123
110
 
124
- # --- Update Status SECOND --- (CORRECTED ORDER)
125
- # This will now emit an event with the deliverables already attached to the task.
126
111
  if not task_board.update_task_status(target_task.task_id, status_enum, agent_name):
127
112
  error_msg = f"Failed to update status for task '{task_name}'. An unexpected error occurred on the task board."
128
113
  logger.error(f"Agent '{agent_name}': {error_msg}")
@@ -16,18 +16,18 @@ from .tool_category import ToolCategory
16
16
  # --- Re-export specific tools for easier access ---
17
17
 
18
18
  # Functional tools (decorated functions are now instances)
19
- from .ask_user_input import ask_user_input
20
19
  from .pdf_downloader import pdf_downloader
21
20
  from .bash.bash_executor import bash_executor
22
21
  from .file.file_reader import file_reader
23
22
  from .file.file_writer import file_writer
24
23
 
25
24
  # General Class-based tools
25
+ from .google_search import GoogleSearch
26
26
  from .image_downloader import ImageDownloader
27
27
  from .timer import Timer
28
+ from .multimedia.image_tools import GenerateImageTool, EditImageTool
28
29
 
29
30
  # Standalone Browser tools
30
- from .browser.standalone.google_search_ui import GoogleSearch
31
31
  from .browser.standalone.navigate_to import NavigateTo as StandaloneNavigateTo # Alias to avoid name clash
32
32
  from .browser.standalone.webpage_reader import WebPageReader as StandaloneWebPageReader # Alias
33
33
  from .browser.standalone.webpage_screenshot_taker import WebPageScreenshotTaker as StandaloneWebPageScreenshotTaker # Alias
@@ -53,18 +53,19 @@ __all__ = [
53
53
  "ToolCategory",
54
54
 
55
55
  # Re-exported functional tool instances
56
- "ask_user_input",
57
56
  "pdf_downloader",
58
57
  "bash_executor",
59
58
  "file_reader",
60
59
  "file_writer",
61
60
 
62
61
  # Re-exported general class-based tools
62
+ "GoogleSearch",
63
63
  "ImageDownloader",
64
64
  "Timer",
65
+ "GenerateImageTool",
66
+ "EditImageTool",
65
67
 
66
68
  # Re-exported Standalone Browser tools
67
- "GoogleSearch",
68
69
  "StandaloneNavigateTo",
69
70
  "StandaloneWebPageReader",
70
71
  "StandaloneWebPageScreenshotTaker",