autobyteus 1.1.7__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 +86 -23
- 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.7.dist-info → autobyteus-1.1.9.dist-info}/METADATA +2 -2
- {autobyteus-1.1.7.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.7.dist-info → autobyteus-1.1.9.dist-info}/WHEEL +0 -0
- {autobyteus-1.1.7.dist-info → autobyteus-1.1.9.dist-info}/licenses/LICENSE +0 -0
- {autobyteus-1.1.7.dist-info → autobyteus-1.1.9.dist-info}/top_level.txt +0 -0
|
@@ -3,6 +3,7 @@ import logging
|
|
|
3
3
|
from typing import TYPE_CHECKING, Dict, List, Optional, Type
|
|
4
4
|
|
|
5
5
|
from autobyteus.utils.singleton import SingletonMeta
|
|
6
|
+
from autobyteus.agent.processor_option import ProcessorOption
|
|
6
7
|
from .processor_definition import LLMResponseProcessorDefinition
|
|
7
8
|
if TYPE_CHECKING:
|
|
8
9
|
from .base_processor import BaseLLMResponseProcessor
|
|
@@ -23,14 +24,6 @@ class LLMResponseProcessorRegistry(metaclass=SingletonMeta):
|
|
|
23
24
|
def register_processor(self, definition: LLMResponseProcessorDefinition) -> None:
|
|
24
25
|
"""
|
|
25
26
|
Registers an LLM response processor definition.
|
|
26
|
-
If a definition with the same name already exists, it will be overwritten,
|
|
27
|
-
and a warning will be logged.
|
|
28
|
-
|
|
29
|
-
Args:
|
|
30
|
-
definition: The LLMResponseProcessorDefinition object to register.
|
|
31
|
-
|
|
32
|
-
Raises:
|
|
33
|
-
TypeError: If the definition is not an instance of LLMResponseProcessorDefinition.
|
|
34
27
|
"""
|
|
35
28
|
if not isinstance(definition, LLMResponseProcessorDefinition):
|
|
36
29
|
raise TypeError(f"Expected LLMResponseProcessorDefinition instance, got {type(definition).__name__}.")
|
|
@@ -45,12 +38,6 @@ class LLMResponseProcessorRegistry(metaclass=SingletonMeta):
|
|
|
45
38
|
def get_processor_definition(self, name: str) -> Optional[LLMResponseProcessorDefinition]:
|
|
46
39
|
"""
|
|
47
40
|
Retrieves an LLM response processor definition by its name.
|
|
48
|
-
|
|
49
|
-
Args:
|
|
50
|
-
name: The name of the LLM response processor definition to retrieve.
|
|
51
|
-
|
|
52
|
-
Returns:
|
|
53
|
-
The LLMResponseProcessorDefinition object if found, otherwise None.
|
|
54
41
|
"""
|
|
55
42
|
if not isinstance(name, str):
|
|
56
43
|
logger.warning(f"Attempted to retrieve LLM response processor definition with non-string name: {type(name).__name__}.")
|
|
@@ -63,12 +50,6 @@ class LLMResponseProcessorRegistry(metaclass=SingletonMeta):
|
|
|
63
50
|
def get_processor(self, name: str) -> Optional['BaseLLMResponseProcessor']:
|
|
64
51
|
"""
|
|
65
52
|
Retrieves an instance of an LLM response processor by its name.
|
|
66
|
-
|
|
67
|
-
Args:
|
|
68
|
-
name: The name of the LLM response processor to retrieve.
|
|
69
|
-
|
|
70
|
-
Returns:
|
|
71
|
-
An instance of the BaseLLMResponseProcessor if found and instantiable, otherwise None.
|
|
72
53
|
"""
|
|
73
54
|
definition = self.get_processor_definition(name)
|
|
74
55
|
if definition:
|
|
@@ -81,13 +62,23 @@ class LLMResponseProcessorRegistry(metaclass=SingletonMeta):
|
|
|
81
62
|
|
|
82
63
|
def list_processor_names(self) -> List[str]:
|
|
83
64
|
"""
|
|
84
|
-
Returns
|
|
85
|
-
|
|
86
|
-
Returns:
|
|
87
|
-
A list of strings, where each string is a registered processor name.
|
|
65
|
+
Returns an unordered list of names of all registered LLM response processor definitions.
|
|
88
66
|
"""
|
|
89
67
|
return list(self._definitions.keys())
|
|
90
68
|
|
|
69
|
+
def get_ordered_processor_options(self) -> List[ProcessorOption]:
|
|
70
|
+
"""
|
|
71
|
+
Returns a list of ProcessorOption objects, sorted by their execution order.
|
|
72
|
+
"""
|
|
73
|
+
definitions = list(self._definitions.values())
|
|
74
|
+
sorted_definitions = sorted(definitions, key=lambda d: d.processor_class.get_order())
|
|
75
|
+
return [
|
|
76
|
+
ProcessorOption(
|
|
77
|
+
name=d.name,
|
|
78
|
+
is_mandatory=d.processor_class.is_mandatory()
|
|
79
|
+
) for d in sorted_definitions
|
|
80
|
+
]
|
|
81
|
+
|
|
91
82
|
def get_all_definitions(self) -> Dict[str, LLMResponseProcessorDefinition]:
|
|
92
83
|
"""
|
|
93
84
|
Returns a shallow copy of the dictionary containing all registered LLM response processor definitions.
|
|
@@ -27,6 +27,20 @@ class ProviderAwareToolUsageProcessor(BaseLLMResponseProcessor):
|
|
|
27
27
|
self._parser = ProviderAwareToolUsageParser()
|
|
28
28
|
logger.debug("ProviderAwareToolUsageProcessor initialized.")
|
|
29
29
|
|
|
30
|
+
@classmethod
|
|
31
|
+
def get_name(cls) -> str:
|
|
32
|
+
return "ProviderAwareToolUsageProcessor"
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def get_order(cls) -> int:
|
|
36
|
+
"""Runs with the highest priority to parse for tool calls before any other processing."""
|
|
37
|
+
return 100
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def is_mandatory(cls) -> bool:
|
|
41
|
+
"""This processor is essential for any agent that uses tools."""
|
|
42
|
+
return True
|
|
43
|
+
|
|
30
44
|
async def process_response(self, response: 'CompleteResponse', context: 'AgentContext', triggering_event: 'LLMCompleteResponseReceivedEvent') -> bool:
|
|
31
45
|
"""
|
|
32
46
|
Uses a ProviderAwareToolUsageParser to get tool invocations, makes their
|
|
@@ -4,6 +4,7 @@ from typing import Optional, List, Dict, Any
|
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
|
|
6
6
|
from .context_file import ContextFile # Import the new ContextFile dataclass
|
|
7
|
+
from autobyteus.agent.sender_type import SenderType
|
|
7
8
|
|
|
8
9
|
logger = logging.getLogger(__name__)
|
|
9
10
|
|
|
@@ -15,11 +16,14 @@ class AgentInputUserMessage:
|
|
|
15
16
|
allowing users to provide various documents and media as context via a single list.
|
|
16
17
|
"""
|
|
17
18
|
content: str
|
|
19
|
+
sender_type: SenderType = SenderType.USER
|
|
18
20
|
context_files: Optional[List[ContextFile]] = field(default=None)
|
|
19
21
|
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
20
22
|
|
|
21
23
|
def __post_init__(self):
|
|
22
24
|
# Basic type validation that dataclasses don't do automatically for mutable defaults or complex types
|
|
25
|
+
if not isinstance(self.sender_type, SenderType):
|
|
26
|
+
raise TypeError(f"AgentInputUserMessage 'sender_type' must be a SenderType enum. Got {type(self.sender_type)}")
|
|
23
27
|
if self.context_files is not None and not (isinstance(self.context_files, list) and all(isinstance(cf, ContextFile) for cf in self.context_files)):
|
|
24
28
|
raise TypeError("AgentInputUserMessage 'context_files' must be a list of ContextFile objects if provided.")
|
|
25
29
|
if not isinstance(self.metadata, dict): # Should be caught by default_factory, but good practice
|
|
@@ -30,7 +34,7 @@ class AgentInputUserMessage:
|
|
|
30
34
|
if logger.isEnabledFor(logging.DEBUG):
|
|
31
35
|
num_context_files = len(self.context_files) if self.context_files else 0
|
|
32
36
|
logger.debug(
|
|
33
|
-
f"AgentInputUserMessage initialized. Content: '{self.content[:50]}...', "
|
|
37
|
+
f"AgentInputUserMessage initialized. SenderType: {self.sender_type.value}, Content: '{self.content[:50]}...', "
|
|
34
38
|
f"Num ContextFiles: {num_context_files}, "
|
|
35
39
|
f"Metadata keys: {list(self.metadata.keys())}"
|
|
36
40
|
)
|
|
@@ -44,6 +48,7 @@ class AgentInputUserMessage:
|
|
|
44
48
|
|
|
45
49
|
return {
|
|
46
50
|
"content": self.content,
|
|
51
|
+
"sender_type": self.sender_type.value,
|
|
47
52
|
"context_files": context_files_dict_list,
|
|
48
53
|
"metadata": self.metadata,
|
|
49
54
|
}
|
|
@@ -55,6 +60,13 @@ class AgentInputUserMessage:
|
|
|
55
60
|
if not isinstance(content, str): # Ensure content is string
|
|
56
61
|
raise ValueError("AgentInputUserMessage 'content' in dictionary must be a string.")
|
|
57
62
|
|
|
63
|
+
sender_type_val = data.get("sender_type", "user")
|
|
64
|
+
try:
|
|
65
|
+
sender_type = SenderType(sender_type_val)
|
|
66
|
+
except ValueError:
|
|
67
|
+
logger.warning(f"Invalid sender_type '{sender_type_val}' in AgentInputUserMessage data. Defaulting to USER.")
|
|
68
|
+
sender_type = SenderType.USER
|
|
69
|
+
|
|
58
70
|
context_files_data = data.get("context_files")
|
|
59
71
|
context_files_list: Optional[List[ContextFile]] = None
|
|
60
72
|
if context_files_data is not None:
|
|
@@ -68,6 +80,7 @@ class AgentInputUserMessage:
|
|
|
68
80
|
|
|
69
81
|
return cls(
|
|
70
82
|
content=content,
|
|
83
|
+
sender_type=sender_type,
|
|
71
84
|
context_files=context_files_list,
|
|
72
85
|
metadata=metadata
|
|
73
86
|
)
|
|
@@ -82,5 +95,5 @@ class AgentInputUserMessage:
|
|
|
82
95
|
|
|
83
96
|
meta_repr = f", metadata_keys={list(self.metadata.keys())}" if self.metadata else ""
|
|
84
97
|
|
|
85
|
-
return (f"AgentInputUserMessage(content='{content_preview}'"
|
|
98
|
+
return (f"AgentInputUserMessage(sender_type='{self.sender_type.value}', content='{content_preview}'"
|
|
86
99
|
f"{context_repr}{meta_repr})")
|
|
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Any, Optional
|
|
|
4
4
|
|
|
5
5
|
from autobyteus.tools.base_tool import BaseTool
|
|
6
6
|
from autobyteus.tools.tool_category import ToolCategory
|
|
7
|
-
from autobyteus.
|
|
7
|
+
from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
|
|
8
8
|
from autobyteus.tools.tool_config import ToolConfig
|
|
9
9
|
# This import is for type hinting only and avoids circular dependencies at runtime
|
|
10
10
|
if TYPE_CHECKING:
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent/processor_option.py
|
|
2
|
+
"""
|
|
3
|
+
Defines common data transfer objects for agent component options.
|
|
4
|
+
"""
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class ProcessorOption:
|
|
9
|
+
"""A data class representing a processor option for configuration."""
|
|
10
|
+
name: str
|
|
11
|
+
is_mandatory: bool
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class HookOption:
|
|
15
|
+
"""A data class representing a hook option for configuration."""
|
|
16
|
+
name: str
|
|
17
|
+
is_mandatory: bool
|
autobyteus/agent/sender_type.py
CHANGED
|
@@ -9,6 +9,7 @@ class SenderType(str, Enum):
|
|
|
9
9
|
USER = "user" # A message originating from an external human user.
|
|
10
10
|
AGENT = "agent" # A message from another agent within the same team or a different team.
|
|
11
11
|
SYSTEM = "system" # An automated message from an internal system component.
|
|
12
|
+
TOOL = "tool" # A message generated as the result of a tool execution.
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
# --- System Sender Identification ---
|
|
@@ -24,6 +24,22 @@ class BaseSystemPromptProcessor(ABC, metaclass=SystemPromptProcessorMeta):
|
|
|
24
24
|
"""
|
|
25
25
|
return cls.__name__
|
|
26
26
|
|
|
27
|
+
@classmethod
|
|
28
|
+
def get_order(cls) -> int:
|
|
29
|
+
"""
|
|
30
|
+
Returns the execution order for this processor. Lower numbers execute earlier.
|
|
31
|
+
Defaults to 500 (normal priority).
|
|
32
|
+
"""
|
|
33
|
+
return 500
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def is_mandatory(cls) -> bool:
|
|
37
|
+
"""
|
|
38
|
+
Returns True if this processor is mandatory for the agent to function correctly.
|
|
39
|
+
Defaults to False (optional).
|
|
40
|
+
"""
|
|
41
|
+
return False
|
|
42
|
+
|
|
27
43
|
@abstractmethod
|
|
28
44
|
def process(self,
|
|
29
45
|
system_prompt: str,
|
|
@@ -45,4 +61,4 @@ class BaseSystemPromptProcessor(ABC, metaclass=SystemPromptProcessorMeta):
|
|
|
45
61
|
raise NotImplementedError("Subclasses must implement the 'process' method.")
|
|
46
62
|
|
|
47
63
|
def __repr__(self) -> str:
|
|
48
|
-
return f"
|
|
64
|
+
return f"<{self.__class__.__name__}>"
|
|
@@ -3,6 +3,7 @@ import logging
|
|
|
3
3
|
from typing import TYPE_CHECKING, Dict, List, Optional, Type
|
|
4
4
|
|
|
5
5
|
from autobyteus.utils.singleton import SingletonMeta
|
|
6
|
+
from autobyteus.agent.processor_option import ProcessorOption
|
|
6
7
|
from .processor_definition import SystemPromptProcessorDefinition # Relative import
|
|
7
8
|
|
|
8
9
|
if TYPE_CHECKING:
|
|
@@ -24,14 +25,6 @@ class SystemPromptProcessorRegistry(metaclass=SingletonMeta):
|
|
|
24
25
|
def register_processor(self, definition: SystemPromptProcessorDefinition) -> None:
|
|
25
26
|
"""
|
|
26
27
|
Registers a system prompt processor definition.
|
|
27
|
-
If a definition with the same name already exists, it will be overwritten,
|
|
28
|
-
and a warning will be logged.
|
|
29
|
-
|
|
30
|
-
Args:
|
|
31
|
-
definition: The SystemPromptProcessorDefinition object to register.
|
|
32
|
-
|
|
33
|
-
Raises:
|
|
34
|
-
TypeError: If the definition is not an instance of SystemPromptProcessorDefinition.
|
|
35
28
|
"""
|
|
36
29
|
if not isinstance(definition, SystemPromptProcessorDefinition):
|
|
37
30
|
raise TypeError(f"Expected SystemPromptProcessorDefinition instance, got {type(definition).__name__}.")
|
|
@@ -46,12 +39,6 @@ class SystemPromptProcessorRegistry(metaclass=SingletonMeta):
|
|
|
46
39
|
def get_processor_definition(self, name: str) -> Optional[SystemPromptProcessorDefinition]:
|
|
47
40
|
"""
|
|
48
41
|
Retrieves a system prompt processor definition by its name.
|
|
49
|
-
|
|
50
|
-
Args:
|
|
51
|
-
name: The name of the system prompt processor definition to retrieve.
|
|
52
|
-
|
|
53
|
-
Returns:
|
|
54
|
-
The SystemPromptProcessorDefinition object if found, otherwise None.
|
|
55
42
|
"""
|
|
56
43
|
if not isinstance(name, str):
|
|
57
44
|
logger.warning(f"Attempted to retrieve system prompt processor definition with non-string name: {type(name).__name__}.")
|
|
@@ -64,12 +51,6 @@ class SystemPromptProcessorRegistry(metaclass=SingletonMeta):
|
|
|
64
51
|
def get_processor(self, name: str) -> Optional['BaseSystemPromptProcessor']:
|
|
65
52
|
"""
|
|
66
53
|
Retrieves an instance of a system prompt processor by its name.
|
|
67
|
-
|
|
68
|
-
Args:
|
|
69
|
-
name: The name of the system prompt processor to retrieve.
|
|
70
|
-
|
|
71
|
-
Returns:
|
|
72
|
-
An instance of the BaseSystemPromptProcessor if found and instantiable, otherwise None.
|
|
73
54
|
"""
|
|
74
55
|
definition = self.get_processor_definition(name)
|
|
75
56
|
if definition:
|
|
@@ -83,19 +64,26 @@ class SystemPromptProcessorRegistry(metaclass=SingletonMeta):
|
|
|
83
64
|
|
|
84
65
|
def list_processor_names(self) -> List[str]:
|
|
85
66
|
"""
|
|
86
|
-
Returns
|
|
87
|
-
|
|
88
|
-
Returns:
|
|
89
|
-
A list of strings, where each string is a registered processor name.
|
|
67
|
+
Returns an unordered list of names of all registered system prompt processor definitions.
|
|
90
68
|
"""
|
|
91
69
|
return list(self._definitions.keys())
|
|
92
70
|
|
|
71
|
+
def get_ordered_processor_options(self) -> List[ProcessorOption]:
|
|
72
|
+
"""
|
|
73
|
+
Returns a list of ProcessorOption objects, sorted by their execution order.
|
|
74
|
+
"""
|
|
75
|
+
definitions = list(self._definitions.values())
|
|
76
|
+
sorted_definitions = sorted(definitions, key=lambda d: d.processor_class.get_order())
|
|
77
|
+
return [
|
|
78
|
+
ProcessorOption(
|
|
79
|
+
name=d.name,
|
|
80
|
+
is_mandatory=d.processor_class.is_mandatory()
|
|
81
|
+
) for d in sorted_definitions
|
|
82
|
+
]
|
|
83
|
+
|
|
93
84
|
def get_all_definitions(self) -> Dict[str, SystemPromptProcessorDefinition]:
|
|
94
85
|
"""
|
|
95
86
|
Returns a shallow copy of the dictionary containing all registered system prompt processor definitions.
|
|
96
|
-
|
|
97
|
-
Returns:
|
|
98
|
-
A dictionary where keys are processor names and values are SystemPromptProcessorDefinition objects.
|
|
99
87
|
"""
|
|
100
88
|
return dict(self._definitions)
|
|
101
89
|
|
|
@@ -32,6 +32,16 @@ class ToolManifestInjectorProcessor(BaseSystemPromptProcessor):
|
|
|
32
32
|
def get_name(cls) -> str:
|
|
33
33
|
return "ToolManifestInjector"
|
|
34
34
|
|
|
35
|
+
@classmethod
|
|
36
|
+
def get_order(cls) -> int:
|
|
37
|
+
"""Explicitly set to default, as it's often the only system prompt processor."""
|
|
38
|
+
return 500
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def is_mandatory(cls) -> bool:
|
|
42
|
+
"""This processor is essential for the LLM to know which tools are available."""
|
|
43
|
+
return True
|
|
44
|
+
|
|
35
45
|
def process(self, system_prompt: str, tool_instances: Dict[str, 'BaseTool'], agent_id: str, context: 'AgentContext') -> str:
|
|
36
46
|
try:
|
|
37
47
|
prompt_template = PromptTemplate(template=system_prompt)
|
|
@@ -26,6 +26,22 @@ class BaseToolExecutionResultProcessor(ABC, metaclass=ToolExecutionResultProcess
|
|
|
26
26
|
"""
|
|
27
27
|
return cls.__name__
|
|
28
28
|
|
|
29
|
+
@classmethod
|
|
30
|
+
def get_order(cls) -> int:
|
|
31
|
+
"""
|
|
32
|
+
Returns the execution order for this processor. Lower numbers execute earlier.
|
|
33
|
+
Defaults to 500 (normal priority).
|
|
34
|
+
"""
|
|
35
|
+
return 500
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def is_mandatory(cls) -> bool:
|
|
39
|
+
"""
|
|
40
|
+
Returns True if this processor is mandatory for the agent to function correctly.
|
|
41
|
+
Defaults to False (optional).
|
|
42
|
+
"""
|
|
43
|
+
return False
|
|
44
|
+
|
|
29
45
|
@abstractmethod
|
|
30
46
|
async def process(self,
|
|
31
47
|
event: 'ToolResultEvent',
|
|
@@ -43,4 +59,4 @@ class BaseToolExecutionResultProcessor(ABC, metaclass=ToolExecutionResultProcess
|
|
|
43
59
|
raise NotImplementedError("Subclasses must implement the 'process' method.")
|
|
44
60
|
|
|
45
61
|
def __repr__(self) -> str:
|
|
46
|
-
return f"
|
|
62
|
+
return f"<{self.__class__.__name__}>"
|
|
@@ -3,6 +3,7 @@ import logging
|
|
|
3
3
|
from typing import TYPE_CHECKING, Dict, List, Optional
|
|
4
4
|
|
|
5
5
|
from autobyteus.utils.singleton import SingletonMeta
|
|
6
|
+
from autobyteus.agent.processor_option import ProcessorOption
|
|
6
7
|
from .processor_definition import ToolExecutionResultProcessorDefinition
|
|
7
8
|
|
|
8
9
|
if TYPE_CHECKING:
|
|
@@ -56,10 +57,23 @@ class ToolExecutionResultProcessorRegistry(metaclass=SingletonMeta):
|
|
|
56
57
|
|
|
57
58
|
def list_processor_names(self) -> List[str]:
|
|
58
59
|
"""
|
|
59
|
-
Returns
|
|
60
|
+
Returns an unordered list of names of all registered processor definitions.
|
|
60
61
|
"""
|
|
61
62
|
return list(self._definitions.keys())
|
|
62
63
|
|
|
64
|
+
def get_ordered_processor_options(self) -> List[ProcessorOption]:
|
|
65
|
+
"""
|
|
66
|
+
Returns a list of ProcessorOption objects, sorted by their execution order.
|
|
67
|
+
"""
|
|
68
|
+
definitions = list(self._definitions.values())
|
|
69
|
+
sorted_definitions = sorted(definitions, key=lambda d: d.processor_class.get_order())
|
|
70
|
+
return [
|
|
71
|
+
ProcessorOption(
|
|
72
|
+
name=d.name,
|
|
73
|
+
is_mandatory=d.processor_class.is_mandatory()
|
|
74
|
+
) for d in sorted_definitions
|
|
75
|
+
]
|
|
76
|
+
|
|
63
77
|
def get_all_definitions(self) -> Dict[str, ToolExecutionResultProcessorDefinition]:
|
|
64
78
|
"""
|
|
65
79
|
Returns a dictionary of all registered processor definitions.
|
|
@@ -3,7 +3,7 @@ import logging
|
|
|
3
3
|
import uuid
|
|
4
4
|
from abc import ABC, abstractmethod
|
|
5
5
|
from typing import Optional, Any, Dict, TYPE_CHECKING
|
|
6
|
-
from autobyteus.
|
|
6
|
+
from autobyteus.utils.parameter_schema import ParameterSchema
|
|
7
7
|
from autobyteus.agent.workspace.workspace_meta import WorkspaceMeta
|
|
8
8
|
from autobyteus.agent.workspace.workspace_config import WorkspaceConfig
|
|
9
9
|
|
|
@@ -4,7 +4,7 @@ for a specific type of agent workspace.
|
|
|
4
4
|
"""
|
|
5
5
|
import logging
|
|
6
6
|
from typing import Type, Optional, TYPE_CHECKING
|
|
7
|
-
from autobyteus.
|
|
7
|
+
from autobyteus.utils.parameter_schema import ParameterSchema
|
|
8
8
|
|
|
9
9
|
if TYPE_CHECKING:
|
|
10
10
|
from autobyteus.agent.workspace.base_workspace import BaseAgentWorkspace
|
|
@@ -30,7 +30,7 @@ class TeamContextInitializationStep(BaseAgentTeamBootstrapStep):
|
|
|
30
30
|
if notifier:
|
|
31
31
|
# The notifier, a long-lived component, subscribes to events
|
|
32
32
|
# from the task_board, another long-lived component.
|
|
33
|
-
notifier.subscribe_from(sender=task_board, event=EventType.
|
|
33
|
+
notifier.subscribe_from(sender=task_board, event=EventType.TASK_BOARD_TASKS_ADDED, listener=notifier.handle_and_publish_task_board_event)
|
|
34
34
|
notifier.subscribe_from(sender=task_board, event=EventType.TASK_BOARD_STATUS_UPDATED, listener=notifier.handle_and_publish_task_board_event)
|
|
35
35
|
logger.info(f"Team '{team_id}': Successfully bridged TaskBoard events to the team notifier.")
|
|
36
36
|
else:
|
|
@@ -3,7 +3,7 @@ from typing import Optional, Any
|
|
|
3
3
|
from pydantic import BaseModel, Field
|
|
4
4
|
from autobyteus.agent_team.phases.agent_team_operational_phase import AgentTeamOperationalPhase
|
|
5
5
|
from autobyteus.agent.streaming.stream_events import StreamEvent as AgentStreamEvent
|
|
6
|
-
from autobyteus.task_management.events import
|
|
6
|
+
from autobyteus.task_management.events import TasksAddedEvent, TaskStatusUpdatedEvent
|
|
7
7
|
# Need to use a forward reference string to avoid circular import at runtime
|
|
8
8
|
from typing import TYPE_CHECKING, Union
|
|
9
9
|
if TYPE_CHECKING:
|
|
@@ -29,4 +29,4 @@ class SubTeamEventRebroadcastPayload(BaseModel):
|
|
|
29
29
|
sub_team_event: "AgentTeamStreamEvent" = Field(..., description="The original, unmodified event from the sub-team's stream")
|
|
30
30
|
|
|
31
31
|
# --- Payload for events originating from the "TASK_BOARD" source ---
|
|
32
|
-
TaskBoardEventPayload = Union[
|
|
32
|
+
TaskBoardEventPayload = Union[TasksAddedEvent, TaskStatusUpdatedEvent]
|
|
@@ -4,8 +4,12 @@ This package contains components for automatically notifying agents of runnable
|
|
|
4
4
|
"""
|
|
5
5
|
from .system_event_driven_agent_task_notifier import SystemEventDrivenAgentTaskNotifier
|
|
6
6
|
from .task_notification_mode import TaskNotificationMode
|
|
7
|
+
from .activation_policy import ActivationPolicy
|
|
8
|
+
from .task_activator import TaskActivator
|
|
7
9
|
|
|
8
10
|
__all__ = [
|
|
9
11
|
"SystemEventDrivenAgentTaskNotifier",
|
|
10
12
|
"TaskNotificationMode",
|
|
13
|
+
"ActivationPolicy",
|
|
14
|
+
"TaskActivator",
|
|
11
15
|
]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent_team/task_notification/activation_policy.py
|
|
2
|
+
"""
|
|
3
|
+
Defines the policy for deciding which agents should be activated based on task runnability.
|
|
4
|
+
"""
|
|
5
|
+
import logging
|
|
6
|
+
from typing import List, Set
|
|
7
|
+
|
|
8
|
+
from autobyteus.task_management.task import Task
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
class ActivationPolicy:
|
|
13
|
+
"""
|
|
14
|
+
Encapsulates the "Single Wave" notification logic for an agent team.
|
|
15
|
+
|
|
16
|
+
This class maintains a stateful set of agents that have already been
|
|
17
|
+
activated. It decides which new agents should receive a "start work"
|
|
18
|
+
notification based on a list of currently runnable tasks.
|
|
19
|
+
"""
|
|
20
|
+
def __init__(self, team_id: str):
|
|
21
|
+
"""
|
|
22
|
+
Initializes the ActivationPolicy.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
team_id: The ID of the team this policy belongs to, for logging.
|
|
26
|
+
"""
|
|
27
|
+
self._team_id = team_id
|
|
28
|
+
self._activated_agents: Set[str] = set()
|
|
29
|
+
logger.debug(f"ActivationPolicy initialized for team '{self._team_id}'.")
|
|
30
|
+
|
|
31
|
+
def reset(self):
|
|
32
|
+
"""
|
|
33
|
+
Resets the activation state. This should be called when a new batch of
|
|
34
|
+
tasks is published to the task board, signifying a new plan or a
|
|
35
|
+
significant change in scope.
|
|
36
|
+
"""
|
|
37
|
+
logger.info(f"Team '{self._team_id}': ActivationPolicy state has been reset. All agents are now considered inactive.")
|
|
38
|
+
self._activated_agents.clear()
|
|
39
|
+
|
|
40
|
+
def determine_activations(self, runnable_tasks: List[Task]) -> List[str]:
|
|
41
|
+
"""
|
|
42
|
+
Determines which agents should be activated based on a list of runnable tasks.
|
|
43
|
+
|
|
44
|
+
An agent is selected for activation if they have one or more runnable tasks
|
|
45
|
+
and have not already been activated in the current work cycle.
|
|
46
|
+
|
|
47
|
+
This method is stateful: it updates its internal set of activated agents
|
|
48
|
+
with the new agents it returns.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
runnable_tasks: A list of tasks that are currently runnable.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
A list of unique agent names that should be activated.
|
|
55
|
+
"""
|
|
56
|
+
if not runnable_tasks:
|
|
57
|
+
return []
|
|
58
|
+
|
|
59
|
+
agents_with_runnable_tasks = {task.assignee_name for task in runnable_tasks}
|
|
60
|
+
|
|
61
|
+
# Determine which of these agents have not yet been activated.
|
|
62
|
+
new_agents_to_activate = list(agents_with_runnable_tasks - self._activated_agents)
|
|
63
|
+
|
|
64
|
+
if new_agents_to_activate:
|
|
65
|
+
# Update the state to remember that these agents have now been activated.
|
|
66
|
+
self._activated_agents.update(new_agents_to_activate)
|
|
67
|
+
logger.info(f"Team '{self._team_id}': Policy determined {len(new_agents_to_activate)} new agent(s) to activate: {new_agents_to_activate}. "
|
|
68
|
+
f"Total activated agents is now {len(self._activated_agents)}.")
|
|
69
|
+
|
|
70
|
+
return new_agents_to_activate
|