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.
- autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +6 -2
- autobyteus/agent/handlers/inter_agent_message_event_handler.py +17 -19
- autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +6 -3
- autobyteus/agent/handlers/tool_result_event_handler.py +61 -18
- autobyteus/agent/handlers/user_input_message_event_handler.py +19 -10
- autobyteus/agent/hooks/base_phase_hook.py +17 -0
- autobyteus/agent/hooks/hook_registry.py +15 -27
- autobyteus/agent/input_processor/base_user_input_processor.py +17 -1
- autobyteus/agent/input_processor/processor_registry.py +15 -27
- autobyteus/agent/llm_response_processor/base_processor.py +17 -1
- autobyteus/agent/llm_response_processor/processor_registry.py +15 -24
- autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +14 -0
- autobyteus/agent/message/agent_input_user_message.py +15 -2
- autobyteus/agent/message/send_message_to.py +1 -1
- autobyteus/agent/processor_option.py +17 -0
- autobyteus/agent/sender_type.py +1 -0
- autobyteus/agent/system_prompt_processor/base_processor.py +17 -1
- autobyteus/agent/system_prompt_processor/processor_registry.py +15 -27
- autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +10 -0
- autobyteus/agent/tool_execution_result_processor/base_processor.py +17 -1
- autobyteus/agent/tool_execution_result_processor/processor_registry.py +15 -1
- autobyteus/agent/workspace/base_workspace.py +1 -1
- autobyteus/agent/workspace/workspace_definition.py +1 -1
- autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +1 -1
- autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +2 -2
- autobyteus/agent_team/task_notification/__init__.py +4 -0
- autobyteus/agent_team/task_notification/activation_policy.py +70 -0
- autobyteus/agent_team/task_notification/system_event_driven_agent_task_notifier.py +56 -122
- autobyteus/agent_team/task_notification/task_activator.py +66 -0
- autobyteus/cli/agent_team_tui/state.py +17 -20
- autobyteus/cli/agent_team_tui/widgets/focus_pane.py +1 -1
- autobyteus/cli/agent_team_tui/widgets/task_board_panel.py +1 -1
- autobyteus/events/event_types.py +2 -2
- autobyteus/llm/api/gemini_llm.py +45 -54
- autobyteus/llm/api/qwen_llm.py +25 -0
- autobyteus/llm/autobyteus_provider.py +8 -2
- autobyteus/llm/llm_factory.py +16 -0
- autobyteus/multimedia/audio/api/autobyteus_audio_client.py +4 -1
- autobyteus/multimedia/audio/api/gemini_audio_client.py +84 -153
- autobyteus/multimedia/audio/audio_client_factory.py +47 -22
- autobyteus/multimedia/audio/audio_model.py +13 -6
- autobyteus/multimedia/audio/autobyteus_audio_provider.py +8 -2
- autobyteus/multimedia/audio/base_audio_client.py +3 -1
- autobyteus/multimedia/image/api/autobyteus_image_client.py +12 -5
- autobyteus/multimedia/image/api/gemini_image_client.py +72 -130
- autobyteus/multimedia/image/api/openai_image_client.py +4 -2
- autobyteus/multimedia/image/autobyteus_image_provider.py +8 -2
- autobyteus/multimedia/image/base_image_client.py +6 -2
- autobyteus/multimedia/image/image_client_factory.py +20 -19
- autobyteus/multimedia/image/image_model.py +13 -6
- autobyteus/multimedia/providers.py +1 -0
- autobyteus/task_management/__init__.py +9 -10
- autobyteus/task_management/base_task_board.py +14 -6
- autobyteus/task_management/converters/__init__.py +0 -2
- autobyteus/task_management/converters/task_board_converter.py +7 -16
- autobyteus/task_management/events.py +6 -6
- autobyteus/task_management/in_memory_task_board.py +48 -38
- autobyteus/task_management/schemas/__init__.py +2 -2
- autobyteus/task_management/schemas/{plan_definition.py → task_definition.py} +5 -6
- autobyteus/task_management/schemas/task_status_report.py +0 -1
- autobyteus/task_management/task.py +60 -0
- autobyteus/task_management/tools/__init__.py +4 -2
- autobyteus/task_management/tools/get_my_tasks.py +80 -0
- autobyteus/task_management/tools/get_task_board_status.py +3 -3
- autobyteus/task_management/tools/publish_task.py +77 -0
- autobyteus/task_management/tools/publish_tasks.py +74 -0
- autobyteus/task_management/tools/update_task_status.py +5 -5
- autobyteus/tools/__init__.py +3 -1
- autobyteus/tools/base_tool.py +4 -4
- autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +1 -1
- autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +1 -1
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +1 -1
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +1 -1
- autobyteus/tools/browser/standalone/navigate_to.py +1 -1
- autobyteus/tools/browser/standalone/web_page_pdf_generator.py +1 -1
- autobyteus/tools/browser/standalone/webpage_image_downloader.py +1 -1
- autobyteus/tools/browser/standalone/webpage_reader.py +1 -1
- autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +1 -1
- autobyteus/tools/functional_tool.py +1 -1
- autobyteus/tools/google_search.py +1 -1
- autobyteus/tools/image_downloader.py +1 -1
- autobyteus/tools/mcp/factory.py +1 -1
- autobyteus/tools/mcp/schema_mapper.py +1 -1
- autobyteus/tools/mcp/tool.py +1 -1
- autobyteus/tools/multimedia/__init__.py +2 -0
- autobyteus/tools/multimedia/audio_tools.py +10 -20
- autobyteus/tools/multimedia/image_tools.py +21 -22
- autobyteus/tools/multimedia/media_reader_tool.py +117 -0
- autobyteus/tools/pydantic_schema_converter.py +1 -1
- autobyteus/tools/registry/tool_definition.py +1 -1
- autobyteus/tools/timer.py +1 -1
- autobyteus/tools/tool_meta.py +1 -1
- autobyteus/tools/usage/formatters/default_json_example_formatter.py +1 -1
- autobyteus/tools/usage/formatters/default_xml_example_formatter.py +1 -1
- autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +59 -3
- autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +1 -1
- autobyteus/tools/usage/formatters/google_json_example_formatter.py +1 -1
- autobyteus/tools/usage/formatters/openai_json_example_formatter.py +1 -1
- autobyteus/{tools → utils}/parameter_schema.py +1 -1
- {autobyteus-1.1.8.dist-info → autobyteus-1.1.9.dist-info}/METADATA +2 -2
- {autobyteus-1.1.8.dist-info → autobyteus-1.1.9.dist-info}/RECORD +105 -99
- examples/run_poem_writer.py +1 -1
- autobyteus/task_management/converters/task_plan_converter.py +0 -48
- autobyteus/task_management/task_plan.py +0 -110
- autobyteus/task_management/tools/publish_task_plan.py +0 -101
- {autobyteus-1.1.8.dist-info → autobyteus-1.1.9.dist-info}/WHEEL +0 -0
- {autobyteus-1.1.8.dist-info → autobyteus-1.1.9.dist-info}/licenses/LICENSE +0 -0
- {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.
|
|
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
|
|
18
|
-
"""
|
|
19
|
-
|
|
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 .
|
|
11
|
+
from .task import Task
|
|
12
12
|
from .base_task_board import BaseTaskBoard, TaskStatus
|
|
13
|
-
from .events import
|
|
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
|
|
31
|
+
def add_tasks(self, tasks: List[Task]) -> bool:
|
|
34
32
|
"""
|
|
35
|
-
|
|
33
|
+
Adds new tasks to the board. This is an additive-only operation.
|
|
36
34
|
"""
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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.
|
|
42
|
-
|
|
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
|
-
|
|
48
|
-
event_payload = TaskPlanPublishedEvent(
|
|
43
|
+
event_payload = TasksAddedEvent(
|
|
49
44
|
team_id=self.team_id,
|
|
50
|
-
|
|
51
|
-
plan=plan
|
|
45
|
+
tasks=tasks,
|
|
52
46
|
)
|
|
53
|
-
self.emit(EventType.
|
|
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.
|
|
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 .
|
|
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
|
-
"
|
|
10
|
+
"TasksDefinitionSchema",
|
|
11
11
|
"TaskDefinitionSchema",
|
|
12
12
|
"TaskStatusReportSchema",
|
|
13
13
|
"TaskStatusReportItemSchema",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Defines the Pydantic models for task
|
|
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
|
|
23
|
-
"""A Pydantic model representing a
|
|
24
|
-
|
|
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
|
|
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 .
|
|
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
|
-
"
|
|
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
|
|
29
|
-
"
|
|
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
|
|
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.
|
|
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.
|
|
81
|
-
error_msg = "Error: No
|
|
82
|
-
logger.warning(f"Agent '{agent_name}' tried to update task status, but
|
|
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.
|
|
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."
|
autobyteus/tools/__init__.py
CHANGED
|
@@ -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",
|
autobyteus/tools/base_tool.py
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|