base_agent/uas/action/registry/action_registry.py

159 lines
6.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""
Action 工厂注册表
─────────────────────────────────────────────────────────────────
将 ActionType → handler 函数的映射集中管理
支持:
- 内置 handler 自动注册
- 运行时动态注册/覆盖 handler
- 通过 create() 工厂方法快速创建 Action 实例
─────────────────────────────────────────────────────────────────
"""
from __future__ import annotations
import logging
import threading
from typing import Callable, Dict, List, Optional, Union
from uas.action.action_model import Action, make_action
from uas.action.action_type import ActionType
logger = logging.getLogger(__name__)
class ActionFactory:
"""
Action 工厂(单例)
─────────────────────────────────────────────────────────────
使用方式:
factory = ActionFactory.instance()
# 注册自定义 handler
factory.register(ActionType.CAPTURE_PHOTO, my_photo_handler)
# 创建 Action 实例(自动绑定 handler
action = factory.create(
ActionType.CAPTURE_PHOTO,
source = "camera-01",
resolution = "4K",
format = "jpg",
)
─────────────────────────────────────────────────────────────
"""
_instance = None
_lock = threading.Lock()
@classmethod
def instance(cls) -> "ActionFactory":
if cls._instance is None:
cls._instance = cls()
return cls._instance
def __init__(self):
# { type_key: handler_fn }
self._handlers: Dict[str, Callable] = {}
self._init_builtin()
def _init_builtin(self):
"""自动注册所有内置 handler"""
from uas.action.actions.builtin_actions import BUILTIN_HANDLERS
for action_type, handler in BUILTIN_HANDLERS.items():
self.register(action_type, handler)
logger.info(f"✅ ActionFactory 初始化,内置 handler={len(self._handlers)}")
# ── 注册 ──────────────────────────────────────────────────────
def register(
self,
action_type: Union[ActionType, str],
handler: Callable,
override: bool = True,
) -> None:
"""
注册 Action 处理函数
:param action_type: ActionType 枚举 或 自定义字符串
:param handler: fn(action: Action, ctx: ActionContext) -> Any
:param override: True=允许覆盖已有 handler
"""
key = action_type.value if isinstance(action_type, ActionType) else str(action_type)
with self._lock:
if key in self._handlers and not override:
logger.warning(f"handler 已存在且 override=False跳过: {key}")
return
self._handlers[key] = handler
logger.info(f"注册 handler: {key} -> {handler.__name__}")
def unregister(self, action_type: Union[ActionType, str]) -> bool:
"""注销 handler"""
key = action_type.value if isinstance(action_type, ActionType) else str(action_type)
with self._lock:
if key in self._handlers:
del self._handlers[key]
logger.info(f"注销 handler: {key}")
return True
return False
def get_handler(self, action_type: Union[ActionType, str]) -> Optional[Callable]:
"""获取指定类型的 handler"""
key = action_type.value if isinstance(action_type, ActionType) else str(action_type)
return self._handlers.get(key)
def has_handler(self, action_type: Union[ActionType, str]) -> bool:
key = action_type.value if isinstance(action_type, ActionType) else str(action_type)
return key in self._handlers
def registered_types(self) -> List[str]:
return list(self._handlers.keys())
# ── 工厂创建 ──────────────────────────────────────────────────
def create(
self,
action_type: Union[ActionType, str],
source: str = "system",
priority: int = 0,
handler: Optional[Callable] = None,
**params
) -> Action:
"""
工厂方法:创建并自动绑定 handler 的 Action 实例
:param action_type: 行为类型
:param source: 触发来源
:param priority: 执行优先级
:param handler: 若指定则覆盖注册表中的 handler
:param params: 传递给 Action 的业务参数
:return: Action 实例
"""
resolved_handler = handler or self.get_handler(action_type)
if resolved_handler is None:
logger.warning(f"未找到 handler: {action_type},将使用空处理器")
resolved_handler = _noop_handler
action = make_action(
action_type = action_type,
handler = resolved_handler,
source = source,
priority = priority,
**params,
)
logger.debug(f"创建 Action: {action}")
return action
def create_batch(self, specs: List[dict]) -> List[Action]:
"""
批量创建 Action
:param specs: [{"action_type": ..., "source": ..., **params}, ...]
"""
return [self.create(**spec) for spec in specs]
def _noop_handler(action, ctx):
"""空处理器(未注册 handler 时的占位)"""
logger.warning(f"[noop] Action [{action.type_key}] 无处理器,跳过执行")
return None
# 全局工厂实例
action_factory = ActionFactory.instance()