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,23 +5,23 @@ Defines the Pydantic models for events emitted by a TaskBoard.
5
5
  from typing import List, Optional
6
6
  from pydantic import BaseModel
7
7
 
8
- from autobyteus.task_management.task_plan import TaskPlan
8
+ from autobyteus.task_management.task import Task
9
9
  from autobyteus.task_management.base_task_board import TaskStatus
10
10
  from .deliverable import FileDeliverable
11
11
 
12
12
  class BaseTaskBoardEvent(BaseModel):
13
13
  """Base class for all task board events."""
14
14
  team_id: str
15
- plan_id: Optional[str]
16
15
 
17
- class TaskPlanPublishedEvent(BaseTaskBoardEvent):
18
- """Payload for when a new task plan is published to the board."""
19
- plan: TaskPlan
16
+ class TasksAddedEvent(BaseTaskBoardEvent):
17
+ """
18
+ Payload for when one or more tasks are added to the board.
19
+ """
20
+ tasks: List[Task]
20
21
 
21
22
  class TaskStatusUpdatedEvent(BaseTaskBoardEvent):
22
23
  """Payload for when a task's status is updated."""
23
24
  task_id: str
24
25
  new_status: TaskStatus
25
26
  agent_name: str
26
- # This field is added to ensure listeners get the full state, including deliverables.
27
27
  deliverables: Optional[List[FileDeliverable]] = None
@@ -8,9 +8,9 @@ from typing import Optional, List, Dict, Any
8
8
  from enum import Enum
9
9
 
10
10
  from autobyteus.events.event_types import EventType
11
- from .task_plan import TaskPlan, Task
11
+ from .task import Task
12
12
  from .base_task_board import BaseTaskBoard, TaskStatus
13
- from .events import TaskPlanPublishedEvent, TaskStatusUpdatedEvent
13
+ from .events import TasksAddedEvent, TaskStatusUpdatedEvent
14
14
 
15
15
  logger = logging.getLogger(__name__)
16
16
 
@@ -23,37 +23,63 @@ class InMemoryTaskBoard(BaseTaskBoard):
23
23
  """
24
24
  Initializes the InMemoryTaskBoard.
25
25
  """
26
- # BaseTaskBoard now handles EventEmitter initialization
27
26
  super().__init__(team_id=team_id)
28
- self.current_plan: Optional[TaskPlan] = None
29
27
  self.task_statuses: Dict[str, TaskStatus] = {}
30
28
  self._task_map: Dict[str, Task] = {}
31
29
  logger.info(f"InMemoryTaskBoard initialized for team '{self.team_id}'.")
32
30
 
33
- def load_task_plan(self, plan: TaskPlan) -> bool:
31
+ def add_tasks(self, tasks: List[Task]) -> bool:
34
32
  """
35
- Loads a new plan onto the board, resetting its state and emitting an event.
33
+ Adds new tasks to the board. This is an additive-only operation.
36
34
  """
37
- if not isinstance(plan, TaskPlan):
38
- logger.error(f"Team '{self.team_id}': Failed to load task plan. Provided object is not a TaskPlan.")
39
- return False
35
+ for task in tasks:
36
+ self.tasks.append(task)
37
+ self.task_statuses[task.task_id] = TaskStatus.NOT_STARTED
38
+ self._task_map[task.task_id] = task
40
39
 
41
- self.current_plan = plan
42
- self.task_statuses = {task.task_id: TaskStatus.NOT_STARTED for task in plan.tasks}
43
- self._task_map = {task.task_id: task for task in plan.tasks}
44
-
45
- logger.info(f"Team '{self.team_id}': New TaskPlan '{plan.plan_id}' loaded. Emitting event.")
40
+ self._hydrate_all_dependencies()
41
+ logger.info(f"Team '{self.team_id}': Added {len(tasks)} new task(s) to the board. Emitting TasksAddedEvent.")
46
42
 
