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.
Files changed (108) hide show
  1. autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +6 -2
  2. autobyteus/agent/handlers/inter_agent_message_event_handler.py +17 -19
  3. autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +6 -3
  4. autobyteus/agent/handlers/tool_result_event_handler.py +86 -23
  5. autobyteus/agent/handlers/user_input_message_event_handler.py +19 -10
  6. autobyteus/agent/hooks/base_phase_hook.py +17 -0
  7. autobyteus/agent/hooks/hook_registry.py +15 -27
  8. autobyteus/agent/input_processor/base_user_input_processor.py +17 -1
  9. autobyteus/agent/input_processor/processor_registry.py +15 -27
  10. autobyteus/agent/llm_response_processor/base_processor.py +17 -1
  11. autobyteus/agent/llm_response_processor/processor_registry.py +15 -24
  12. autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +14 -0
  13. autobyteus/agent/message/agent_input_user_message.py +15 -2
  14. autobyteus/agent/message/send_message_to.py +1 -1
  15. autobyteus/agent/processor_option.py +17 -0
  16. autobyteus/agent/sender_type.py +1 -0
  17. autobyteus/agent/system_prompt_processor/base_processor.py +17 -1
  18. autobyteus/agent/system_prompt_processor/processor_registry.py +15 -27
  19. autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +10 -0
  20. autobyteus/agent/tool_execution_result_processor/base_processor.py +17 -1
  21. autobyteus/agent/tool_execution_result_processor/processor_registry.py +15 -1
  22. autobyteus/agent/workspace/base_workspace.py +1 -1
  23. autobyteus/agent/workspace/workspace_definition.py +1 -1
  24. autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +1 -1
  25. autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +2 -2
  26. autobyteus/agent_team/task_notification/__init__.py +4 -0
  27. autobyteus/agent_team/task_notification/activation_policy.py +70 -0
  28. autobyteus/agent_team/task_notification/system_event_driven_agent_task_notifier.py +56 -122
  29. autobyteus/agent_team/task_notification/task_activator.py +66 -0
  30. autobyteus/cli/agent_team_tui/state.py +17 -20
  31. autobyteus/cli/agent_team_tui/widgets/focus_pane.py +1 -1
  32. autobyteus/cli/agent_team_tui/widgets/task_board_panel.py +1 -1
  33. autobyteus/events/event_types.py +2 -2
  34. autobyteus/llm/api/gemini_llm.py +45 -54
  35. autobyteus/llm/api/qwen_llm.py +25 -0
  36. autobyteus/llm/autobyteus_provider.py +8 -2
  37. autobyteus/llm/llm_factory.py +16 -0
  38. autobyteus/multimedia/audio/api/autobyteus_audio_client.py +4 -1
  39. autobyteus/multimedia/audio/api/gemini_audio_client.py +84 -153
  40. autobyteus/multimedia/audio/audio_client_factory.py +47 -22
  41. autobyteus/multimedia/audio/audio_model.py +13 -6
  42. autobyteus/multimedia/audio/autobyteus_audio_provider.py +8 -2
  43. autobyteus/multimedia/audio/base_audio_client.py +3 -1
  44. autobyteus/multimedia/image/api/autobyteus_image_client.py +12 -5
  45. autobyteus/multimedia/image/api/gemini_image_client.py +72 -130
  46. autobyteus/multimedia/image/api/openai_image_client.py +4 -2
  47. autobyteus/multimedia/image/autobyteus_image_provider.py +8 -2
  48. autobyteus/multimedia/image/base_image_client.py +6 -2
  49. autobyteus/multimedia/image/image_client_factory.py +20 -19
  50. autobyteus/multimedia/image/image_model.py +13 -6
  51. autobyteus/multimedia/providers.py +1 -0
  52. autobyteus/task_management/__init__.py +9 -10
  53. autobyteus/task_management/base_task_board.py +14 -6
  54. autobyteus/task_management/converters/__init__.py +0 -2
  55. autobyteus/task_management/converters/task_board_converter.py +7 -16
  56. autobyteus/task_management/events.py +6 -6
  57. autobyteus/task_management/in_memory_task_board.py +48 -38
  58. autobyteus/task_management/schemas/__init__.py +2 -2
  59. autobyteus/task_management/schemas/{plan_definition.py → task_definition.py} +5 -6
  60. autobyteus/task_management/schemas/task_status_report.py +0 -1
  61. autobyteus/task_management/task.py +60 -0
  62. autobyteus/task_management/tools/__init__.py +4 -2
  63. autobyteus/task_management/tools/get_my_tasks.py +80 -0
  64. autobyteus/task_management/tools/get_task_board_status.py +3 -3
  65. autobyteus/task_management/tools/publish_task.py +77 -0
  66. autobyteus/task_management/tools/publish_tasks.py +74 -0
  67. autobyteus/task_management/tools/update_task_status.py +5 -5
  68. autobyteus/tools/__init__.py +3 -1
  69. autobyteus/tools/base_tool.py +4 -4
  70. autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +1 -1
  71. autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +1 -1
  72. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +1 -1
  73. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +1 -1
  74. autobyteus/tools/browser/standalone/navigate_to.py +1 -1
  75. autobyteus/tools/browser/standalone/web_page_pdf_generator.py +1 -1
  76. autobyteus/tools/browser/standalone/webpage_image_downloader.py +1 -1
  77. autobyteus/tools/browser/standalone/webpage_reader.py +1 -1
  78. autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +1 -1
  79. autobyteus/tools/functional_tool.py +1 -1
  80. autobyteus/tools/google_search.py +1 -1
  81. autobyteus/tools/image_downloader.py +1 -1
  82. autobyteus/tools/mcp/factory.py +1 -1
  83. autobyteus/tools/mcp/schema_mapper.py +1 -1
  84. autobyteus/tools/mcp/tool.py +1 -1
  85. autobyteus/tools/multimedia/__init__.py +2 -0
  86. autobyteus/tools/multimedia/audio_tools.py +10 -20
  87. autobyteus/tools/multimedia/image_tools.py +21 -22
  88. autobyteus/tools/multimedia/media_reader_tool.py +117 -0
  89. autobyteus/tools/pydantic_schema_converter.py +1 -1
  90. autobyteus/tools/registry/tool_definition.py +1 -1
  91. autobyteus/tools/timer.py +1 -1
  92. autobyteus/tools/tool_meta.py +1 -1
  93. autobyteus/tools/usage/formatters/default_json_example_formatter.py +1 -1
  94. autobyteus/tools/usage/formatters/default_xml_example_formatter.py +1 -1
  95. autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +59 -3
  96. autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +1 -1
  97. autobyteus/tools/usage/formatters/google_json_example_formatter.py +1 -1
  98. autobyteus/tools/usage/formatters/openai_json_example_formatter.py +1 -1
  99. autobyteus/{tools → utils}/parameter_schema.py +1 -1
  100. {autobyteus-1.1.7.dist-info → autobyteus-1.1.9.dist-info}/METADATA +2 -2
  101. {autobyteus-1.1.7.dist-info → autobyteus-1.1.9.dist-info}/RECORD +105 -99
  102. examples/run_poem_writer.py +1 -1
  103. autobyteus/task_management/converters/task_plan_converter.py +0 -48
  104. autobyteus/task_management/task_plan.py +0 -110
  105. autobyteus/task_management/tools/publish_task_plan.py +0 -101
  106. {autobyteus-1.1.7.dist-info → autobyteus-1.1.9.dist-info}/WHEEL +0 -0
  107. {autobyteus-1.1.7.dist-info → autobyteus-1.1.9.dist-info}/licenses/LICENSE +0 -0
  108. {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 a list of names of all registered LLM response processor definitions.
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.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
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
@@ -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"<{self.__class__.__name__}>"
64
+ return f"&lt;{self.__class__.__name__}&gt;"
@@ -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 a list of names of all registered system prompt processor definitions.
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"<{self.__class__.__name__}>"
62
+ return f"&lt;{self.__class__.__name__}&gt;"
@@ -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 a list of names of all registered processor definitions.
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.tools.parameter_schema import ParameterSchema
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.tools.parameter_schema import ParameterSchema
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.TASK_BOARD_PLAN_PUBLISHED, listener=notifier.handle_and_publish_task_board_event)
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 TaskPlanPublishedEvent, TaskStatusUpdatedEvent
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[TaskPlanPublishedEvent, TaskStatusUpdatedEvent]
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