autobyteus 1.1.9__py3-none-any.whl → 1.2.1__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/context/agent_runtime_state.py +4 -0
- autobyteus/agent/events/notifiers.py +5 -1
- autobyteus/agent/message/send_message_to.py +5 -4
- autobyteus/agent/streaming/agent_event_stream.py +5 -0
- autobyteus/agent/streaming/stream_event_payloads.py +25 -0
- autobyteus/agent/streaming/stream_events.py +13 -1
- autobyteus/agent_team/bootstrap_steps/task_notifier_initialization_step.py +4 -4
- autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +12 -12
- autobyteus/agent_team/context/agent_team_runtime_state.py +2 -2
- autobyteus/agent_team/streaming/agent_team_event_notifier.py +4 -4
- autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +3 -3
- autobyteus/agent_team/streaming/agent_team_stream_events.py +8 -8
- autobyteus/agent_team/task_notification/activation_policy.py +1 -1
- autobyteus/agent_team/task_notification/system_event_driven_agent_task_notifier.py +22 -22
- autobyteus/agent_team/task_notification/task_notification_mode.py +1 -1
- autobyteus/cli/agent_team_tui/app.py +4 -4
- autobyteus/cli/agent_team_tui/state.py +8 -8
- autobyteus/cli/agent_team_tui/widgets/focus_pane.py +3 -3
- autobyteus/cli/agent_team_tui/widgets/shared.py +1 -1
- autobyteus/cli/agent_team_tui/widgets/{task_board_panel.py → task_plan_panel.py} +5 -5
- autobyteus/clients/__init__.py +10 -0
- autobyteus/clients/autobyteus_client.py +318 -0
- autobyteus/clients/cert_utils.py +105 -0
- autobyteus/clients/certificates/cert.pem +34 -0
- autobyteus/events/event_types.py +4 -3
- autobyteus/llm/api/autobyteus_llm.py +1 -1
- autobyteus/llm/api/zhipu_llm.py +26 -0
- autobyteus/llm/autobyteus_provider.py +1 -1
- autobyteus/llm/llm_factory.py +23 -0
- autobyteus/llm/ollama_provider_resolver.py +1 -0
- autobyteus/llm/providers.py +1 -0
- autobyteus/llm/token_counter/token_counter_factory.py +3 -0
- autobyteus/llm/token_counter/zhipu_token_counter.py +24 -0
- autobyteus/multimedia/audio/api/__init__.py +3 -2
- autobyteus/multimedia/audio/api/autobyteus_audio_client.py +1 -1
- autobyteus/multimedia/audio/api/openai_audio_client.py +112 -0
- autobyteus/multimedia/audio/audio_client_factory.py +37 -0
- autobyteus/multimedia/audio/autobyteus_audio_provider.py +1 -1
- autobyteus/multimedia/image/api/autobyteus_image_client.py +1 -1
- autobyteus/multimedia/image/autobyteus_image_provider.py +1 -1
- autobyteus/multimedia/image/image_client_factory.py +1 -1
- autobyteus/task_management/__init__.py +44 -20
- autobyteus/task_management/{base_task_board.py → base_task_plan.py} +16 -13
- autobyteus/task_management/converters/__init__.py +2 -2
- autobyteus/task_management/converters/{task_board_converter.py → task_plan_converter.py} +13 -13
- autobyteus/task_management/events.py +7 -7
- autobyteus/task_management/{in_memory_task_board.py → in_memory_task_plan.py} +34 -22
- autobyteus/task_management/schemas/__init__.py +3 -0
- autobyteus/task_management/schemas/task_definition.py +1 -1
- autobyteus/task_management/schemas/task_status_report.py +3 -3
- autobyteus/task_management/schemas/todo_definition.py +15 -0
- autobyteus/task_management/todo.py +29 -0
- autobyteus/task_management/todo_list.py +75 -0
- autobyteus/task_management/tools/__init__.py +25 -7
- autobyteus/task_management/tools/task_tools/__init__.py +19 -0
- autobyteus/task_management/tools/task_tools/assign_task_to.py +125 -0
- autobyteus/task_management/tools/{publish_task.py → task_tools/create_task.py} +16 -18
- autobyteus/task_management/tools/{publish_tasks.py → task_tools/create_tasks.py} +19 -19
- autobyteus/task_management/tools/{get_my_tasks.py → task_tools/get_my_tasks.py} +15 -15
- autobyteus/task_management/tools/{get_task_board_status.py → task_tools/get_task_plan_status.py} +16 -16
- autobyteus/task_management/tools/{update_task_status.py → task_tools/update_task_status.py} +16 -16
- autobyteus/task_management/tools/todo_tools/__init__.py +18 -0
- autobyteus/task_management/tools/todo_tools/add_todo.py +78 -0
- autobyteus/task_management/tools/todo_tools/create_todo_list.py +79 -0
- autobyteus/task_management/tools/todo_tools/get_todo_list.py +55 -0
- autobyteus/task_management/tools/todo_tools/update_todo_status.py +85 -0
- autobyteus/tools/__init__.py +61 -21
- autobyteus/tools/bash/bash_executor.py +3 -3
- autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +5 -5
- autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +4 -4
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +3 -3
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +3 -3
- autobyteus/tools/browser/standalone/navigate_to.py +13 -9
- autobyteus/tools/browser/standalone/web_page_pdf_generator.py +9 -5
- autobyteus/tools/browser/standalone/webpage_image_downloader.py +10 -6
- autobyteus/tools/browser/standalone/webpage_reader.py +13 -9
- autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +9 -5
- autobyteus/tools/file/__init__.py +13 -0
- autobyteus/tools/file/edit_file.py +200 -0
- autobyteus/tools/file/list_directory.py +168 -0
- autobyteus/tools/file/{file_reader.py → read_file.py} +3 -3
- autobyteus/tools/file/search_files.py +188 -0
- autobyteus/tools/file/{file_writer.py → write_file.py} +3 -3
- autobyteus/tools/functional_tool.py +10 -8
- autobyteus/tools/mcp/tool.py +3 -3
- autobyteus/tools/mcp/tool_registrar.py +5 -2
- autobyteus/tools/multimedia/__init__.py +2 -1
- autobyteus/tools/multimedia/audio_tools.py +2 -2
- autobyteus/tools/multimedia/download_media_tool.py +136 -0
- autobyteus/tools/multimedia/image_tools.py +4 -4
- autobyteus/tools/multimedia/media_reader_tool.py +1 -1
- autobyteus/tools/registry/tool_definition.py +66 -13
- autobyteus/tools/registry/tool_registry.py +29 -0
- autobyteus/tools/search/__init__.py +17 -0
- autobyteus/tools/search/base_strategy.py +35 -0
- autobyteus/tools/search/client.py +24 -0
- autobyteus/tools/search/factory.py +81 -0
- autobyteus/tools/search/google_cse_strategy.py +68 -0
- autobyteus/tools/search/providers.py +10 -0
- autobyteus/tools/search/serpapi_strategy.py +65 -0
- autobyteus/tools/search/serper_strategy.py +87 -0
- autobyteus/tools/search_tool.py +83 -0
- autobyteus/tools/timer.py +4 -0
- autobyteus/tools/tool_meta.py +4 -24
- autobyteus/tools/usage/parsers/_string_decoders.py +18 -0
- autobyteus/tools/usage/parsers/default_json_tool_usage_parser.py +9 -1
- autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +15 -1
- autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +4 -1
- autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py +4 -1
- autobyteus/workflow/bootstrap_steps/coordinator_prompt_preparation_step.py +1 -2
- {autobyteus-1.1.9.dist-info → autobyteus-1.2.1.dist-info}/METADATA +7 -6
- {autobyteus-1.1.9.dist-info → autobyteus-1.2.1.dist-info}/RECORD +117 -94
- examples/run_agentic_software_engineer.py +239 -0
- examples/run_poem_writer.py +3 -3
- autobyteus/person/__init__.py +0 -0
- autobyteus/person/examples/__init__.py +0 -0
- autobyteus/person/examples/sample_persons.py +0 -14
- autobyteus/person/examples/sample_roles.py +0 -14
- autobyteus/person/person.py +0 -29
- autobyteus/person/role.py +0 -14
- autobyteus/tools/google_search.py +0 -149
- autobyteus/tools/image_downloader.py +0 -99
- autobyteus/tools/pdf_downloader.py +0 -89
- {autobyteus-1.1.9.dist-info → autobyteus-1.2.1.dist-info}/WHEEL +0 -0
- {autobyteus-1.1.9.dist-info → autobyteus-1.2.1.dist-info}/licenses/LICENSE +0 -0
- {autobyteus-1.1.9.dist-info → autobyteus-1.2.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
import uuid
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional, Dict, Any, TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from openai import OpenAI
|
|
9
|
+
|
|
10
|
+
from autobyteus.multimedia.audio.base_audio_client import BaseAudioClient
|
|
11
|
+
from autobyteus.multimedia.utils.response_types import SpeechGenerationResponse
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from autobyteus.multimedia.audio.audio_model import AudioModel
|
|
15
|
+
from autobyteus.multimedia.utils.multimedia_config import MultimediaConfig
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
_AUDIO_TEMP_DIR = Path("/tmp/autobyteus_audio")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _save_audio_bytes(audio_bytes: bytes, file_extension: Optional[str]) -> str:
|
|
23
|
+
"""Saves audio bytes to disk with a random file name."""
|
|
24
|
+
_AUDIO_TEMP_DIR.mkdir(parents=True, exist_ok=True)
|
|
25
|
+
suffix = (file_extension or "mp3").lstrip(".")
|
|
26
|
+
file_path = _AUDIO_TEMP_DIR / f"{uuid.uuid4()}.{suffix}"
|
|
27
|
+
file_path.write_bytes(audio_bytes)
|
|
28
|
+
logger.info(f"Successfully saved generated audio to {file_path}")
|
|
29
|
+
return str(file_path)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class OpenAIAudioClient(BaseAudioClient):
|
|
33
|
+
"""
|
|
34
|
+
An audio client that uses OpenAI's Text-to-Speech (Speech) API.
|
|
35
|
+
|
|
36
|
+
**Setup Requirements:**
|
|
37
|
+
1. Set the `OPENAI_API_KEY` environment variable with your OpenAI API key.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self, model: "AudioModel", config: "MultimediaConfig"):
|
|
41
|
+
super().__init__(model, config)
|
|
42
|
+
api_key = os.getenv("OPENAI_API_KEY")
|
|
43
|
+
if not api_key:
|
|
44
|
+
logger.error("OPENAI_API_KEY environment variable is not set.")
|
|
45
|
+
raise ValueError("OPENAI_API_KEY environment variable is not set.")
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
self.client = OpenAI(api_key=api_key, base_url="https://api.openai.com/v1")
|
|
49
|
+
logger.info(f"OpenAIAudioClient initialized for model '{self.model.name}'.")
|
|
50
|
+
except Exception as exc:
|
|
51
|
+
logger.error(f"Failed to configure OpenAI client: {exc}")
|
|
52
|
+
raise RuntimeError(f"Failed to configure OpenAI client: {exc}") from exc
|
|
53
|
+
|
|
54
|
+
async def generate_speech(
|
|
55
|
+
self,
|
|
56
|
+
prompt: str,
|
|
57
|
+
generation_config: Optional[Dict[str, Any]] = None,
|
|
58
|
+
**kwargs
|
|
59
|
+
) -> SpeechGenerationResponse:
|
|
60
|
+
"""
|
|
61
|
+
Generates speech using OpenAI's Speech endpoint and returns a local file path.
|
|
62
|
+
"""
|
|
63
|
+
try:
|
|
64
|
+
final_config = self.config.to_dict().copy()
|
|
65
|
+
if generation_config:
|
|
66
|
+
final_config.update(generation_config)
|
|
67
|
+
|
|
68
|
+
voice = final_config.get("voice", "alloy")
|
|
69
|
+
response_format = (
|
|
70
|
+
final_config.get("response_format")
|
|
71
|
+
or final_config.get("format")
|
|
72
|
+
or "mp3"
|
|
73
|
+
)
|
|
74
|
+
instructions = final_config.get("instructions")
|
|
75
|
+
|
|
76
|
+
logger.info(
|
|
77
|
+
"Generating speech with OpenAI TTS model '%s' using voice '%s' and format '%s'.",
|
|
78
|
+
self.model.value,
|
|
79
|
+
voice,
|
|
80
|
+
response_format,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
request_kwargs = {
|
|
84
|
+
"model": self.model.value,
|
|
85
|
+
"voice": voice,
|
|
86
|
+
"input": prompt,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if instructions:
|
|
90
|
+
request_kwargs["instructions"] = instructions
|
|
91
|
+
|
|
92
|
+
if response_format:
|
|
93
|
+
request_kwargs["response_format"] = response_format
|
|
94
|
+
|
|
95
|
+
response = await asyncio.to_thread(
|
|
96
|
+
self.client.audio.speech.create,
|
|
97
|
+
**request_kwargs,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
audio_bytes = getattr(response, "content", None)
|
|
101
|
+
if not audio_bytes:
|
|
102
|
+
raise ValueError("OpenAI Speech API returned an empty response.")
|
|
103
|
+
|
|
104
|
+
audio_path = _save_audio_bytes(audio_bytes, response_format)
|
|
105
|
+
return SpeechGenerationResponse(audio_urls=[audio_path])
|
|
106
|
+
|
|
107
|
+
except Exception as exc:
|
|
108
|
+
logger.error("Error during OpenAI speech generation: %s", exc)
|
|
109
|
+
raise ValueError(f"OpenAI speech generation failed: {exc}") from exc
|
|
110
|
+
|
|
111
|
+
async def cleanup(self):
|
|
112
|
+
logger.debug("OpenAIAudioClient cleanup called.")
|
|
@@ -5,6 +5,7 @@ from autobyteus.multimedia.audio.base_audio_client import BaseAudioClient
|
|
|
5
5
|
from autobyteus.multimedia.audio.audio_model import AudioModel
|
|
6
6
|
from autobyteus.multimedia.providers import MultimediaProvider
|
|
7
7
|
from autobyteus.multimedia.audio.api.gemini_audio_client import GeminiAudioClient
|
|
8
|
+
from autobyteus.multimedia.audio.api.openai_audio_client import OpenAIAudioClient
|
|
8
9
|
from autobyteus.multimedia.audio.autobyteus_audio_provider import AutobyteusAudioModelProvider
|
|
9
10
|
from autobyteus.multimedia.utils.multimedia_config import MultimediaConfig
|
|
10
11
|
from autobyteus.utils.singleton import SingletonMeta
|
|
@@ -20,6 +21,11 @@ GEMINI_TTS_VOICES = [
|
|
|
20
21
|
"Vindemiatrix", "Sadachbia", "Sadaltager", "Sulafat"
|
|
21
22
|
]
|
|
22
23
|
|
|
24
|
+
OPENAI_TTS_VOICES = [
|
|
25
|
+
"alloy", "ash", "ballad", "coral", "echo", "fable", "onyx",
|
|
26
|
+
"nova", "sage", "shimmer", "verse"
|
|
27
|
+
]
|
|
28
|
+
|
|
23
29
|
class AudioClientFactory(metaclass=SingletonMeta):
|
|
24
30
|
"""
|
|
25
31
|
A factory for creating instances of audio clients based on registered AudioModels.
|
|
@@ -101,7 +107,38 @@ class AudioClientFactory(metaclass=SingletonMeta):
|
|
|
101
107
|
parameter_schema=gemini_tts_schema
|
|
102
108
|
)
|
|
103
109
|
|
|
110
|
+
openai_tts_schema = ParameterSchema(parameters=[
|
|
111
|
+
ParameterDefinition(
|
|
112
|
+
name="voice",
|
|
113
|
+
param_type=ParameterType.ENUM,
|
|
114
|
+
default_value="alloy",
|
|
115
|
+
enum_values=OPENAI_TTS_VOICES,
|
|
116
|
+
description="The OpenAI TTS voice to use for generation."
|
|
117
|
+
),
|
|
118
|
+
ParameterDefinition(
|
|
119
|
+
name="format",
|
|
120
|
+
param_type=ParameterType.ENUM,
|
|
121
|
+
default_value="mp3",
|
|
122
|
+
enum_values=["mp3", "wav"],
|
|
123
|
+
description="The audio format to generate."
|
|
124
|
+
),
|
|
125
|
+
ParameterDefinition(
|
|
126
|
+
name="instructions",
|
|
127
|
+
param_type=ParameterType.STRING,
|
|
128
|
+
description="Optional delivery instructions (tone, pacing, accent, etc.)."
|
|
129
|
+
)
|
|
130
|
+
])
|
|
131
|
+
|
|
132
|
+
openai_tts_model = AudioModel(
|
|
133
|
+
name="gpt-4o-mini-tts",
|
|
134
|
+
value="gpt-4o-mini-tts",
|
|
135
|
+
provider=MultimediaProvider.OPENAI,
|
|
136
|
+
client_class=OpenAIAudioClient,
|
|
137
|
+
parameter_schema=openai_tts_schema
|
|
138
|
+
)
|
|
139
|
+
|
|
104
140
|
models_to_register = [
|
|
141
|
+
openai_tts_model,
|
|
105
142
|
gemini_tts_model,
|
|
106
143
|
]
|
|
107
144
|
|
|
@@ -3,7 +3,7 @@ from typing import List
|
|
|
3
3
|
import os
|
|
4
4
|
from urllib.parse import urlparse
|
|
5
5
|
|
|
6
|
-
from
|
|
6
|
+
from autobyteus.clients import AutobyteusClient
|
|
7
7
|
from autobyteus.multimedia.audio.api.autobyteus_audio_client import AutobyteusAudioClient
|
|
8
8
|
from autobyteus.multimedia.audio.audio_model import AudioModel
|
|
9
9
|
from autobyteus.multimedia.providers import MultimediaProvider
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from typing import Optional, List, Dict, Any, TYPE_CHECKING
|
|
3
|
-
from
|
|
3
|
+
from autobyteus.clients import AutobyteusClient
|
|
4
4
|
from autobyteus.multimedia.image.base_image_client import BaseImageClient
|
|
5
5
|
from autobyteus.multimedia.utils.response_types import ImageGenerationResponse
|
|
6
6
|
|
|
@@ -3,7 +3,7 @@ from typing import Dict, Any, List
|
|
|
3
3
|
import os
|
|
4
4
|
from urllib.parse import urlparse
|
|
5
5
|
|
|
6
|
-
from
|
|
6
|
+
from autobyteus.clients import AutobyteusClient
|
|
7
7
|
from autobyteus.multimedia.image.api.autobyteus_image_client import AutobyteusImageClient
|
|
8
8
|
from autobyteus.multimedia.image.image_model import ImageModel
|
|
9
9
|
from autobyteus.multimedia.providers import MultimediaProvider
|
|
@@ -49,7 +49,7 @@ class ImageClientFactory(metaclass=SingletonMeta):
|
|
|
49
49
|
|
|
50
50
|
gpt_image_1_model = ImageModel(
|
|
51
51
|
name="gpt-image-1",
|
|
52
|
-
value="
|
|
52
|
+
value="gpt-image-1",
|
|
53
53
|
provider=MultimediaProvider.OPENAI,
|
|
54
54
|
client_class=OpenAIImageClient,
|
|
55
55
|
parameter_schema=gpt_image_1_schema
|
|
@@ -1,23 +1,36 @@
|
|
|
1
1
|
# file: autobyteus/autobyteus/task_management/__init__.py
|
|
2
2
|
"""
|
|
3
3
|
This package defines components for task management and state tracking,
|
|
4
|
-
including task plans and live
|
|
5
|
-
module usable by various components, such as agents or agent teams.
|
|
4
|
+
including task plans and live plan execution tracking. It is designed to be a
|
|
5
|
+
general-purpose module usable by various components, such as agents or agent teams.
|
|
6
6
|
"""
|
|
7
7
|
from .task import Task
|
|
8
8
|
from .schemas import (TasksDefinitionSchema, TaskDefinitionSchema, TaskStatusReportSchema,
|
|
9
|
-
TaskStatusReportItemSchema, FileDeliverableSchema)
|
|
10
|
-
from .
|
|
11
|
-
from .
|
|
9
|
+
TaskStatusReportItemSchema, FileDeliverableSchema, ToDoDefinitionSchema, ToDosDefinitionSchema)
|
|
10
|
+
from .base_task_plan import BaseTaskPlan, TaskStatus
|
|
11
|
+
from .in_memory_task_plan import InMemoryTaskPlan
|
|
12
12
|
from .deliverable import FileDeliverable
|
|
13
|
-
from .tools import
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
from .tools import (
|
|
14
|
+
GetTaskPlanStatus,
|
|
15
|
+
CreateTasks,
|
|
16
|
+
CreateTask,
|
|
17
|
+
UpdateTaskStatus,
|
|
18
|
+
AssignTaskTo,
|
|
19
|
+
GetMyTasks,
|
|
20
|
+
CreateToDoList,
|
|
21
|
+
AddToDo,
|
|
22
|
+
GetToDoList,
|
|
23
|
+
UpdateToDoStatus as UpdateToDoStatusTool,
|
|
24
|
+
)
|
|
25
|
+
from .converters import TaskPlanConverter
|
|
26
|
+
from .events import BaseTaskPlanEvent, TasksCreatedEvent, TaskStatusUpdatedEvent
|
|
27
|
+
from .todo import ToDo, ToDoStatus
|
|
28
|
+
from .todo_list import ToDoList
|
|
16
29
|
|
|
17
|
-
# For convenience, we can alias
|
|
18
|
-
# This allows other parts of the code to import `
|
|
30
|
+
# For convenience, we can alias InMemoryTaskPlan as the default TaskPlan.
|
|
31
|
+
# This allows other parts of the code to import `TaskPlan` without needing
|
|
19
32
|
# to know the specific implementation being used by default.
|
|
20
|
-
|
|
33
|
+
TaskPlan = InMemoryTaskPlan
|
|
21
34
|
|
|
22
35
|
__all__ = [
|
|
23
36
|
"Task",
|
|
@@ -26,17 +39,28 @@ __all__ = [
|
|
|
26
39
|
"TaskStatusReportSchema",
|
|
27
40
|
"TaskStatusReportItemSchema",
|
|
28
41
|
"FileDeliverableSchema",
|
|
29
|
-
"
|
|
42
|
+
"ToDoDefinitionSchema",
|
|
43
|
+
"ToDosDefinitionSchema",
|
|
44
|
+
"BaseTaskPlan",
|
|
30
45
|
"TaskStatus",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
46
|
+
"InMemoryTaskPlan",
|
|
47
|
+
"TaskPlan", # Exposing the alias
|
|
33
48
|
"FileDeliverable",
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
49
|
+
"GetTaskPlanStatus",
|
|
50
|
+
"CreateTasks",
|
|
51
|
+
"CreateTask",
|
|
37
52
|
"UpdateTaskStatus",
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
53
|
+
"AssignTaskTo",
|
|
54
|
+
"GetMyTasks",
|
|
55
|
+
"CreateToDoList",
|
|
56
|
+
"AddToDo",
|
|
57
|
+
"GetToDoList",
|
|
58
|
+
"UpdateToDoStatusTool",
|
|
59
|
+
"TaskPlanConverter",
|
|
60
|
+
"BaseTaskPlanEvent",
|
|
61
|
+
"TasksCreatedEvent",
|
|
41
62
|
"TaskStatusUpdatedEvent",
|
|
63
|
+
"ToDo",
|
|
64
|
+
"ToDoStatus",
|
|
65
|
+
"ToDoList",
|
|
42
66
|
]
|
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/task_management/
|
|
1
|
+
# file: autobyteus/autobyteus/task_management/base_task_plan.py
|
|
2
2
|
"""
|
|
3
|
-
Defines the abstract interface for a
|
|
3
|
+
Defines the abstract interface for a TaskPlan and its related enums.
|
|
4
4
|
"""
|
|
5
5
|
import logging
|
|
6
6
|
from abc import ABC, abstractmethod
|
|
7
7
|
from enum import Enum
|
|
8
|
-
from typing import Dict, Any, List, Optional
|
|
8
|
+
from typing import Dict, Any, List, Optional, TYPE_CHECKING
|
|
9
9
|
|
|
10
10
|
from autobyteus.events.event_emitter import EventEmitter
|
|
11
11
|
from .task import Task
|
|
12
12
|
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from autobyteus.task_management.schemas import TaskDefinitionSchema
|
|
15
|
+
|
|
13
16
|
logger = logging.getLogger(__name__)
|
|
14
17
|
|
|
15
18
|
class TaskStatus(str, Enum):
|
|
16
|
-
"""Enumerates the possible lifecycle states of a task on the
|
|
19
|
+
"""Enumerates the possible lifecycle states of a task on the TaskPlan."""
|
|
17
20
|
NOT_STARTED = "not_started"
|
|
18
21
|
QUEUED = "queued"
|
|
19
22
|
IN_PROGRESS = "in_progress"
|
|
@@ -25,12 +28,12 @@ class TaskStatus(str, Enum):
|
|
|
25
28
|
"""Returns True if the status is a final state."""
|
|
26
29
|
return self in {TaskStatus.COMPLETED, TaskStatus.FAILED}
|
|
27
30
|
|
|
28
|
-
class
|
|
31
|
+
class BaseTaskPlan(ABC, EventEmitter):
|
|
29
32
|
"""
|
|
30
|
-
Abstract base class for a
|
|
33
|
+
Abstract base class for a TaskPlan.
|
|
31
34
|
|
|
32
35
|
This class defines the contract for any component that manages the live state
|
|
33
|
-
of tasks for a team. It is a dynamic
|
|
36
|
+
of tasks for a team. It is a dynamic plan, not a static document.
|
|
34
37
|
It inherits from EventEmitter to broadcast state changes.
|
|
35
38
|
"""
|
|
36
39
|
|
|
@@ -38,19 +41,19 @@ class BaseTaskBoard(ABC, EventEmitter):
|
|
|
38
41
|
EventEmitter.__init__(self)
|
|
39
42
|
self.team_id = team_id
|
|
40
43
|
self.tasks: List[Task] = []
|
|
41
|
-
logger.debug(f"
|
|
44
|
+
logger.debug(f"BaseTaskPlan initialized for team '{self.team_id}'.")
|
|
42
45
|
|
|
43
46
|
@abstractmethod
|
|
44
|
-
def add_tasks(self,
|
|
47
|
+
def add_tasks(self, task_definitions: List['TaskDefinitionSchema']) -> List[Task]:
|
|
45
48
|
"""
|
|
46
|
-
|
|
49
|
+
Creates new tasks from definitions, adds them to the plan, and returns the created Task objects.
|
|
47
50
|
"""
|
|
48
51
|
raise NotImplementedError
|
|
49
52
|
|
|
50
53
|
@abstractmethod
|
|
51
|
-
def add_task(self,
|
|
54
|
+
def add_task(self, task_definition: 'TaskDefinitionSchema') -> Optional[Task]:
|
|
52
55
|
"""
|
|
53
|
-
|
|
56
|
+
Creates a single new task from a definition, adds it to the plan, and returns it.
|
|
54
57
|
"""
|
|
55
58
|
raise NotImplementedError
|
|
56
59
|
|
|
@@ -64,7 +67,7 @@ class BaseTaskBoard(ABC, EventEmitter):
|
|
|
64
67
|
@abstractmethod
|
|
65
68
|
def get_status_overview(self) -> Dict[str, Any]:
|
|
66
69
|
"""
|
|
67
|
-
Returns a serializable dictionary of the
|
|
70
|
+
Returns a serializable dictionary of the plan's current state.
|
|
68
71
|
"""
|
|
69
72
|
raise NotImplementedError
|
|
70
73
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/task_management/converters/
|
|
1
|
+
# file: autobyteus/autobyteus/task_management/converters/task_plan_converter.py
|
|
2
2
|
"""
|
|
3
3
|
Contains converters for translating internal task management objects into
|
|
4
4
|
LLM-friendly Pydantic schemas.
|
|
@@ -6,35 +6,35 @@ LLM-friendly Pydantic schemas.
|
|
|
6
6
|
import logging
|
|
7
7
|
from typing import Optional
|
|
8
8
|
|
|
9
|
-
from autobyteus.task_management.
|
|
9
|
+
from autobyteus.task_management.base_task_plan import BaseTaskPlan
|
|
10
10
|
from autobyteus.task_management.schemas import TaskStatusReportSchema, TaskStatusReportItemSchema
|
|
11
11
|
|
|
12
12
|
logger = logging.getLogger(__name__)
|
|
13
13
|
|
|
14
|
-
class
|
|
15
|
-
"""A converter to transform
|
|
14
|
+
class TaskPlanConverter:
|
|
15
|
+
"""A converter to transform TaskPlan state into LLM-friendly schemas."""
|
|
16
16
|
|
|
17
17
|
@staticmethod
|
|
18
|
-
def to_schema(
|
|
18
|
+
def to_schema(task_plan: BaseTaskPlan) -> Optional[TaskStatusReportSchema]:
|
|
19
19
|
"""
|
|
20
|
-
Converts the current state of a
|
|
20
|
+
Converts the current state of a TaskPlan into a TaskStatusReportSchema.
|
|
21
21
|
|
|
22
22
|
Args:
|
|
23
|
-
|
|
23
|
+
task_plan: The task plan instance to convert.
|
|
24
24
|
|
|
25
25
|
Returns:
|
|
26
26
|
A TaskStatusReportSchema object if there are tasks, otherwise None.
|
|
27
27
|
"""
|
|
28
|
-
if not
|
|
29
|
-
logger.debug(f"
|
|
28
|
+
if not task_plan.tasks:
|
|
29
|
+
logger.debug(f"TaskPlan for team '{task_plan.team_id}' has no tasks. Cannot generate report.")
|
|
30
30
|
return None
|
|
31
31
|
|
|
32
|
-
internal_status =
|
|
32
|
+
internal_status = task_plan.get_status_overview()
|
|
33
33
|
|
|
34
|
-
id_to_name_map = {task.task_id: task.task_name for task in
|
|
34
|
+
id_to_name_map = {task.task_id: task.task_name for task in task_plan.tasks}
|
|
35
35
|
|
|
36
36
|
report_items = []
|
|
37
|
-
for task in
|
|
37
|
+
for task in task_plan.tasks:
|
|
38
38
|
dep_names = [id_to_name_map.get(dep_id, str(dep_id)) for dep_id in task.dependencies]
|
|
39
39
|
|
|
40
40
|
report_item = TaskStatusReportItemSchema(
|
|
@@ -51,5 +51,5 @@ class TaskBoardConverter:
|
|
|
51
51
|
tasks=report_items
|
|
52
52
|
)
|
|
53
53
|
|
|
54
|
-
logger.debug(f"Successfully converted
|
|
54
|
+
logger.debug(f"Successfully converted TaskPlan state to TaskStatusReportSchema for team '{task_plan.team_id}'.")
|
|
55
55
|
return status_report
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
# file: autobyteus/autobyteus/task_management/events.py
|
|
2
2
|
"""
|
|
3
|
-
Defines the Pydantic models for events emitted by a
|
|
3
|
+
Defines the Pydantic models for events emitted by a TaskPlan.
|
|
4
4
|
"""
|
|
5
5
|
from typing import List, Optional
|
|
6
6
|
from pydantic import BaseModel
|
|
7
7
|
|
|
8
8
|
from autobyteus.task_management.task import Task
|
|
9
|
-
from autobyteus.task_management.
|
|
9
|
+
from autobyteus.task_management.base_task_plan import TaskStatus
|
|
10
10
|
from .deliverable import FileDeliverable
|
|
11
11
|
|
|
12
|
-
class
|
|
13
|
-
"""Base class for all task
|
|
12
|
+
class BaseTaskPlanEvent(BaseModel):
|
|
13
|
+
"""Base class for all task plan events."""
|
|
14
14
|
team_id: str
|
|
15
15
|
|
|
16
|
-
class
|
|
16
|
+
class TasksCreatedEvent(BaseTaskPlanEvent):
|
|
17
17
|
"""
|
|
18
|
-
Payload for when one or more tasks are
|
|
18
|
+
Payload for when one or more tasks are created in the plan.
|
|
19
19
|
"""
|
|
20
20
|
tasks: List[Task]
|
|
21
21
|
|
|
22
|
-
class TaskStatusUpdatedEvent(
|
|
22
|
+
class TaskStatusUpdatedEvent(BaseTaskPlanEvent):
|
|
23
23
|
"""Payload for when a task's status is updated."""
|
|
24
24
|
task_id: str
|
|
25
25
|
new_status: TaskStatus
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/task_management/
|
|
1
|
+
# file: autobyteus/autobyteus/task_management/in_memory_task_plan.py
|
|
2
2
|
"""
|
|
3
|
-
An in-memory implementation of the
|
|
3
|
+
An in-memory implementation of the BaseTaskPlan.
|
|
4
4
|
It tracks task statuses in a simple dictionary and emits events on state changes.
|
|
5
5
|
"""
|
|
6
6
|
import logging
|
|
@@ -8,50 +8,62 @@ 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 .schemas import TaskDefinitionSchema
|
|
11
12
|
from .task import Task
|
|
12
|
-
from .
|
|
13
|
-
from .events import
|
|
13
|
+
from .base_task_plan import BaseTaskPlan, TaskStatus
|
|
14
|
+
from .events import TasksCreatedEvent, TaskStatusUpdatedEvent
|
|
14
15
|
|
|
15
16
|
logger = logging.getLogger(__name__)
|
|
16
17
|
|
|
17
|
-
class
|
|
18
|
+
class InMemoryTaskPlan(BaseTaskPlan):
|
|
18
19
|
"""
|
|
19
|
-
An in-memory, dictionary-based implementation of the
|
|
20
|
+
An in-memory, dictionary-based implementation of the TaskPlan that emits
|
|
20
21
|
events on state changes.
|
|
21
22
|
"""
|
|
22
23
|
def __init__(self, team_id: str):
|
|
23
24
|
"""
|
|
24
|
-
Initializes the
|
|
25
|
+
Initializes the InMemoryTaskPlan.
|
|
25
26
|
"""
|
|
26
27
|
super().__init__(team_id=team_id)
|
|
27
28
|
self.task_statuses: Dict[str, TaskStatus] = {}
|
|
28
29
|
self._task_map: Dict[str, Task] = {}
|
|
29
|
-
|
|
30
|
+
self._id_counter: int = 0
|
|
31
|
+
logger.info(f"InMemoryTaskPlan initialized for team '{self.team_id}'.")
|
|
32
|
+
|
|
33
|
+
def _generate_next_id(self) -> str:
|
|
34
|
+
self._id_counter += 1
|
|
35
|
+
return f"task_{self._id_counter:04d}"
|
|
30
36
|
|
|
31
|
-
def add_tasks(self,
|
|
37
|
+
def add_tasks(self, task_definitions: List[TaskDefinitionSchema]) -> List[Task]:
|
|
32
38
|
"""
|
|
33
|
-
|
|
39
|
+
Creates new tasks from definitions, adds them to the plan, and returns the created tasks.
|
|
34
40
|
"""
|
|
35
|
-
|
|
41
|
+
new_tasks: List[Task] = []
|
|
42
|
+
for task_def in task_definitions:
|
|
43
|
+
new_id = self._generate_next_id()
|
|
44
|
+
task = Task(task_id=new_id, **task_def.model_dump())
|
|
45
|
+
|
|
36
46
|
self.tasks.append(task)
|
|
37
47
|
self.task_statuses[task.task_id] = TaskStatus.NOT_STARTED
|
|
38
48
|
self._task_map[task.task_id] = task
|
|
49
|
+
new_tasks.append(task)
|
|
39
50
|
|
|
40
51
|
self._hydrate_all_dependencies()
|
|
41
|
-
logger.info(f"Team '{self.team_id}': Added {len(
|
|
52
|
+
logger.info(f"Team '{self.team_id}': Added {len(new_tasks)} new task(s) to the plan. Emitting TasksCreatedEvent.")
|
|
42
53
|
|
|
43
|
-
event_payload =
|
|
54
|
+
event_payload = TasksCreatedEvent(
|
|
44
55
|
team_id=self.team_id,
|
|
45
|
-
tasks=
|
|
56
|
+
tasks=new_tasks,
|
|
46
57
|
)
|
|
47
|
-
self.emit(EventType.
|
|
48
|
-
return
|
|
58
|
+
self.emit(EventType.TASK_PLAN_TASKS_CREATED, payload=event_payload)
|
|
59
|
+
return new_tasks
|
|
49
60
|
|
|
50
|
-
def add_task(self,
|
|
61
|
+
def add_task(self, task_definition: TaskDefinitionSchema) -> Optional[Task]:
|
|
51
62
|
"""
|
|
52
|
-
|
|
63
|
+
Creates a single new task from a definition, adds it to the plan, and returns it.
|
|
53
64
|
"""
|
|
54
|
-
|
|
65
|
+
created_tasks = self.add_tasks([task_definition])
|
|
66
|
+
return created_tasks[0] if created_tasks else None
|
|
55
67
|
|
|
56
68
|
def _hydrate_all_dependencies(self):
|
|
57
69
|
"""
|
|
@@ -67,7 +79,7 @@ class InMemoryTaskBoard(BaseTaskBoard):
|
|
|
67
79
|
|
|
68
80
|
resolved_deps = []
|
|
69
81
|
for dep in task.dependencies:
|
|
70
|
-
# Case 1: The dependency is already a valid task_id on the
|
|
82
|
+
# Case 1: The dependency is already a valid task_id on the plan.
|
|
71
83
|
if dep in all_task_ids:
|
|
72
84
|
resolved_deps.append(dep)
|
|
73
85
|
# Case 2: The dependency is a task_name that can be resolved.
|
|
@@ -103,12 +115,12 @@ class InMemoryTaskBoard(BaseTaskBoard):
|
|
|
103
115
|
agent_name=agent_name,
|
|
104
116
|
deliverables=task_deliverables
|
|
105
117
|
)
|
|
106
|
-
self.emit(EventType.
|
|
118
|
+
self.emit(EventType.TASK_PLAN_STATUS_UPDATED, payload=event_payload)
|
|
107
119
|
return True
|
|
108
120
|
|
|
109
121
|
def get_status_overview(self) -> Dict[str, Any]:
|
|
110
122
|
"""
|
|
111
|
-
Returns a serializable dictionary of the
|
|
123
|
+
Returns a serializable dictionary of the plan's current state.
|
|
112
124
|
The overall_goal is now fetched from the context via the converter.
|
|
113
125
|
"""
|
|
114
126
|
return {
|
|
@@ -5,6 +5,7 @@ Exposes the public schema models for the task management module.
|
|
|
5
5
|
from .task_definition import TasksDefinitionSchema, TaskDefinitionSchema
|
|
6
6
|
from .task_status_report import TaskStatusReportSchema, TaskStatusReportItemSchema
|
|
7
7
|
from .deliverable_schema import FileDeliverableSchema
|
|
8
|
+
from .todo_definition import ToDoDefinitionSchema, ToDosDefinitionSchema
|
|
8
9
|
|
|
9
10
|
__all__ = [
|
|
10
11
|
"TasksDefinitionSchema",
|
|
@@ -12,4 +13,6 @@ __all__ = [
|
|
|
12
13
|
"TaskStatusReportSchema",
|
|
13
14
|
"TaskStatusReportItemSchema",
|
|
14
15
|
"FileDeliverableSchema",
|
|
16
|
+
"ToDoDefinitionSchema",
|
|
17
|
+
"ToDosDefinitionSchema",
|
|
15
18
|
]
|
|
@@ -13,7 +13,7 @@ class TaskDefinitionSchema(BaseModel):
|
|
|
13
13
|
"""A Pydantic model representing a single task as defined by an LLM."""
|
|
14
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
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.")
|
|
16
|
+
description: str = Field(..., description="A clear, detailed, and unambiguous description of what this task entails. Provide all necessary context for the assignee to complete the work. For example, if the task involves a file, specify its full, absolute path. If it requires creating a file, specify where it should be saved. Mention any specific requirements or expected outputs.")
|
|
17
17
|
dependencies: List[str] = Field(
|
|
18
18
|
default_factory=list,
|
|
19
19
|
description="A list of 'task_name' values for tasks that must be completed first."
|
|
@@ -9,18 +9,18 @@ but includes dynamic state information (like task status).
|
|
|
9
9
|
from typing import List, Optional
|
|
10
10
|
from pydantic import BaseModel, Field
|
|
11
11
|
|
|
12
|
-
from autobyteus.task_management.
|
|
12
|
+
from autobyteus.task_management.base_task_plan import TaskStatus
|
|
13
13
|
from autobyteus.task_management.deliverable import FileDeliverable
|
|
14
14
|
|
|
15
15
|
class TaskStatusReportItemSchema(BaseModel):
|
|
16
16
|
"""Represents the status of a single task in an LLM-friendly format."""
|
|
17
17
|
task_name: str = Field(..., description="The unique, descriptive name for this task.")
|
|
18
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.")
|
|
19
|
+
description: str = Field(..., description="A clear, detailed, and unambiguous description of what this task entails. Provide all necessary context for the assignee to complete the work. For example, if the task involves a file, specify its full, absolute path. If it requires creating a file, specify where it should be saved. Mention any specific requirements or expected outputs.")
|
|
20
20
|
dependencies: List[str] = Field(..., description="A list of 'task_name' values for tasks that must be completed first.")
|
|
21
21
|
status: TaskStatus = Field(..., description="The current status of this task.")
|
|
22
22
|
file_deliverables: List[FileDeliverable] = Field(default_factory=list, description="A list of files submitted as deliverables for this task.")
|
|
23
23
|
|
|
24
24
|
class TaskStatusReportSchema(BaseModel):
|
|
25
|
-
"""Represents a full task
|
|
25
|
+
"""Represents a full task plan status report in an LLM-friendly format."""
|
|
26
26
|
tasks: List[TaskStatusReportItemSchema] = Field(..., description="The list of tasks and their current statuses.")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/task_management/schemas/todo_definition.py
|
|
2
|
+
"""
|
|
3
|
+
Defines the Pydantic models for ToDo "definitions".
|
|
4
|
+
These models represent the structure an LLM is expected to generate for personal planning.
|
|
5
|
+
"""
|
|
6
|
+
from typing import List
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
class ToDoDefinitionSchema(BaseModel):
|
|
10
|
+
"""A Pydantic model representing a single to-do item as defined by an LLM."""
|
|
11
|
+
description: str = Field(..., description="A clear, detailed description of what this to-do item or step entails.")
|
|
12
|
+
|
|
13
|
+
class ToDosDefinitionSchema(BaseModel):
|
|
14
|
+
"""A Pydantic model representing a list of to-do items as generated by an LLM."""
|
|
15
|
+
todos: List[ToDoDefinitionSchema] = Field(..., description="The list of to-do items to create.")
|