47
- # Emit event
48
- event_payload = TaskPlanPublishedEvent(
43
+ event_payload = TasksAddedEvent(
49
44
  team_id=self.team_id,
50
- plan_id=plan.plan_id,
51
- plan=plan
45
+ tasks=tasks,
52
46
  )
53
- self.emit(EventType.TASK_BOARD_PLAN_PUBLISHED, payload=event_payload)
54
-
47
+ self.emit(EventType.TASK_BOARD_TASKS_ADDED, payload=event_payload)
55
48
  return True
56
49
 
50
+ def add_task(self, task: Task) -> bool:
51
+ """
52
+ Adds a single new task to the board by wrapping it in a list and calling add_tasks.
53
+ """
54
+ return self.add_tasks([task])
55
+
56
+ def _hydrate_all_dependencies(self):
57
+ """
58
+ Re-calculates all dependencies to ensure they are all valid task_ids.
59
+ This robustly handles dependencies that are already IDs and those that are names.
60
+ """
61
+ name_to_id_map = {task.task_name: task.task_id for task in self.tasks}
62
+ all_task_ids = set(self._task_map.keys())
63
+
64
+ for task in self.tasks:
65
+ if not task.dependencies:
66
+ continue
67
+
68
+ resolved_deps = []
69
+ for dep in task.dependencies:
70
+ # Case 1: The dependency is already a valid task_id on the board.
71
+ if dep in all_task_ids:
72
+ resolved_deps.append(dep)
73
+ # Case 2: The dependency is a task_name that can be resolved.
74
+ elif dep in name_to_id_map:
75
+ resolved_deps.append(name_to_id_map[dep])
76
+ # Case 3: The dependency is invalid.
77
+ else:
78
+ logger.warning(f"Team '{self.team_id}': Dependency '{dep}' for task '{task.task_name}' could not be resolved to a known task ID or name.")
79
+
80
+ task.dependencies = resolved_deps
81
+
82
+
57
83
  def update_task_status(self, task_id: str, status: TaskStatus, agent_name: str) -> bool:
58
84
  """
59
85
  Updates the status of a specific task and emits an event.
@@ -67,40 +93,27 @@ class InMemoryTaskBoard(BaseTaskBoard):
67
93
  log_msg = f"Team '{self.team_id}': Status of task '{task_id}' updated from '{old_status.value if isinstance(old_status, Enum) else old_status}' to '{status.value}' by agent '{agent_name}'."
68
94
  logger.info(log_msg)
69
95
 
70
- # Find the task to get its deliverables for the event payload
71
96
  task = self._task_map.get(task_id)
72
97
  task_deliverables = task.file_deliverables if task else None
73
98
 
74
- # Emit event
75
99
  event_payload = TaskStatusUpdatedEvent(
76
100
  team_id=self.team_id,
77
- plan_id=self.current_plan.plan_id if self.current_plan else None,
78
101
  task_id=task_id,
79
102
  new_status=status,
80
103
  agent_name=agent_name,
81
104
  deliverables=task_deliverables
82
105
  )
83
106
  self.emit(EventType.TASK_BOARD_STATUS_UPDATED, payload=event_payload)
84
-
85
107
  return True
86
108
 
87
109
  def get_status_overview(self) -> Dict[str, Any]:
88
110
  """
89
111
  Returns a serializable dictionary of the board's current state.
112
+ The overall_goal is now fetched from the context via the converter.
90
113
  """
91
- if not self.current_plan:
92
- return {
93
- "plan_id": None,
94
- "overall_goal": None,
95
- "task_statuses": {},
96
- "tasks": []
97
- }
98
-
99
114
  return {
100
- "plan_id": self.current_plan.plan_id,
101
- "overall_goal": self.current_plan.overall_goal,
102
115
  "task_statuses": {task_id: status.value for task_id, status in self.task_statuses.items()},
103
- "tasks": [task.model_dump() for task in self.current_plan.tasks]
116
+ "tasks": [task.model_dump() for task in self.tasks]
104
117
  }
105
118
 
106
119
  def get_next_runnable_tasks(self) -> List[Task]:
@@ -108,9 +121,6 @@ class InMemoryTaskBoard(BaseTaskBoard):
108
121
  Calculates which tasks can be executed now based on dependencies and statuses.
109
122
  """
110
123
  runnable_tasks: List[Task] = []
111
- if not self.current_plan:
112
- return runnable_tasks
113
-
114
124
  for task_id, status in self.task_statuses.items():
115
125
  if status == TaskStatus.NOT_STARTED:
116
126
  task = self._task_map.get(task_id)
@@ -2,12 +2,12 @@
2
2
  """
3
3
  Exposes the public schema models for the task management module.
4
4
  """
5
- from .plan_definition import TaskPlanDefinitionSchema, TaskDefinitionSchema
5
+ from .task_definition import TasksDefinitionSchema, TaskDefinitionSchema
6
6
  from .task_status_report import TaskStatusReportSchema, TaskStatusReportItemSchema
7
7
  from .deliverable_schema import FileDeliverableSchema
8
8
 
9
9
  __all__ = [
10
- "TaskPlanDefinitionSchema",
10
+ "TasksDefinitionSchema",
11
11
  "TaskDefinitionSchema",
12
12
  "TaskStatusReportSchema",
13
13
  "TaskStatusReportItemSchema",
@@ -1,5 +1,5 @@
1
1
  """
2
- Defines the Pydantic models for task plan "definitions".
2
+ Defines the Pydantic models for task "definitions".
3
3
 
4
4
  These models represent the exact structure that an LLM is expected to generate.
5
5
  They serve as a blueprint or definition for a plan, which the system then uses
@@ -19,14 +19,13 @@ class TaskDefinitionSchema(BaseModel):
19
19
  description="A list of 'task_name' values for tasks that must be completed first."
20
20
  )
21
21
 
22
- class TaskPlanDefinitionSchema(BaseModel):
23
- """A Pydantic model representing a full task plan as generated by an LLM."""
24
- overall_goal: str = Field(..., description="The high-level objective of the entire plan.")
25
- tasks: List[TaskDefinitionSchema] = Field(..., description="The list of tasks that make up this plan.")
22
+ class TasksDefinitionSchema(BaseModel):
23
+ """A Pydantic model representing a list of tasks as generated by an LLM."""
24
+ tasks: List[TaskDefinitionSchema] = Field(..., description="The list of tasks to be published.")
26
25
 
27
26
  @field_validator('tasks')
28
27
  def task_names_must_be_unique(cls, tasks: List[TaskDefinitionSchema]) -> List[TaskDefinitionSchema]:
29
- """Ensures that the LLM-provided task_names are unique within the plan."""
28
+ """Ensures that the LLM-provided task_names are unique within this list."""
30
29
  seen_names = set()
31
30
  for task in tasks:
32
31
  if task.task_name in seen_names:
@@ -23,5 +23,4 @@ class TaskStatusReportItemSchema(BaseModel):
23
23
 
24
24
  class TaskStatusReportSchema(BaseModel):
25
25
  """Represents a full task board status report in an LLM-friendly format."""
26
- overall_goal: str = Field(..., description="The high-level objective of the entire plan.")
27
26
  tasks: List[TaskStatusReportItemSchema] = Field(..., description="The list of tasks and their current statuses.")
@@ -0,0 +1,60 @@
1
+ # file: autobyteus/autobyteus/task_management/task.py
2
+ """
3
+ Defines the data structures for a task.
4
+ """
5
+ import logging
6
+ import uuid
7
+ from typing import List, Any
8
+ from pydantic import BaseModel, Field, model_validator
9
+
10
+ # To avoid circular import, we use a string forward reference.
11
+ from typing import TYPE_CHECKING
12
+ if TYPE_CHECKING:
13
+ from autobyteus.task_management.deliverable import FileDeliverable
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ def generate_task_id():
18
+ """Generates a unique task identifier."""
19
+ return f"task_{uuid.uuid4().hex}"
20
+
21
+ class Task(BaseModel):
22
+ """
23
+ Represents a single, discrete unit of work.
24
+ """
25
+ task_name: str = Field(..., description="A short, unique, descriptive name for this task within the plan (e.g., 'setup_project', 'implement_scraper'). Used for defining dependencies.")
26
+
27
+ task_id: str = Field(default_factory=generate_task_id, description="A unique system-generated identifier for this task within the plan.")
28
+
29
+ assignee_name: str = Field(..., description="The unique name of the agent or sub-team responsible for executing this task (e.g., 'SoftwareEngineer', 'ResearchTeam').")
30
+ description: str = Field(..., description="A clear and concise description of what this task entails.")
31
+
32
+ dependencies: List[str] = Field(
33
+ default_factory=list,
34
+ description="A list of 'task_name' values for tasks that must be completed before this one can be started."
35
+ )
36
+
37
+ # This is the updated field as per user request.
38
+ file_deliverables: List["FileDeliverable"] = Field(
39
+ default_factory=list,
40
+ description="A list of file deliverables that were produced as a result of completing this task."
41
+ )
42
+
43
+ @model_validator(mode='before')
44
+ @classmethod
45
+ def handle_local_id_compatibility(cls, data: Any) -> Any:
46
+ """Handles backward compatibility for the 'local_id' field."""
47
+ if isinstance(data, dict) and 'local_id' in data:
48
+ data['task_name'] = data.pop('local_id')
49
+ # Compatibility for old artifact field
50
+ if isinstance(data, dict) and 'produced_artifact_ids' in data:
51
+ del data['produced_artifact_ids']
52
+ return data
53
+
54
+ def model_post_init(self, __context: Any) -> None:
55
+ """Called after the model is initialized and validated."""
56
+ logger.debug(f"Task created: Name='{self.task_name}', SystemID='{self.task_id}', Assignee='{self.assignee_name}'")
57
+
58
+ # This is necessary for Pydantic v2 to correctly handle the recursive model
59
+ from autobyteus.task_management.deliverable import FileDeliverable
60
+ Task.model_rebuild()
@@ -4,11 +4,13 @@ This package contains the class-based tools related to task and project
4
4
  management within an agent team.
5
5
  """
6
6
  from .get_task_board_status import GetTaskBoardStatus
7
- from .publish_task_plan import PublishTaskPlan
7
+ from .publish_tasks import PublishTasks
8
+ from .publish_task import PublishTask
8
9
  from .update_task_status import UpdateTaskStatus
9
10
 
10
11
  __all__ = [
11
12
  "GetTaskBoardStatus",
12
- "PublishTaskPlan",
13
+ "PublishTasks",
14
+ "PublishTask",
13
15
  "UpdateTaskStatus",
14
16
  ]
@@ -0,0 +1,80 @@
1
+ # file: autobyteus/autobyteus/task_management/tools/get_my_tasks.py
2
+ import json
3
+ import logging
4
+ from typing import TYPE_CHECKING, Optional, List
5
+
6
+ from autobyteus.tools.base_tool import BaseTool
7
+ from autobyteus.tools.tool_category import ToolCategory
8
+ from autobyteus.task_management.schemas import TaskDefinitionSchema
9
+ from autobyteus.task_management.base_task_board import TaskStatus
10
+
11
+ if TYPE_CHECKING:
12
+ from autobyteus.agent.context import AgentContext
13
+ from autobyteus.agent_team.context import AgentTeamContext
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class GetMyTasks(BaseTool):
18
+ """A tool for an agent to inspect its own assigned tasks from the central TaskBoard."""
19
+
20
+ CATEGORY = ToolCategory.TASK_MANAGEMENT
21
+
22
+ @classmethod
23
+ def get_name(cls) -> str:
24
+ return "GetMyTasks"
25
+
26
+ @classmethod
27
+ def get_description(cls) -> str:
28
+ return (
29
+ "Retrieves the list of tasks currently assigned to you from the team's shared task board. "
30
+ "This is your personal to-do list. Use this to understand your current workload and decide what to do next."
31
+ )
32
+
33
+ @classmethod
34
+ def get_argument_schema(cls) -> Optional[None]:
35
+ # This tool takes no arguments.
36
+ return None
37
+
38
+ async def _execute(self, context: 'AgentContext') -> str:
39
+ """
40
+ Executes the tool by fetching tasks from the team's TaskBoard and
41
+ filtering them for the current agent.
42
+ """
43
+ agent_name = context.config.name
44
+ logger.info(f"Agent '{agent_name}' is executing GetMyTasks.")
45
+
46
+ team_context: Optional['AgentTeamContext'] = context.custom_data.get("team_context")
47
+ if not team_context:
48
+ error_msg = "Error: Team context is not available. Cannot access the task board."
49
+ logger.error(f"Agent '{agent_name}': {error_msg}")
50
+ return error_msg
51
+
52
+ task_board = getattr(team_context.state, 'task_board', None)
53
+ if not task_board:
54
+ error_msg = "Error: Task board has not been initialized for this team."
55
+ logger.error(f"Agent '{agent_name}': {error_msg}")
56
+ return error_msg
57
+
58
+ # Filter the tasks from the central board for this agent.
59
+ # An agent should only see tasks that are specifically for them and are ready to be worked on.
60
+ my_tasks = [
61
+ task for task in task_board.tasks
62
+ if task.assignee_name == agent_name and task_board.task_statuses.get(task.task_id) == TaskStatus.QUEUED
63
+ ]
64
+
65
+ if not my_tasks:
66
+ return "Your personal task queue is empty. You have no new tasks assigned and ready to be started."
67
+
68
+ try:
69
+ # Convert the internal Task objects back to the LLM-friendly schema.
70
+ tasks_for_llm = [
71
+ TaskDefinitionSchema.model_validate(task).model_dump() for task in my_tasks
72
+ ]
73
+
74
+ logger.info(f"Agent '{agent_name}' retrieved {len(tasks_for_llm)} tasks from the central task board.")
75
+ return json.dumps(tasks_for_llm, indent=2)
76
+
77
+ except Exception as e:
78
+ error_msg = f"An unexpected error occurred while formatting your tasks: {e}"
79
+ logger.error(f"Agent '{agent_name}': {error_msg}", exc_info=True)
80
+ return f"Error: {error_msg}"
@@ -25,8 +25,8 @@ class GetTaskBoardStatus(BaseTool):
25
25
  @classmethod
26
26
  def get_description(cls) -> str:
27
27
  return (
28
- "Retrieves the current status of the team's task board, including the overall goal "
29
- "and the status of all individual tasks. Returns the status as a structured, LLM-friendly JSON string."
28
+ "Retrieves the current status of the team's task board, including the status of all individual tasks. "
29
+ "Returns the status as a structured, LLM-friendly JSON string."
30
30
  )
31
31
 
32
32
  @classmethod
@@ -57,7 +57,7 @@ class GetTaskBoardStatus(BaseTool):
57
57
  status_report_schema = TaskBoardConverter.to_schema(task_board)
58
58
 
59
59
  if not status_report_schema:
60
- return "The task board is currently empty. No plan has been published."
60
+ return "The task board is currently empty. No tasks have been published."
61
61
 
62
62
  logger.info(f"Agent '{context.agent_id}' successfully retrieved and formatted task board status.")
63
63
  return status_report_schema.model_dump_json(indent=2)
@@ -0,0 +1,77 @@
1
+ # file: autobyteus/autobyteus/task_management/tools/publish_task.py
2
+ import logging
3
+ from typing import TYPE_CHECKING, Optional, Dict, Any
4
+
5
+ from pydantic import ValidationError
6
+
7
+ from autobyteus.tools.base_tool import BaseTool
8
+ from autobyteus.tools.tool_category import ToolCategory
9
+ from autobyteus.utils.parameter_schema import ParameterSchema
10
+ from autobyteus.tools.pydantic_schema_converter import pydantic_to_parameter_schema
11
+ from autobyteus.task_management.schemas import TaskDefinitionSchema
12
+ from autobyteus.task_management.task import Task
13
+
14
+ if TYPE_CHECKING:
15
+ from autobyteus.agent.context import AgentContext
16
+ from autobyteus.agent_team.context import AgentTeamContext
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+ class PublishTask(BaseTool):
21
+ """A tool for any agent to add a single new task to the team's task board."""
22
+
23
+ CATEGORY = ToolCategory.TASK_MANAGEMENT
24
+
25
+ @classmethod
26
+ def get_name(cls) -> str:
27
+ return "PublishTask"
28
+
29
+ @classmethod
30
+ def get_description(cls) -> str:
31
+ return (
32
+ "Adds a single new task to the team's shared task board. This is an additive action "
33
+ "and does not affect existing tasks. Use this to create follow-up tasks or delegate new work."
34
+ )
35
+
36
+ @classmethod
37
+ def get_argument_schema(cls) -> Optional[ParameterSchema]:
38
+ # The schema for this tool is effectively the schema of a single task definition.
39
+ return pydantic_to_parameter_schema(TaskDefinitionSchema)
40
+
41
+ async def _execute(self, context: 'AgentContext', **kwargs: Any) -> str:
42
+ """
43
+ Executes the tool by validating the task object and adding it to the board.
44
+ """
45
+ agent_name = context.config.name
46
+ task_name = kwargs.get("task_name", "unnamed task")
47
+ logger.info(f"Agent '{agent_name}' is executing PublishTask for task '{task_name}'.")
48
+
49
+ team_context: Optional['AgentTeamContext'] = context.custom_data.get("team_context")
50
+ if not team_context:
51
+ error_msg = "Error: Team context is not available. Cannot access the task board."
52
+ logger.error(f"Agent '{agent_name}': {error_msg}")
53
+ return error_msg
54
+
55
+ task_board = getattr(team_context.state, 'task_board', None)
56
+ if not task_board:
57
+ error_msg = "Error: Task board has not been initialized for this team."
58
+ logger.error(f"Agent '{agent_name}': {error_msg}")
59
+ return error_msg
60
+
61
+ try:
62
+ task_def_schema = TaskDefinitionSchema(**kwargs)
63
+ new_task = Task(**task_def_schema.model_dump())
64
+ except (ValidationError, ValueError) as e:
65
+ error_msg = f"Invalid task definition provided: {e}"
66
+ logger.warning(f"Agent '{agent_name}' provided an invalid definition for PublishTask: {error_msg}")
67
+ return f"Error: {error_msg}"
68
+
69
+ if task_board.add_task(new_task):
70
+ success_msg = f"Successfully published new task '{new_task.task_name}' to the task board."
71
+ logger.info(f"Agent '{agent_name}': {success_msg}")
72
+ return success_msg
73
+ else:
74
+ # This path is less likely now but kept for robustness.
75
+ error_msg = "Failed to publish task to the board for an unknown reason."
76
+ logger.error(f"Agent '{agent_name}': {error_msg}")
77
+ return f"Error: {error_msg}"
@@ -0,0 +1,74 @@
1
+ # file: autobyteus/autobyteus/task_management/tools/publish_tasks.py
2
+ import logging
3
+ from typing import TYPE_CHECKING, Optional, Dict, Any
4
+
5
+ from pydantic import ValidationError
6
+
7
+ from autobyteus.tools.base_tool import BaseTool
8
+ from autobyteus.tools.tool_category import ToolCategory
9
+ from autobyteus.utils.parameter_schema import ParameterSchema
10
+ from autobyteus.tools.pydantic_schema_converter import pydantic_to_parameter_schema
11
+ from autobyteus.task_management.schemas import TasksDefinitionSchema
12
+ from autobyteus.task_management.task import Task
13
+
14
+ if TYPE_CHECKING:
15
+ from autobyteus.agent.context import AgentContext
16
+ from autobyteus.agent_team.context import AgentTeamContext
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+ class PublishTasks(BaseTool):
21
+ """
22
+ A tool to publish multiple tasks to the task board. This is an additive-only operation.
23
+ """
24
+
25
+ CATEGORY = ToolCategory.TASK_MANAGEMENT
26
+
27
+ @classmethod
28
+ def get_name(cls) -> str:
29
+ return "PublishTasks"
30
+
31
+ @classmethod
32
+ def get_description(cls) -> str:
33
+ return (
34
+ "Adds a list of new tasks to the team's shared task board. This action is additive and "
35
+ "does not affect existing tasks or the team's overall goal."
36
+ )
37
+
38
+ @classmethod
39
+ def get_argument_schema(cls) -> Optional[ParameterSchema]:
40
+ return pydantic_to_parameter_schema(TasksDefinitionSchema)
41
+
42
+ async def _execute(self, context: 'AgentContext', **kwargs: Any) -> str:
43
+ agent_name = context.config.name
44
+ logger.info(f"Agent '{agent_name}' is executing PublishTasks.")
45
+
46
+ team_context: Optional['AgentTeamContext'] = context.custom_data.get("team_context")
47
+ if not team_context:
48
+ error_msg = "Error: Team context is not available. Cannot access the task board."
49
+ logger.error(f"Agent '{agent_name}': {error_msg}")
50
+ return error_msg
51
+
52
+ task_board = getattr(team_context.state, 'task_board', None)
53
+ if not task_board:
54
+ error_msg = "Error: Task board has not been initialized for this team."
55
+ logger.error(f"Agent '{agent_name}': {error_msg}")
56
+ return error_msg
57
+
58
+ try:
59
+ tasks_def_schema = TasksDefinitionSchema(**kwargs)
60
+ final_tasks = [Task(**task_def.model_dump()) for task_def in tasks_def_schema.tasks]
61
+ except (ValidationError, ValueError) as e:
62
+ error_msg = f"Invalid task definitions provided: {e}"
63
+ logger.warning(f"Agent '{agent_name}' provided an invalid definition for PublishTasks: {error_msg}")
64
+ return f"Error: {error_msg}"
65
+
66
+ if task_board.add_tasks(tasks=final_tasks):
67
+ success_msg = f"Successfully published {len(final_tasks)} new task(s) to the task board."
68
+ logger.info(f"Agent '{agent_name}': {success_msg}")
69
+ return success_msg
70
+ else:
71
+ # This path is less likely now but kept for robustness.
72
+ error_msg = "Failed to publish tasks to the board for an unknown reason."
73
+ logger.error(f"Agent '{agent_name}': {error_msg}")
74
+ return f"Error: {error_msg}"
@@ -5,7 +5,7 @@ from pydantic import ValidationError
5
5
 
6
6
  from autobyteus.tools.base_tool import BaseTool
7
7
  from autobyteus.tools.tool_category import ToolCategory
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.pydantic_schema_converter import pydantic_to_parameter_schema
10
10
  from autobyteus.task_management.base_task_board import TaskStatus
11
11
  from autobyteus.task_management.deliverable import FileDeliverable
@@ -77,12 +77,12 @@ class UpdateTaskStatus(BaseTool):
77
77
  logger.error(f"Agent '{agent_name}': {error_msg}")
78
78
  return error_msg
79
79
 
80
- if not task_board.current_plan:
81
- error_msg = "Error: No task plan is currently loaded on the task board."
82
- logger.warning(f"Agent '{agent_name}' tried to update task status, but no plan is loaded.")
80
+ if not task_board.tasks:
81
+ error_msg = "Error: No tasks are currently loaded on the task board."
82
+ logger.warning(f"Agent '{agent_name}' tried to update task status, but the board is empty.")
83
83
  return error_msg
84
84
 
85
- target_task = next((t for t in task_board.current_plan.tasks if t.task_name == task_name), None)
85
+ target_task = next((t for t in task_board.tasks if t.task_name == task_name), None)
86
86
 
87
87
  if not target_task:
88
88
  error_msg = f"Failed to update status for task '{task_name}'. The task name does not exist on the current plan."
@@ -8,7 +8,7 @@ It also contains implementations of various standard tools.
8
8
  # Core components for defining tools
9
9
  from .base_tool import BaseTool
10
10
  from .functional_tool import tool # The @tool decorator
11
- from .parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
11
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
12
12
  from .tool_config import ToolConfig # Configuration data object, primarily for class-based tools
13
13
  from .tool_origin import ToolOrigin
14
14
  from .tool_category import ToolCategory
@@ -26,6 +26,7 @@ from .google_search import GoogleSearch
26
26
  from .image_downloader import ImageDownloader
27
27
  from .timer import Timer
28
28
  from .multimedia.image_tools import GenerateImageTool, EditImageTool
29
+ from .multimedia.media_reader_tool import ReadMediaFile
29
30
 
30
31
  # Standalone Browser tools
31
32
  from .browser.standalone.navigate_to import NavigateTo as StandaloneNavigateTo # Alias to avoid name clash
@@ -64,6 +65,7 @@ __all__ = [
64
65
  "Timer",
65
66
  "GenerateImageTool",
66
67
  "EditImageTool",
68
+ "ReadMediaFile",
67
69
 
68
70
  # Re-exported Standalone Browser tools
69
71
  "StandaloneNavigateTo",
@@ -5,14 +5,14 @@ from abc import ABC, abstractmethod
5
5
  from typing import Optional, Any, TYPE_CHECKING, List as TypingList, Dict, Union
6
6
 
7
7
  from autobyteus.events.event_emitter import EventEmitter
8
- from autobyteus.tools.parameter_schema import ParameterType
8
+ from autobyteus.utils.parameter_schema import ParameterType
9
9
 
10
10
  from .tool_meta import ToolMeta
11
11
  from .tool_state import ToolState
12
12
 
13
13
  if TYPE_CHECKING:
14
14
  from autobyteus.agent.context import AgentContext
15
- from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition
15
+ from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition
16
16
  from autobyteus.tools.tool_config import ToolConfig
17
17
  from .tool_state import ToolState
18
18
  from autobyteus.tools.registry import ToolDefinition
@@ -90,8 +90,8 @@ class BaseTool(ABC, EventEmitter, metaclass=ToolMeta):
90
90
  if item_schema_dict and isinstance(item_schema_dict, dict) and item_schema_dict.get("type") == "object":
91
91
  # Create a temporary ParameterSchema for the item type to enable recursion.
92
92
  # This is a simplified conversion for coercion purposes only.
93
- from .parameter_schema import ParameterSchema as TempSchema
94
- from .parameter_schema import ParameterDefinition as TempDef
93
+ from autobyteus.utils.parameter_schema import ParameterSchema as TempSchema
94
+ from autobyteus.utils.parameter_schema import ParameterDefinition as TempDef
95
95
 
96
96
  item_param_schema = TempSchema()
97
97
  props = item_schema_dict.get("properties", {})
@@ -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 autobyteus.tools.browser.session_aware.browser_session_aware_tool import BrowserSessionAwareTool
8
8
  from autobyteus.tools.browser.session_aware.shared_browser_session import SharedBrowserSession
9
9
  from autobyteus.tools.browser.session_aware.web_element_action import WebElementAction
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_config import ToolConfig
12
12
  from autobyteus.tools.tool_category import ToolCategory
13
13