ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s

This commit is contained in:
2026-08-20 13:12:50 +00:00
commit b119135836
10275 changed files with 3284984 additions and 0 deletions
@@ -0,0 +1,170 @@
# coding: utf-8
# Copyright (c) 2025 inclusionAI.
import functools
import inspect
import logging
from typing import Dict, Any, Callable, Optional, Union, Awaitable
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger("callback_registry")
class CallbackRegistry:
"""Callback function registry, used to manage and execute callback functions"""
# Registry for storing decorated callback functions
_registry: Dict[str, Callable] = {}
@classmethod
def register(cls, key_name: str, func: Callable) -> Callable:
"""Register callback function to the registry
Args:
key_name: Unique identifier for the callback function
func: Callback function to register
Returns:
Registered callback function
"""
# Check if a callback function with the same key_name already exists
if key_name in cls._registry:
existing_func = cls._registry[key_name]
logger.warning(
f"Callback function '{key_name}' already exists and will be overwritten! "
f"Original function: {existing_func.__name__ if hasattr(existing_func, '__name__') else str(existing_func)}, "
f"New function: {func.__name__ if hasattr(func, '__name__') else str(func)}"
)
cls._registry[key_name] = func
return func
@classmethod
def get(cls, key_name: str) -> Optional[Callable]:
"""Get registered callback function by key_name
Args:
key_name: Unique identifier for the callback function
Returns:
Registered callback function, or None if not found
"""
return cls._registry.get(key_name)
@classmethod
async def execute(
cls,
key_name: str,
tool: Any,
args: Dict[str, Any],
tool_context: Any,
tool_response: Optional[Dict[str, Any]] = None
) -> Optional[Dict[str, Any]]:
"""Execute registered callback function
Args:
key_name: Unique identifier for the callback function
tool: Tool object
args: Tool arguments
tool_context: Tool context
tool_response: Tool response (for post-callbacks)
Returns:
Return value of the callback function, or None if the callback function doesn't exist
"""
callback = cls.get(key_name)
if not callback:
return None
# Determine parameters based on callback type
if tool_response is not None:
# Post-callback
result = callback(tool, args, tool_context, tool_response)
else:
# Pre-callback
result = callback(tool, args, tool_context)
# Handle asynchronous callbacks
if inspect.isawaitable(result):
result = await result
return result
@classmethod
def list(cls) -> Dict[str, str]:
"""List all registered callback functions
Returns:
Dictionary containing callback function names and descriptions
"""
return {
key: func.__name__ if hasattr(func, '__name__') else str(func)
for key, func in cls._registry.items()
}
def reg_callback(key_name: str):
"""Decorator for registering callback functions
Args:
key_name: Unique identifier for the callback function
Returns:
Decorator function
"""
def decorator(func):
# Register function to the global registry
CallbackRegistry.register(key_name, func)
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
return decorator
# For backward compatibility, keep these functions
def get_callback(key_name: str) -> Optional[Callable]:
"""Get registered callback function by key_name
Args:
key_name: Unique identifier for the callback function
Returns:
Registered callback function, or None if not found
"""
return CallbackRegistry.get(key_name)
async def execute_callback(
key_name: str,
tool: Any,
args: Dict[str, Any],
tool_context: Any,
tool_response: Optional[Dict[str, Any]] = None
) -> Optional[Dict[str, Any]]:
"""Execute registered callback function
Args:
key_name: Unique identifier for the callback function
tool: Tool object
args: Tool arguments
tool_context: Tool context
tool_response: Tool response (for post-callbacks)
Returns:
Return value of the callback function, or None if the callback function doesn't exist
"""
return await CallbackRegistry.execute(key_name, tool, args, tool_context, tool_response)
def list_callbacks() -> Dict[str, str]:
"""List all registered callback functions
Returns:
Dictionary containing callback function names and descriptions
"""
return CallbackRegistry.list()
@@ -0,0 +1,84 @@
from typing import Tuple
from aworld.runners.callback.decorator import CallbackRegistry
from aworld.runners.handler.base import DefaultHandler
from aworld.core.common import Observation, CallbackItem
from aworld.core.event.base import Message, Constants
from aworld.logs.util import logger
from aworld.runners.state_manager import RuntimeStateManager, HandleResult, RunNodeStatus
class ToolCallbackHandler(DefaultHandler):
def __init__(self, runner):
self.runner = runner
async def handle(self, message):
if message.category != Constants.TOOL_CALLBACK:
return
logger.info(f"-------ToolCallbackHandler start handle message----: {message}")
self.context = message.context
observation = None
state_mng = RuntimeStateManager.instance()
if not state_mng:
logger.eror("-------ToolCallbackHandler state_mng is None----")
return
try:
payload = message.payload
if not payload:
state_mng.run_failed(message.id, "callback failed", [])
return
if isinstance(payload, CallbackItem):
observation = payload.data[0] if isinstance(payload.data, Tuple) else payload.data
elif isinstance(payload, Tuple) and isinstance(payload[0], Observation):
observation=payload[0]
if not isinstance(observation, Observation):
state_mng.run_failed(message.id, "callback failed", [])
return
if not observation.action_result:
state_mng.run_failed(message.id, "callback failed", [])
return
results = []
for res in observation.action_result:
success = False
result = HandleResult(
result=Message(payload=None,
category=Constants.TOOL_CALLBACK,
sender=self.name(),
session_id=message.context.session_id,
headers={"context": message.context}),
status=RunNodeStatus.FAILED
)
if not res or not res.content or not res.tool_name or not res.action_name:
results.append(result)
continue
callback_func = CallbackRegistry.get(res.tool_name + "__" + res.action_name)
if not callback_func:
result.status = RunNodeStatus.SUCCESS
results.append(result)
continue
callback_res = callback_func(res)
if not callback_res or callback_res.success is False:
results.append(result)
continue
result.status = RunNodeStatus.SUCCESS
result.result.payload = callback_res
results.append(result)
state_mng.run_succeed(message.id, "test callback succ", results)
except Exception as e:
# todo
logger.warning(f"ToolCallbackHandler Failed to parse payload: {e}")
state_mng.run_failed(message.id, "callback failed", [])
finally:
yield Message(
category=Constants.OUTPUT,
payload=None,
sender=self.name(),
session_id=message.session_id,
headers={"context": self.context}
)
return