autobyteus 1.1.4__py3-none-any.whl → 1.1.5__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 (167) hide show
  1. autobyteus/agent/context/__init__.py +4 -2
  2. autobyteus/agent/context/agent_config.py +0 -4
  3. autobyteus/agent/context/agent_context_registry.py +73 -0
  4. autobyteus/agent/events/notifiers.py +4 -0
  5. autobyteus/agent/handlers/inter_agent_message_event_handler.py +7 -2
  6. autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +19 -19
  7. autobyteus/agent/handlers/user_input_message_event_handler.py +15 -0
  8. autobyteus/agent/message/send_message_to.py +29 -23
  9. autobyteus/agent/runtime/agent_runtime.py +10 -2
  10. autobyteus/agent/sender_type.py +15 -0
  11. autobyteus/agent/streaming/agent_event_stream.py +6 -0
  12. autobyteus/agent/streaming/stream_event_payloads.py +12 -0
  13. autobyteus/agent/streaming/stream_events.py +3 -0
  14. autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +7 -4
  15. autobyteus/agent_team/__init__.py +1 -0
  16. autobyteus/agent_team/agent_team.py +93 -0
  17. autobyteus/agent_team/agent_team_builder.py +184 -0
  18. autobyteus/agent_team/base_agent_team.py +86 -0
  19. autobyteus/agent_team/bootstrap_steps/__init__.py +24 -0
  20. autobyteus/agent_team/bootstrap_steps/agent_configuration_preparation_step.py +73 -0
  21. autobyteus/agent_team/bootstrap_steps/agent_team_bootstrapper.py +54 -0
  22. autobyteus/agent_team/bootstrap_steps/agent_team_runtime_queue_initialization_step.py +25 -0
  23. autobyteus/agent_team/bootstrap_steps/base_agent_team_bootstrap_step.py +23 -0
  24. autobyteus/agent_team/bootstrap_steps/coordinator_initialization_step.py +41 -0
  25. autobyteus/agent_team/bootstrap_steps/coordinator_prompt_preparation_step.py +85 -0
  26. autobyteus/agent_team/bootstrap_steps/task_notifier_initialization_step.py +51 -0
  27. autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +45 -0
  28. autobyteus/agent_team/context/__init__.py +17 -0
  29. autobyteus/agent_team/context/agent_team_config.py +33 -0
  30. autobyteus/agent_team/context/agent_team_context.py +61 -0
  31. autobyteus/agent_team/context/agent_team_runtime_state.py +56 -0
  32. autobyteus/agent_team/context/team_manager.py +147 -0
  33. autobyteus/agent_team/context/team_node_config.py +76 -0
  34. autobyteus/agent_team/events/__init__.py +29 -0
  35. autobyteus/agent_team/events/agent_team_event_dispatcher.py +39 -0
  36. autobyteus/agent_team/events/agent_team_events.py +53 -0
  37. autobyteus/agent_team/events/agent_team_input_event_queue_manager.py +21 -0
  38. autobyteus/agent_team/exceptions.py +8 -0
  39. autobyteus/agent_team/factory/__init__.py +9 -0
  40. autobyteus/agent_team/factory/agent_team_factory.py +99 -0
  41. autobyteus/agent_team/handlers/__init__.py +19 -0
  42. autobyteus/agent_team/handlers/agent_team_event_handler_registry.py +23 -0
  43. autobyteus/agent_team/handlers/base_agent_team_event_handler.py +16 -0
  44. autobyteus/agent_team/handlers/inter_agent_message_request_event_handler.py +61 -0
  45. autobyteus/agent_team/handlers/lifecycle_agent_team_event_handler.py +27 -0
  46. autobyteus/agent_team/handlers/process_user_message_event_handler.py +46 -0
  47. autobyteus/agent_team/handlers/tool_approval_team_event_handler.py +48 -0
  48. autobyteus/agent_team/phases/__init__.py +11 -0
  49. autobyteus/agent_team/phases/agent_team_operational_phase.py +19 -0
  50. autobyteus/agent_team/phases/agent_team_phase_manager.py +48 -0
  51. autobyteus/agent_team/runtime/__init__.py +13 -0
  52. autobyteus/agent_team/runtime/agent_team_runtime.py +82 -0
  53. autobyteus/agent_team/runtime/agent_team_worker.py +117 -0
  54. autobyteus/agent_team/shutdown_steps/__init__.py +17 -0
  55. autobyteus/agent_team/shutdown_steps/agent_team_shutdown_orchestrator.py +35 -0
  56. autobyteus/agent_team/shutdown_steps/agent_team_shutdown_step.py +42 -0
  57. autobyteus/agent_team/shutdown_steps/base_agent_team_shutdown_step.py +16 -0
  58. autobyteus/agent_team/shutdown_steps/bridge_cleanup_step.py +28 -0
  59. autobyteus/agent_team/shutdown_steps/sub_team_shutdown_step.py +41 -0
  60. autobyteus/agent_team/streaming/__init__.py +26 -0
  61. autobyteus/agent_team/streaming/agent_event_bridge.py +48 -0
  62. autobyteus/agent_team/streaming/agent_event_multiplexer.py +70 -0
  63. autobyteus/agent_team/streaming/agent_team_event_notifier.py +64 -0
  64. autobyteus/agent_team/streaming/agent_team_event_stream.py +33 -0
  65. autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +32 -0
  66. autobyteus/agent_team/streaming/agent_team_stream_events.py +56 -0
  67. autobyteus/agent_team/streaming/team_event_bridge.py +50 -0
  68. autobyteus/agent_team/task_notification/__init__.py +11 -0
  69. autobyteus/agent_team/task_notification/system_event_driven_agent_task_notifier.py +164 -0
  70. autobyteus/agent_team/task_notification/task_notification_mode.py +24 -0
  71. autobyteus/agent_team/utils/__init__.py +9 -0
  72. autobyteus/agent_team/utils/wait_for_idle.py +46 -0
  73. autobyteus/cli/agent_team_tui/__init__.py +4 -0
  74. autobyteus/cli/agent_team_tui/app.py +210 -0
  75. autobyteus/cli/agent_team_tui/state.py +180 -0
  76. autobyteus/cli/agent_team_tui/widgets/__init__.py +6 -0
  77. autobyteus/cli/agent_team_tui/widgets/agent_list_sidebar.py +149 -0
  78. autobyteus/cli/agent_team_tui/widgets/focus_pane.py +320 -0
  79. autobyteus/cli/agent_team_tui/widgets/logo.py +20 -0
  80. autobyteus/cli/agent_team_tui/widgets/renderables.py +77 -0
  81. autobyteus/cli/agent_team_tui/widgets/shared.py +60 -0
  82. autobyteus/cli/agent_team_tui/widgets/status_bar.py +14 -0
  83. autobyteus/cli/agent_team_tui/widgets/task_board_panel.py +82 -0
  84. autobyteus/events/event_types.py +7 -2
  85. autobyteus/llm/api/autobyteus_llm.py +11 -12
  86. autobyteus/llm/api/lmstudio_llm.py +10 -13
  87. autobyteus/llm/api/ollama_llm.py +8 -13
  88. autobyteus/llm/autobyteus_provider.py +73 -46
  89. autobyteus/llm/llm_factory.py +102 -140
  90. autobyteus/llm/lmstudio_provider.py +63 -48
  91. autobyteus/llm/models.py +83 -53
  92. autobyteus/llm/ollama_provider.py +69 -61
  93. autobyteus/llm/ollama_provider_resolver.py +1 -0
  94. autobyteus/llm/providers.py +13 -13
  95. autobyteus/llm/runtimes.py +11 -0
  96. autobyteus/task_management/__init__.py +43 -0
  97. autobyteus/task_management/base_task_board.py +68 -0
  98. autobyteus/task_management/converters/__init__.py +11 -0
  99. autobyteus/task_management/converters/task_board_converter.py +64 -0
  100. autobyteus/task_management/converters/task_plan_converter.py +48 -0
  101. autobyteus/task_management/deliverable.py +16 -0
  102. autobyteus/task_management/deliverables/__init__.py +8 -0
  103. autobyteus/task_management/deliverables/file_deliverable.py +15 -0
  104. autobyteus/task_management/events.py +27 -0
  105. autobyteus/task_management/in_memory_task_board.py +126 -0
  106. autobyteus/task_management/schemas/__init__.py +15 -0
  107. autobyteus/task_management/schemas/deliverable_schema.py +13 -0
  108. autobyteus/task_management/schemas/plan_definition.py +35 -0
  109. autobyteus/task_management/schemas/task_status_report.py +27 -0
  110. autobyteus/task_management/task_plan.py +110 -0
  111. autobyteus/task_management/tools/__init__.py +14 -0
  112. autobyteus/task_management/tools/get_task_board_status.py +68 -0
  113. autobyteus/task_management/tools/publish_task_plan.py +113 -0
  114. autobyteus/task_management/tools/update_task_status.py +135 -0
  115. autobyteus/tools/bash/bash_executor.py +59 -14
  116. autobyteus/tools/mcp/config_service.py +63 -58
  117. autobyteus/tools/mcp/server/http_managed_mcp_server.py +14 -2
  118. autobyteus/tools/mcp/server/stdio_managed_mcp_server.py +14 -2
  119. autobyteus/tools/mcp/server_instance_manager.py +30 -4
  120. autobyteus/tools/mcp/tool_registrar.py +103 -50
  121. autobyteus/tools/parameter_schema.py +17 -11
  122. autobyteus/tools/registry/tool_definition.py +24 -29
  123. autobyteus/tools/tool_category.py +1 -0
  124. autobyteus/tools/usage/formatters/default_json_example_formatter.py +78 -3
  125. autobyteus/tools/usage/formatters/default_xml_example_formatter.py +23 -3
  126. autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +6 -0
  127. autobyteus/tools/usage/formatters/google_json_example_formatter.py +7 -0
  128. autobyteus/tools/usage/formatters/openai_json_example_formatter.py +6 -4
  129. autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +23 -7
  130. autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +14 -25
  131. autobyteus/tools/usage/providers/__init__.py +2 -12
  132. autobyteus/tools/usage/providers/tool_manifest_provider.py +36 -29
  133. autobyteus/tools/usage/registries/__init__.py +7 -12
  134. autobyteus/tools/usage/registries/tool_formatter_pair.py +15 -0
  135. autobyteus/tools/usage/registries/tool_formatting_registry.py +58 -0
  136. autobyteus/tools/usage/registries/tool_usage_parser_registry.py +55 -0
  137. {autobyteus-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/METADATA +3 -3
  138. {autobyteus-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/RECORD +146 -72
  139. examples/agent_team/__init__.py +1 -0
  140. examples/run_browser_agent.py +17 -15
  141. examples/run_google_slides_agent.py +17 -16
  142. examples/run_poem_writer.py +22 -12
  143. examples/run_sqlite_agent.py +17 -15
  144. autobyteus/tools/mcp/call_handlers/__init__.py +0 -16
  145. autobyteus/tools/mcp/call_handlers/base_handler.py +0 -40
  146. autobyteus/tools/mcp/call_handlers/stdio_handler.py +0 -76
  147. autobyteus/tools/mcp/call_handlers/streamable_http_handler.py +0 -55
  148. autobyteus/tools/usage/providers/json_example_provider.py +0 -32
  149. autobyteus/tools/usage/providers/json_schema_provider.py +0 -35
  150. autobyteus/tools/usage/providers/json_tool_usage_parser_provider.py +0 -28
  151. autobyteus/tools/usage/providers/xml_example_provider.py +0 -28
  152. autobyteus/tools/usage/providers/xml_schema_provider.py +0 -29
  153. autobyteus/tools/usage/providers/xml_tool_usage_parser_provider.py +0 -26
  154. autobyteus/tools/usage/registries/json_example_formatter_registry.py +0 -51
  155. autobyteus/tools/usage/registries/json_schema_formatter_registry.py +0 -51
  156. autobyteus/tools/usage/registries/json_tool_usage_parser_registry.py +0 -42
  157. autobyteus/tools/usage/registries/xml_example_formatter_registry.py +0 -30
  158. autobyteus/tools/usage/registries/xml_schema_formatter_registry.py +0 -33
  159. autobyteus/tools/usage/registries/xml_tool_usage_parser_registry.py +0 -30
  160. examples/workflow/__init__.py +0 -1
  161. examples/workflow/run_basic_research_workflow.py +0 -189
  162. examples/workflow/run_code_review_workflow.py +0 -269
  163. examples/workflow/run_debate_workflow.py +0 -212
  164. examples/workflow/run_workflow_with_tui.py +0 -153
  165. {autobyteus-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/WHEEL +0 -0
  166. {autobyteus-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/licenses/LICENSE +0 -0
  167. {autobyteus-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,48 @@
1
+ """
2
+ Contains converters for translating LLM-friendly definition schemas into
3
+ internal task management objects.
4
+ """
5
+ import logging
6
+
7
+ from autobyteus.task_management.task_plan import TaskPlan, Task
8
+ from autobyteus.task_management.schemas import TaskPlanDefinitionSchema
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+ class TaskPlanConverter:
13
+ """A converter to transform a TaskPlanDefinitionSchema into a system-ready TaskPlan."""
14
+
15
+ @staticmethod
16
+ def from_schema(plan_definition_schema: TaskPlanDefinitionSchema) -> TaskPlan:
17
+ """
18
+ Converts a TaskPlanDefinitionSchema object from an LLM into a fully-hydrated,
19
+ internal TaskPlan object.
20
+
21
+ This process involves:
22
+ 1. Converting each TaskDefinitionSchema into a system Task object (which generates a unique task_id).
23
+ 2. Assembling these Tasks into a TaskPlan (which generates a unique plan_id).
24
+ 3. Hydrating the dependencies by replacing task_name references with the newly generated task_ids.
25
+
26
+ Args:
27
+ plan_definition_schema: The Pydantic model representing the LLM's output.
28
+
29
+ Returns:
30
+ A system-ready, internally consistent TaskPlan object.
31
+ """
32
+ logger.debug(f"Converting TaskPlanDefinitionSchema for goal: '{plan_definition_schema.overall_goal}'")
33
+
34
+ # Step 1: Convert "TaskDefinitionSchema" objects into final, internal Task objects.
35
+ # This automatically generates the system-level 'task_id' for each.
36
+ final_tasks = [Task(**task_def.model_dump()) for task_def in plan_definition_schema.tasks]
37
+
38
+ # Step 2: Create the final TaskPlan object. This generates the 'plan_id'.
39
+ final_plan = TaskPlan(
40
+ overall_goal=plan_definition_schema.overall_goal,
41
+ tasks=final_tasks
42
+ )
43
+
44
+ # Step 3: Hydrate dependencies: convert task_name references to system task_ids.
45
+ final_plan.hydrate_dependencies()
46
+
47
+ logger.info(f"Successfully converted TaskPlanDefinitionSchema to internal TaskPlan with ID '{final_plan.plan_id}'.")
48
+ return final_plan
@@ -0,0 +1,16 @@
1
+ # file: autobyteus/autobyteus/task_management/deliverable.py
2
+ """
3
+ Defines the core data model for a file deliverable.
4
+ """
5
+ import datetime
6
+ from pydantic import BaseModel, Field
7
+
8
+ class FileDeliverable(BaseModel):
9
+ """
10
+ Represents the full, internal record of a file deliverable once it has been
11
+ submitted and attached to a task.
12
+ """
13
+ file_path: str
14
+ summary: str
15
+ author_agent_name: str
16
+ timestamp: datetime.datetime = Field(default_factory=datetime.datetime.utcnow)
@@ -0,0 +1,8 @@
1
+ """
2
+ Exposes the public components of the deliverables module.
3
+ """
4
+ from .file_deliverable import FileDeliverable
5
+
6
+ __all__ = [
7
+ "FileDeliverable",
8
+ ]
@@ -0,0 +1,15 @@
1
+ """
2
+ Defines the data models for a file deliverable.
3
+ """
4
+ import datetime
5
+ from pydantic import BaseModel, Field
6
+
7
+ class FileDeliverable(BaseModel):
8
+ """
9
+ Represents the full, internal record of a file deliverable once it has been
10
+ submitted and attached to a task.
11
+ """
12
+ file_path: str
13
+ summary: str
14
+ author_agent_name: str
15
+ timestamp: datetime.datetime = Field(default_factory=datetime.datetime.utcnow)
@@ -0,0 +1,27 @@
1
+ # file: autobyteus/autobyteus/task_management/events.py
2
+ """
3
+ Defines the Pydantic models for events emitted by a TaskBoard.
4
+ """
5
+ from typing import List, Optional
6
+ from pydantic import BaseModel
7
+
8
+ from autobyteus.task_management.task_plan import TaskPlan
9
+ from autobyteus.task_management.base_task_board import TaskStatus
10
+ from .deliverable import FileDeliverable
11
+
12
+ class BaseTaskBoardEvent(BaseModel):
13
+ """Base class for all task board events."""
14
+ team_id: str
15
+ plan_id: Optional[str]
16
+
17
+ class TaskPlanPublishedEvent(BaseTaskBoardEvent):
18
+ """Payload for when a new task plan is published to the board."""
19
+ plan: TaskPlan
20
+
21
+ class TaskStatusUpdatedEvent(BaseTaskBoardEvent):
22
+ """Payload for when a task's status is updated."""
23
+ task_id: str
24
+ new_status: TaskStatus
25
+ agent_name: str
26
+ # This field is added to ensure listeners get the full state, including deliverables.
27
+ deliverables: Optional[List[FileDeliverable]] = None
@@ -0,0 +1,126 @@
1
+ # file: autobyteus/autobyteus/task_management/in_memory_task_board.py
2
+ """
3
+ An in-memory implementation of the BaseTaskBoard.
4
+ It tracks task statuses in a simple dictionary and emits events on state changes.
5
+ """
6
+ import logging
7
+ from typing import Optional, List, Dict, Any
8
+ from enum import Enum
9
+
10
+ from autobyteus.events.event_types import EventType
11
+ from .task_plan import TaskPlan, Task
12
+ from .base_task_board import BaseTaskBoard, TaskStatus
13
+ from .events import TaskPlanPublishedEvent, TaskStatusUpdatedEvent
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class InMemoryTaskBoard(BaseTaskBoard):
18
+ """
19
+ An in-memory, dictionary-based implementation of the TaskBoard that emits
20
+ events on state changes.
21
+ """
22
+ def __init__(self, team_id: str):
23
+ """
24
+ Initializes the InMemoryTaskBoard.
25
+ """
26
+ # BaseTaskBoard now handles EventEmitter initialization
27
+ super().__init__(team_id=team_id)
28
+ self.current_plan: Optional[TaskPlan] = None
29
+ self.task_statuses: Dict[str, TaskStatus] = {}
30
+ self._task_map: Dict[str, Task] = {}
31
+ logger.info(f"InMemoryTaskBoard initialized for team '{self.team_id}'.")
32
+
33
+ def load_task_plan(self, plan: TaskPlan) -> bool:
34
+ """
35
+ Loads a new plan onto the board, resetting its state and emitting an event.
36
+ """
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
40
+
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.")
46
+
47
+ # Emit event
48
+ event_payload = TaskPlanPublishedEvent(
49
+ team_id=self.team_id,
50
+ plan_id=plan.plan_id,
51
+ plan=plan
52
+ )
53
+ self.emit(EventType.TASK_BOARD_PLAN_PUBLISHED, payload=event_payload)
54
+
55
+ return True
56
+
57
+ def update_task_status(self, task_id: str, status: TaskStatus, agent_name: str) -> bool:
58
+ """
59
+ Updates the status of a specific task and emits an event.
60
+ """
61
+ if task_id not in self.task_statuses:
62
+ logger.warning(f"Team '{self.team_id}': Agent '{agent_name}' attempted to update status for non-existent task_id '{task_id}'.")
63
+ return False
64
+
65
+ old_status = self.task_statuses.get(task_id, "N/A")
66
+ self.task_statuses[task_id] = status
67
+ 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
+ logger.info(log_msg)
69
+
70
+ # Find the task to get its deliverables for the event payload
71
+ task = self._task_map.get(task_id)
72
+ task_deliverables = task.file_deliverables if task else None
73
+
74
+ # Emit event
75
+ event_payload = TaskStatusUpdatedEvent(
76
+ team_id=self.team_id,
77
+ plan_id=self.current_plan.plan_id if self.current_plan else None,
78
+ task_id=task_id,
79
+ new_status=status,
80
+ agent_name=agent_name,
81
+ deliverables=task_deliverables
82
+ )
83
+ self.emit(EventType.TASK_BOARD_STATUS_UPDATED, payload=event_payload)
84
+
85
+ return True
86
+
87
+ def get_status_overview(self) -> Dict[str, Any]:
88
+ """
89
+ Returns a serializable dictionary of the board's current state.
90
+ """
91
+ if not self.current_plan:
92
+ return {
93
+ "plan_id": None,
94
+ "overall_goal": None,
95
+ "task_statuses": {},
96
+ "tasks": []
97
+ }
98
+
99
+ return {
100
+ "plan_id": self.current_plan.plan_id,
101
+ "overall_goal": self.current_plan.overall_goal,
102
+ "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]
104
+ }
105
+
106
+ def get_next_runnable_tasks(self) -> List[Task]:
107
+ """
108
+ Calculates which tasks can be executed now based on dependencies and statuses.
109
+ """
110
+ runnable_tasks: List[Task] = []
111
+ if not self.current_plan:
112
+ return runnable_tasks
113
+
114
+ for task_id, status in self.task_statuses.items():
115
+ if status == TaskStatus.NOT_STARTED:
116
+ task = self._task_map.get(task_id)
117
+ if not task: continue
118
+ dependencies = task.dependencies
119
+ if not dependencies:
120
+ runnable_tasks.append(task)
121
+ continue
122
+ dependencies_met = all(self.task_statuses.get(dep_id) == TaskStatus.COMPLETED for dep_id in dependencies)
123
+ if dependencies_met:
124
+ runnable_tasks.append(task)
125
+
126
+ return runnable_tasks
@@ -0,0 +1,15 @@
1
+ # file: autobyteus/autobyteus/task_management/schemas/__init__.py
2
+ """
3
+ Exposes the public schema models for the task management module.
4
+ """
5
+ from .plan_definition import TaskPlanDefinitionSchema, TaskDefinitionSchema
6
+ from .task_status_report import TaskStatusReportSchema, TaskStatusReportItemSchema
7
+ from .deliverable_schema import FileDeliverableSchema
8
+
9
+ __all__ = [
10
+ "TaskPlanDefinitionSchema",
11
+ "TaskDefinitionSchema",
12
+ "TaskStatusReportSchema",
13
+ "TaskStatusReportItemSchema",
14
+ "FileDeliverableSchema",
15
+ ]
@@ -0,0 +1,13 @@
1
+ # file: autobyteus/autobyteus/task_management/schemas/deliverable_schema.py
2
+ """
3
+ Defines the Pydantic schema for submitting a file deliverable.
4
+ """
5
+ from pydantic import BaseModel, Field
6
+
7
+ class FileDeliverableSchema(BaseModel):
8
+ """
9
+ A Pydantic model representing the arguments for submitting a single
10
+ file deliverable. This is used as an input schema for tools.
11
+ """
12
+ file_path: str = Field(..., description="The relative path to the file being submitted.")
13
+ summary: str = Field(..., description="A summary of the work done on this file, explaining what is new or what was updated.")
@@ -0,0 +1,35 @@
1
+ """
2
+ Defines the Pydantic models for task plan "definitions".
3
+
4
+ These models represent the exact structure that an LLM is expected to generate.
5
+ They serve as a blueprint or definition for a plan, which the system then uses
6
+ to construct the final, internal TaskPlan object. They are used for input
7
+ validation and for programmatically generating a JSON schema for tool descriptions.
8
+ """
9
+ from typing import List
10
+ from pydantic import BaseModel, Field, field_validator
11
+
12
+ class TaskDefinitionSchema(BaseModel):
13
+ """A Pydantic model representing a single task as defined by an LLM."""
14
+ 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.")
15
+ assignee_name: str = Field(..., description="The name of the agent or sub-team assigned to this task.")
16
+ description: str = Field(..., description="A detailed description of the task.")
17
+ dependencies: List[str] = Field(
18
+ default_factory=list,
19
+ description="A list of 'task_name' values for tasks that must be completed first."
20
+ )
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.")
26
+
27
+ @field_validator('tasks')
28
+ 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."""
30
+ seen_names = set()
31
+ for task in tasks:
32
+ if task.task_name in seen_names:
33
+ raise ValueError(f"Duplicate task_name '{task.task_name}' found in task list. Each task_name must be unique.")
34
+ seen_names.add(task.task_name)
35
+ return tasks
@@ -0,0 +1,27 @@
1
+ # file: autobyteus/autobyteus/task_management/schemas/task_status_report.py
2
+ """
3
+ Defines the Pydantic models for LLM-friendly status reports.
4
+
5
+ These models are designed to be returned by tools to the LLM, providing a
6
+ clear and consistent structure that mirrors the input schemas (like TaskPlanDefinitionSchema)
7
+ but includes dynamic state information (like task status).
8
+ """
9
+ from typing import List, Optional
10
+ from pydantic import BaseModel, Field
11
+
12
+ from autobyteus.task_management.base_task_board import TaskStatus
13
+ from autobyteus.task_management.deliverable import FileDeliverable
14
+
15
+ class TaskStatusReportItemSchema(BaseModel):
16
+ """Represents the status of a single task in an LLM-friendly format."""
17
+ task_name: str = Field(..., description="The unique, descriptive name for this task.")
18
+ assignee_name: str = Field(..., description="The name of the agent or sub-team assigned to this task.")
19
+ description: str = Field(..., description="A detailed description of the task.")
20
+ dependencies: List[str] = Field(..., description="A list of 'task_name' values for tasks that must be completed first.")
21
+ status: TaskStatus = Field(..., description="The current status of this task.")
22
+ file_deliverables: List[FileDeliverable] = Field(default_factory=list, description="A list of files submitted as deliverables for this task.")
23
+
24
+ class TaskStatusReportSchema(BaseModel):
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
+ tasks: List[TaskStatusReportItemSchema] = Field(..., description="The list of tasks and their current statuses.")
@@ -0,0 +1,110 @@
1
+ # file: autobyteus/autobyteus/task_management/task_plan.py
2
+ """
3
+ Defines the data structures for a task plan and its constituent tasks.
4
+ These models represent the static, intended structure of a plan of action.
5
+ """
6
+ import logging
7
+ import uuid
8
+ from typing import List, Dict, Any
9
+ from pydantic import BaseModel, Field, field_validator, model_validator
10
+
11
+ # To avoid circular import, we use a string forward reference.
12
+ from typing import TYPE_CHECKING
13
+ if TYPE_CHECKING:
14
+ from autobyteus.task_management.deliverable import FileDeliverable
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ def generate_task_id():
19
+ """Generates a unique task identifier."""
20
+ return f"task_{uuid.uuid4().hex}"
21
+
22
+ def generate_plan_id():
23
+ """Generates a unique plan identifier."""
24
+ return f"plan_{uuid.uuid4().hex}"
25
+
26
+ class Task(BaseModel):
27
+ """
28
+ Represents a single, discrete unit of work within a larger TaskPlan.
29
+ """
30
+ 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.")
31
+
32
+ task_id: str = Field(default_factory=generate_task_id, description="A unique system-generated identifier for this task within the plan.")
33
+
34
+ assignee_name: str = Field(..., description="The unique name of the agent or sub-team responsible for executing this task (e.g., 'SoftwareEngineer', 'ResearchTeam').")
35
+ description: str = Field(..., description="A clear and concise description of what this task entails.")
36
+
37
+ dependencies: List[str] = Field(
38
+ default_factory=list,
39
+ description="A list of 'task_name' values for tasks that must be completed before this one can be started."
40
+ )
41
+
42
+ # This is the updated field as per user request.
43
+ file_deliverables: List["FileDeliverable"] = Field(
44
+ default_factory=list,
45
+ description="A list of file deliverables that were produced as a result of completing this task."
46
+ )
47
+
48
+ @model_validator(mode='before')
49
+ @classmethod
50
+ def handle_local_id_compatibility(cls, data: Any) -> Any:
51
+ """Handles backward compatibility for the 'local_id' field."""
52
+ if isinstance(data, dict) and 'local_id' in data:
53
+ data['task_name'] = data.pop('local_id')
54
+ # Compatibility for old artifact field
55
+ if isinstance(data, dict) and 'produced_artifact_ids' in data:
56
+ del data['produced_artifact_ids']
57
+ return data
58
+
59
+ def model_post_init(self, __context: Any) -> None:
60
+ """Called after the model is initialized and validated."""
61
+ logger.debug(f"Task created: Name='{self.task_name}', SystemID='{self.task_id}', Assignee='{self.assignee_name}'")
62
+
63
+
64
+ class TaskPlan(BaseModel):
65
+ """
66
+ Represents a complete, static plan for achieving a high-level goal.
67
+ It is composed of a list of interconnected tasks.
68
+ """
69
+ plan_id: str = Field(default_factory=generate_plan_id, description="A unique system-generated identifier for this entire plan.")
70
+
71
+ overall_goal: str = Field(..., description="The high-level objective that this plan is designed to achieve.")
72
+ tasks: List[Task] = Field(..., description="The list of tasks that make up this plan.")
73
+
74
+ @field_validator('tasks')
75
+ def task_names_must_be_unique(cls, tasks: List[Task]) -> List[Task]:
76
+ """Ensures that the LLM-provided task_names are unique within the plan."""
77
+ seen_names = set()
78
+ for task in tasks:
79
+ if task.task_name in seen_names:
80
+ raise ValueError(f"Duplicate task_name '{task.task_name}' found in task list. Each task_name must be unique within the plan.")
81
+ seen_names.add(task.task_name)
82
+ return tasks
83
+
84
+ def hydrate_dependencies(self) -> 'TaskPlan':
85
+ """
86
+ Converts the dependency list of task_names to system-generated task_ids.
87
+ This makes the plan internally consistent and ready for execution.
88
+ """
89
+ name_to_system_id_map = {task.task_name: task.task_id for task in self.tasks}
90
+
91
+ for task in self.tasks:
92
+ # Create a new list for the resolved dependency IDs
93
+ resolved_deps = []
94
+ for dep_name in task.dependencies:
95
+ if dep_name not in name_to_system_id_map:
96
+ raise ValueError(f"Task '{task.task_name}' has an invalid dependency: '{dep_name}' does not correspond to any task's name.")
97
+ resolved_deps.append(name_to_system_id_map[dep_name])
98
+ # Replace the old list of names with the new list of system_ids
99
+ task.dependencies = resolved_deps
100
+
101
+ logger.debug(f"TaskPlan '{self.plan_id}' successfully hydrated dependencies.")
102
+ return self
103
+
104
+ def model_post_init(self, __context: Any) -> None:
105
+ """Called after the model is initialized and validated."""
106
+ logger.debug(f"TaskPlan created: ID='{self.plan_id}', Tasks={len(self.tasks)}")
107
+
108
+ # This is necessary for Pydantic v2 to correctly handle the recursive model
109
+ from autobyteus.task_management.deliverable import FileDeliverable
110
+ Task.model_rebuild()
@@ -0,0 +1,14 @@
1
+ # file: autobyteus/autobyteus/task_management/tools/__init__.py
2
+ """
3
+ This package contains the class-based tools related to task and project
4
+ management within an agent team.
5
+ """
6
+ from .get_task_board_status import GetTaskBoardStatus
7
+ from .publish_task_plan import PublishTaskPlan
8
+ from .update_task_status import UpdateTaskStatus
9
+
10
+ __all__ = [
11
+ "GetTaskBoardStatus",
12
+ "PublishTaskPlan",
13
+ "UpdateTaskStatus",
14
+ ]
@@ -0,0 +1,68 @@
1
+ # file: autobyteus/autobyteus/task_management/tools/get_task_board_status.py
2
+ import json
3
+ import logging
4
+ from typing import TYPE_CHECKING, Optional
5
+
6
+ from autobyteus.tools.base_tool import BaseTool
7
+ from autobyteus.tools.tool_category import ToolCategory
8
+ from autobyteus.task_management.converters import TaskBoardConverter
9
+
10
+ if TYPE_CHECKING:
11
+ from autobyteus.agent.context import AgentContext
12
+ from autobyteus.agent_team.context import AgentTeamContext
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ class GetTaskBoardStatus(BaseTool):
17
+ """A tool for agents to get a current snapshot of the team's TaskBoard."""
18
+
19
+ CATEGORY = ToolCategory.TASK_MANAGEMENT
20
+
21
+ @classmethod
22
+ def get_name(cls) -> str:
23
+ return "GetTaskBoardStatus"
24
+
25
+ @classmethod
26
+ def get_description(cls) -> str:
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."
30
+ )
31
+
32
+ @classmethod
33
+ def get_argument_schema(cls) -> Optional[None]:
34
+ # This tool takes no arguments.
35
+ return None
36
+
37
+ async def _execute(self, context: 'AgentContext') -> str:
38
+ """
39
+ Executes the tool by fetching the task board and using a converter to
40
+ generate an LLM-friendly report.
41
+ """
42
+ logger.info(f"Agent '{context.agent_id}' is executing GetTaskBoardStatus.")
43
+
44
+ team_context: Optional['AgentTeamContext'] = context.custom_data.get("team_context")
45
+ if not team_context:
46
+ error_msg = "Error: Team context is not available to the agent. Cannot access the task board."
47
+ logger.error(f"Agent '{context.agent_id}': {error_msg}")
48
+ return error_msg
49
+
50
+ task_board = getattr(team_context.state, 'task_board', None)
51
+ if not task_board:
52
+ error_msg = "Error: Task board has not been initialized for this team."
53
+ logger.error(f"Agent '{context.agent_id}': {error_msg}")
54
+ return error_msg
55
+
56
+ try:
57
+ status_report_schema = TaskBoardConverter.to_schema(task_board)
58
+
59
+ if not status_report_schema:
60
+ return "The task board is currently empty. No plan has been published."
61
+
62
+ logger.info(f"Agent '{context.agent_id}' successfully retrieved and formatted task board status.")
63
+ return status_report_schema.model_dump_json(indent=2)
64
+
65
+ except Exception as e:
66
+ error_msg = f"An unexpected error occurred while retrieving or formatting task board status: {e}"
67
+ logger.error(f"Agent '{context.agent_id}': {error_msg}", exc_info=True)
68
+ return error_msg
@@ -0,0 +1,113 @@
1
+ # file: autobyteus/autobyteus/task_management/tools/publish_task_plan.py
2
+ import json
3
+ import logging
4
+ from typing import TYPE_CHECKING, Optional, Dict, Any
5
+
6
+ from pydantic import ValidationError
7
+ # No longer need GenerateJsonSchema from pydantic.json_schema
8
+ # from pydantic.json_schema import GenerateJsonSchema
9
+
10
+ from autobyteus.tools.base_tool import BaseTool
11
+ from autobyteus.tools.tool_category import ToolCategory
12
+ from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
13
+ from autobyteus.task_management.schemas import TaskPlanDefinitionSchema
14
+ from autobyteus.task_management.converters import TaskPlanConverter, TaskBoardConverter
15
+
16
+ if TYPE_CHECKING:
17
+ from autobyteus.agent.context import AgentContext
18
+ from autobyteus.agent_team.context import AgentTeamContext
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ class PublishTaskPlan(BaseTool):
23
+ """A tool for the coordinator to parse and load a generated plan into the TaskBoard."""
24
+
25
+ CATEGORY = ToolCategory.TASK_MANAGEMENT
26
+
27
+ # The failing custom InlineSchemaGenerator has been removed.
28
+
29
+ @classmethod
30
+ def get_name(cls) -> str:
31
+ return "PublishTaskPlan"
32
+
33
+ @classmethod
34
+ def get_description(cls) -> str:
35
+ return (
36
+ "Parses a structured object representing a complete task plan, converts it into a "
37
+ "system-ready format, and loads it onto the team's shared task board. "
38
+ "This action resets the task board with the new plan. Upon success, it returns "
39
+ "the initial status of the newly loaded task board. "
40
+ "This tool should typically only be used by the team coordinator."
41
+ )
42
+
43
+ @classmethod
44
+ def get_argument_schema(cls) -> Optional[ParameterSchema]:
45
+ schema = ParameterSchema()
46
+
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()
52
+
53
+ schema.add_parameter(ParameterDefinition(
54
+ name="plan",
55
+ param_type=ParameterType.OBJECT,
56
+ description=(
57
+ "A structured object representing a complete task plan. This object defines the overall goal "
58
+ "and a list of tasks with their assignees, descriptions, and dependencies. "
59
+ "Each task must have a unique name within the plan."
60
+ ),
61
+ required=True,
62
+ object_schema=object_json_schema
63
+ ))
64
+ return schema
65
+
66
+ async def _execute(self, context: 'AgentContext', plan: Dict[str, Any]) -> str:
67
+ """
68
+ Executes the tool by validating the plan object, using a converter to create a TaskPlan,
69
+ and loading it onto the task board.
70
+ """
71
+ logger.info(f"Agent '{context.agent_id}' is executing PublishTaskPlan.")
72
+
73
+ team_context: Optional['AgentTeamContext'] = context.custom_data.get("team_context")
74
+ if not team_context:
75
+ error_msg = "Error: Team context is not available. Cannot access the task board."
76
+ logger.error(f"Agent '{context.agent_id}': {error_msg}")
77
+ return error_msg
78
+
79
+ task_board = getattr(team_context.state, 'task_board', None)
80
+ if not task_board:
81
+ error_msg = "Error: Task board has not been initialized for this team."
82
+ logger.error(f"Agent '{context.agent_id}': {error_msg}")
83
+ return error_msg
84
+
85
+ try:
86
+ # Step 1: The input is now a dictionary, so we can directly validate it.
87
+ plan_definition_schema = TaskPlanDefinitionSchema(**plan)
88
+
89
+ # Step 2: Use the dedicated converter to create the internal TaskPlan object.
90
+ final_plan = TaskPlanConverter.from_schema(plan_definition_schema)
91
+
92
+ except (ValidationError, ValueError) as e:
93
+ error_msg = f"Invalid or inconsistent task plan provided: {e}"
94
+ logger.warning(f"Agent '{context.agent_id}' provided an invalid plan for PublishTaskPlan: {error_msg}")
95
+ return f"Error: {error_msg}"
96
+ except Exception as e:
97
+ error_msg = f"An unexpected error occurred during plan parsing or conversion: {e}"
98
+ logger.error(f"Agent '{context.agent_id}': {error_msg}", exc_info=True)
99
+ return f"Error: {error_msg}"
100
+
101
+ if task_board.load_task_plan(final_plan):
102
+ 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
+ status_report_schema = TaskBoardConverter.to_schema(task_board)
105
+ if status_report_schema:
106
+ return status_report_schema.model_dump_json(indent=2)
107
+ else:
108
+ # This is a fallback case, shouldn't happen right after a successful load.
109
+ return "Task plan published successfully, but could not generate status report."
110
+ else:
111
+ error_msg = "Failed to load task plan onto the board. This can happen if the board implementation rejects the plan."
112
+ logger.error(f"Agent '{context.agent_id}': {error_msg}")
113
+ return f"Error: {error_msg}"