codepp 0.0.437__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.
- code_puppy/__init__.py +10 -0
- code_puppy/__main__.py +10 -0
- code_puppy/agents/__init__.py +31 -0
- code_puppy/agents/agent_c_reviewer.py +155 -0
- code_puppy/agents/agent_code_puppy.py +117 -0
- code_puppy/agents/agent_code_reviewer.py +90 -0
- code_puppy/agents/agent_cpp_reviewer.py +132 -0
- code_puppy/agents/agent_creator_agent.py +638 -0
- code_puppy/agents/agent_golang_reviewer.py +151 -0
- code_puppy/agents/agent_helios.py +124 -0
- code_puppy/agents/agent_javascript_reviewer.py +160 -0
- code_puppy/agents/agent_manager.py +742 -0
- code_puppy/agents/agent_pack_leader.py +385 -0
- code_puppy/agents/agent_planning.py +165 -0
- code_puppy/agents/agent_python_programmer.py +169 -0
- code_puppy/agents/agent_python_reviewer.py +90 -0
- code_puppy/agents/agent_qa_expert.py +163 -0
- code_puppy/agents/agent_qa_kitten.py +208 -0
- code_puppy/agents/agent_scheduler.py +121 -0
- code_puppy/agents/agent_security_auditor.py +181 -0
- code_puppy/agents/agent_terminal_qa.py +323 -0
- code_puppy/agents/agent_typescript_reviewer.py +166 -0
- code_puppy/agents/base_agent.py +2156 -0
- code_puppy/agents/event_stream_handler.py +348 -0
- code_puppy/agents/json_agent.py +202 -0
- code_puppy/agents/pack/__init__.py +34 -0
- code_puppy/agents/pack/bloodhound.py +304 -0
- code_puppy/agents/pack/husky.py +327 -0
- code_puppy/agents/pack/retriever.py +393 -0
- code_puppy/agents/pack/shepherd.py +348 -0
- code_puppy/agents/pack/terrier.py +287 -0
- code_puppy/agents/pack/watchdog.py +367 -0
- code_puppy/agents/prompt_reviewer.py +145 -0
- code_puppy/agents/subagent_stream_handler.py +276 -0
- code_puppy/api/__init__.py +13 -0
- code_puppy/api/app.py +169 -0
- code_puppy/api/main.py +21 -0
- code_puppy/api/pty_manager.py +453 -0
- code_puppy/api/routers/__init__.py +12 -0
- code_puppy/api/routers/agents.py +36 -0
- code_puppy/api/routers/commands.py +217 -0
- code_puppy/api/routers/config.py +75 -0
- code_puppy/api/routers/sessions.py +234 -0
- code_puppy/api/templates/terminal.html +361 -0
- code_puppy/api/websocket.py +154 -0
- code_puppy/callbacks.py +692 -0
- code_puppy/chatgpt_codex_client.py +338 -0
- code_puppy/claude_cache_client.py +672 -0
- code_puppy/cli_runner.py +1073 -0
- code_puppy/command_line/__init__.py +1 -0
- code_puppy/command_line/add_model_menu.py +1092 -0
- code_puppy/command_line/agent_menu.py +662 -0
- code_puppy/command_line/attachments.py +395 -0
- code_puppy/command_line/autosave_menu.py +704 -0
- code_puppy/command_line/clipboard.py +527 -0
- code_puppy/command_line/colors_menu.py +532 -0
- code_puppy/command_line/command_handler.py +293 -0
- code_puppy/command_line/command_registry.py +150 -0
- code_puppy/command_line/config_commands.py +719 -0
- code_puppy/command_line/core_commands.py +867 -0
- code_puppy/command_line/diff_menu.py +865 -0
- code_puppy/command_line/file_path_completion.py +73 -0
- code_puppy/command_line/load_context_completion.py +52 -0
- code_puppy/command_line/mcp/__init__.py +10 -0
- code_puppy/command_line/mcp/base.py +32 -0
- code_puppy/command_line/mcp/catalog_server_installer.py +175 -0
- code_puppy/command_line/mcp/custom_server_form.py +688 -0
- code_puppy/command_line/mcp/custom_server_installer.py +195 -0
- code_puppy/command_line/mcp/edit_command.py +148 -0
- code_puppy/command_line/mcp/handler.py +138 -0
- code_puppy/command_line/mcp/help_command.py +147 -0
- code_puppy/command_line/mcp/install_command.py +214 -0
- code_puppy/command_line/mcp/install_menu.py +705 -0
- code_puppy/command_line/mcp/list_command.py +94 -0
- code_puppy/command_line/mcp/logs_command.py +235 -0
- code_puppy/command_line/mcp/remove_command.py +82 -0
- code_puppy/command_line/mcp/restart_command.py +100 -0
- code_puppy/command_line/mcp/search_command.py +123 -0
- code_puppy/command_line/mcp/start_all_command.py +135 -0
- code_puppy/command_line/mcp/start_command.py +117 -0
- code_puppy/command_line/mcp/status_command.py +184 -0
- code_puppy/command_line/mcp/stop_all_command.py +112 -0
- code_puppy/command_line/mcp/stop_command.py +80 -0
- code_puppy/command_line/mcp/test_command.py +107 -0
- code_puppy/command_line/mcp/utils.py +129 -0
- code_puppy/command_line/mcp/wizard_utils.py +334 -0
- code_puppy/command_line/mcp_completion.py +174 -0
- code_puppy/command_line/model_picker_completion.py +197 -0
- code_puppy/command_line/model_settings_menu.py +932 -0
- code_puppy/command_line/motd.py +96 -0
- code_puppy/command_line/onboarding_slides.py +179 -0
- code_puppy/command_line/onboarding_wizard.py +342 -0
- code_puppy/command_line/pin_command_completion.py +329 -0
- code_puppy/command_line/prompt_toolkit_completion.py +846 -0
- code_puppy/command_line/session_commands.py +302 -0
- code_puppy/command_line/shell_passthrough.py +145 -0
- code_puppy/command_line/skills_completion.py +160 -0
- code_puppy/command_line/uc_menu.py +893 -0
- code_puppy/command_line/utils.py +93 -0
- code_puppy/command_line/wiggum_state.py +78 -0
- code_puppy/config.py +1770 -0
- code_puppy/error_logging.py +134 -0
- code_puppy/gemini_code_assist.py +385 -0
- code_puppy/gemini_model.py +754 -0
- code_puppy/hook_engine/README.md +105 -0
- code_puppy/hook_engine/__init__.py +21 -0
- code_puppy/hook_engine/aliases.py +155 -0
- code_puppy/hook_engine/engine.py +221 -0
- code_puppy/hook_engine/executor.py +296 -0
- code_puppy/hook_engine/matcher.py +156 -0
- code_puppy/hook_engine/models.py +240 -0
- code_puppy/hook_engine/registry.py +106 -0
- code_puppy/hook_engine/validator.py +144 -0
- code_puppy/http_utils.py +361 -0
- code_puppy/keymap.py +128 -0
- code_puppy/main.py +10 -0
- code_puppy/mcp_/__init__.py +66 -0
- code_puppy/mcp_/async_lifecycle.py +286 -0
- code_puppy/mcp_/blocking_startup.py +469 -0
- code_puppy/mcp_/captured_stdio_server.py +275 -0
- code_puppy/mcp_/circuit_breaker.py +290 -0
- code_puppy/mcp_/config_wizard.py +507 -0
- code_puppy/mcp_/dashboard.py +308 -0
- code_puppy/mcp_/error_isolation.py +407 -0
- code_puppy/mcp_/examples/retry_example.py +226 -0
- code_puppy/mcp_/health_monitor.py +589 -0
- code_puppy/mcp_/managed_server.py +428 -0
- code_puppy/mcp_/manager.py +807 -0
- code_puppy/mcp_/mcp_logs.py +224 -0
- code_puppy/mcp_/registry.py +451 -0
- code_puppy/mcp_/retry_manager.py +337 -0
- code_puppy/mcp_/server_registry_catalog.py +1126 -0
- code_puppy/mcp_/status_tracker.py +355 -0
- code_puppy/mcp_/system_tools.py +209 -0
- code_puppy/mcp_prompts/__init__.py +1 -0
- code_puppy/mcp_prompts/hook_creator.py +103 -0
- code_puppy/messaging/__init__.py +255 -0
- code_puppy/messaging/bus.py +613 -0
- code_puppy/messaging/commands.py +167 -0
- code_puppy/messaging/markdown_patches.py +57 -0
- code_puppy/messaging/message_queue.py +361 -0
- code_puppy/messaging/messages.py +569 -0
- code_puppy/messaging/queue_console.py +271 -0
- code_puppy/messaging/renderers.py +311 -0
- code_puppy/messaging/rich_renderer.py +1158 -0
- code_puppy/messaging/spinner/__init__.py +83 -0
- code_puppy/messaging/spinner/console_spinner.py +240 -0
- code_puppy/messaging/spinner/spinner_base.py +95 -0
- code_puppy/messaging/subagent_console.py +460 -0
- code_puppy/model_factory.py +848 -0
- code_puppy/model_switching.py +63 -0
- code_puppy/model_utils.py +168 -0
- code_puppy/models.json +174 -0
- code_puppy/models_dev_api.json +1 -0
- code_puppy/models_dev_parser.py +592 -0
- code_puppy/plugins/__init__.py +186 -0
- code_puppy/plugins/agent_skills/__init__.py +22 -0
- code_puppy/plugins/agent_skills/config.py +175 -0
- code_puppy/plugins/agent_skills/discovery.py +136 -0
- code_puppy/plugins/agent_skills/downloader.py +392 -0
- code_puppy/plugins/agent_skills/installer.py +22 -0
- code_puppy/plugins/agent_skills/metadata.py +219 -0
- code_puppy/plugins/agent_skills/prompt_builder.py +60 -0
- code_puppy/plugins/agent_skills/register_callbacks.py +241 -0
- code_puppy/plugins/agent_skills/remote_catalog.py +322 -0
- code_puppy/plugins/agent_skills/skill_catalog.py +257 -0
- code_puppy/plugins/agent_skills/skills_install_menu.py +664 -0
- code_puppy/plugins/agent_skills/skills_menu.py +781 -0
- code_puppy/plugins/antigravity_oauth/__init__.py +10 -0
- code_puppy/plugins/antigravity_oauth/accounts.py +406 -0
- code_puppy/plugins/antigravity_oauth/antigravity_model.py +706 -0
- code_puppy/plugins/antigravity_oauth/config.py +42 -0
- code_puppy/plugins/antigravity_oauth/constants.py +133 -0
- code_puppy/plugins/antigravity_oauth/oauth.py +478 -0
- code_puppy/plugins/antigravity_oauth/register_callbacks.py +518 -0
- code_puppy/plugins/antigravity_oauth/storage.py +288 -0
- code_puppy/plugins/antigravity_oauth/test_plugin.py +319 -0
- code_puppy/plugins/antigravity_oauth/token.py +167 -0
- code_puppy/plugins/antigravity_oauth/transport.py +863 -0
- code_puppy/plugins/antigravity_oauth/utils.py +168 -0
- code_puppy/plugins/chatgpt_oauth/__init__.py +8 -0
- code_puppy/plugins/chatgpt_oauth/config.py +52 -0
- code_puppy/plugins/chatgpt_oauth/oauth_flow.py +329 -0
- code_puppy/plugins/chatgpt_oauth/register_callbacks.py +176 -0
- code_puppy/plugins/chatgpt_oauth/test_plugin.py +301 -0
- code_puppy/plugins/chatgpt_oauth/utils.py +523 -0
- code_puppy/plugins/claude_code_hooks/__init__.py +1 -0
- code_puppy/plugins/claude_code_hooks/config.py +137 -0
- code_puppy/plugins/claude_code_hooks/register_callbacks.py +175 -0
- code_puppy/plugins/claude_code_oauth/README.md +167 -0
- code_puppy/plugins/claude_code_oauth/SETUP.md +93 -0
- code_puppy/plugins/claude_code_oauth/__init__.py +25 -0
- code_puppy/plugins/claude_code_oauth/config.py +52 -0
- code_puppy/plugins/claude_code_oauth/register_callbacks.py +453 -0
- code_puppy/plugins/claude_code_oauth/test_plugin.py +283 -0
- code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +241 -0
- code_puppy/plugins/claude_code_oauth/utils.py +640 -0
- code_puppy/plugins/customizable_commands/__init__.py +0 -0
- code_puppy/plugins/customizable_commands/register_callbacks.py +152 -0
- code_puppy/plugins/example_custom_command/README.md +280 -0
- code_puppy/plugins/example_custom_command/register_callbacks.py +51 -0
- code_puppy/plugins/file_permission_handler/__init__.py +4 -0
- code_puppy/plugins/file_permission_handler/register_callbacks.py +470 -0
- code_puppy/plugins/frontend_emitter/__init__.py +25 -0
- code_puppy/plugins/frontend_emitter/emitter.py +121 -0
- code_puppy/plugins/frontend_emitter/register_callbacks.py +261 -0
- code_puppy/plugins/hook_creator/__init__.py +1 -0
- code_puppy/plugins/hook_creator/register_callbacks.py +33 -0
- code_puppy/plugins/hook_manager/__init__.py +1 -0
- code_puppy/plugins/hook_manager/config.py +290 -0
- code_puppy/plugins/hook_manager/hooks_menu.py +564 -0
- code_puppy/plugins/hook_manager/register_callbacks.py +227 -0
- code_puppy/plugins/oauth_puppy_html.py +228 -0
- code_puppy/plugins/scheduler/__init__.py +1 -0
- code_puppy/plugins/scheduler/register_callbacks.py +88 -0
- code_puppy/plugins/scheduler/scheduler_menu.py +522 -0
- code_puppy/plugins/scheduler/scheduler_wizard.py +341 -0
- code_puppy/plugins/shell_safety/__init__.py +6 -0
- code_puppy/plugins/shell_safety/agent_shell_safety.py +69 -0
- code_puppy/plugins/shell_safety/command_cache.py +156 -0
- code_puppy/plugins/shell_safety/register_callbacks.py +202 -0
- code_puppy/plugins/synthetic_status/__init__.py +1 -0
- code_puppy/plugins/synthetic_status/register_callbacks.py +132 -0
- code_puppy/plugins/synthetic_status/status_api.py +147 -0
- code_puppy/plugins/universal_constructor/__init__.py +13 -0
- code_puppy/plugins/universal_constructor/models.py +138 -0
- code_puppy/plugins/universal_constructor/register_callbacks.py +47 -0
- code_puppy/plugins/universal_constructor/registry.py +302 -0
- code_puppy/plugins/universal_constructor/sandbox.py +584 -0
- code_puppy/prompts/antigravity_system_prompt.md +1 -0
- code_puppy/pydantic_patches.py +356 -0
- code_puppy/reopenable_async_client.py +232 -0
- code_puppy/round_robin_model.py +150 -0
- code_puppy/scheduler/__init__.py +41 -0
- code_puppy/scheduler/__main__.py +9 -0
- code_puppy/scheduler/cli.py +118 -0
- code_puppy/scheduler/config.py +126 -0
- code_puppy/scheduler/daemon.py +280 -0
- code_puppy/scheduler/executor.py +155 -0
- code_puppy/scheduler/platform.py +19 -0
- code_puppy/scheduler/platform_unix.py +22 -0
- code_puppy/scheduler/platform_win.py +32 -0
- code_puppy/session_storage.py +338 -0
- code_puppy/status_display.py +257 -0
- code_puppy/summarization_agent.py +176 -0
- code_puppy/terminal_utils.py +418 -0
- code_puppy/tools/__init__.py +501 -0
- code_puppy/tools/agent_tools.py +603 -0
- code_puppy/tools/ask_user_question/__init__.py +26 -0
- code_puppy/tools/ask_user_question/constants.py +73 -0
- code_puppy/tools/ask_user_question/demo_tui.py +55 -0
- code_puppy/tools/ask_user_question/handler.py +232 -0
- code_puppy/tools/ask_user_question/models.py +304 -0
- code_puppy/tools/ask_user_question/registration.py +26 -0
- code_puppy/tools/ask_user_question/renderers.py +309 -0
- code_puppy/tools/ask_user_question/terminal_ui.py +329 -0
- code_puppy/tools/ask_user_question/theme.py +155 -0
- code_puppy/tools/ask_user_question/tui_loop.py +423 -0
- code_puppy/tools/browser/__init__.py +37 -0
- code_puppy/tools/browser/browser_control.py +289 -0
- code_puppy/tools/browser/browser_interactions.py +545 -0
- code_puppy/tools/browser/browser_locators.py +640 -0
- code_puppy/tools/browser/browser_manager.py +378 -0
- code_puppy/tools/browser/browser_navigation.py +251 -0
- code_puppy/tools/browser/browser_screenshot.py +179 -0
- code_puppy/tools/browser/browser_scripts.py +462 -0
- code_puppy/tools/browser/browser_workflows.py +221 -0
- code_puppy/tools/browser/chromium_terminal_manager.py +259 -0
- code_puppy/tools/browser/terminal_command_tools.py +534 -0
- code_puppy/tools/browser/terminal_screenshot_tools.py +552 -0
- code_puppy/tools/browser/terminal_tools.py +525 -0
- code_puppy/tools/command_runner.py +1346 -0
- code_puppy/tools/common.py +1409 -0
- code_puppy/tools/display.py +84 -0
- code_puppy/tools/file_modifications.py +886 -0
- code_puppy/tools/file_operations.py +802 -0
- code_puppy/tools/scheduler_tools.py +412 -0
- code_puppy/tools/skills_tools.py +244 -0
- code_puppy/tools/subagent_context.py +158 -0
- code_puppy/tools/tools_content.py +51 -0
- code_puppy/tools/universal_constructor.py +889 -0
- code_puppy/uvx_detection.py +242 -0
- code_puppy/version_checker.py +82 -0
- codepp-0.0.437.dist-info/METADATA +766 -0
- codepp-0.0.437.dist-info/RECORD +288 -0
- codepp-0.0.437.dist-info/WHEEL +4 -0
- codepp-0.0.437.dist-info/entry_points.txt +3 -0
- codepp-0.0.437.dist-info/licenses/LICENSE +21 -0
code_puppy/callbacks.py
ADDED
|
@@ -0,0 +1,692 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
import traceback
|
|
4
|
+
from typing import Any, Callable, Dict, List, Literal, Optional
|
|
5
|
+
|
|
6
|
+
PhaseType = Literal[
|
|
7
|
+
"startup",
|
|
8
|
+
"shutdown",
|
|
9
|
+
"invoke_agent",
|
|
10
|
+
"agent_exception",
|
|
11
|
+
"version_check",
|
|
12
|
+
"edit_file",
|
|
13
|
+
"create_file",
|
|
14
|
+
"replace_in_file",
|
|
15
|
+
"delete_snippet",
|
|
16
|
+
"delete_file",
|
|
17
|
+
"run_shell_command",
|
|
18
|
+
"load_model_config",
|
|
19
|
+
"load_models_config",
|
|
20
|
+
"load_prompt",
|
|
21
|
+
"agent_reload",
|
|
22
|
+
"custom_command",
|
|
23
|
+
"custom_command_help",
|
|
24
|
+
"file_permission",
|
|
25
|
+
"pre_tool_call",
|
|
26
|
+
"post_tool_call",
|
|
27
|
+
"stream_event",
|
|
28
|
+
"register_tools",
|
|
29
|
+
"register_agents",
|
|
30
|
+
"register_model_type",
|
|
31
|
+
"get_model_system_prompt",
|
|
32
|
+
"agent_run_start",
|
|
33
|
+
"agent_run_end",
|
|
34
|
+
"register_mcp_catalog_servers",
|
|
35
|
+
"register_browser_types",
|
|
36
|
+
"get_motd",
|
|
37
|
+
"register_model_providers",
|
|
38
|
+
"message_history_processor_start",
|
|
39
|
+
"message_history_processor_end",
|
|
40
|
+
]
|
|
41
|
+
CallbackFunc = Callable[..., Any]
|
|
42
|
+
|
|
43
|
+
_callbacks: Dict[PhaseType, List[CallbackFunc]] = {
|
|
44
|
+
"startup": [],
|
|
45
|
+
"shutdown": [],
|
|
46
|
+
"invoke_agent": [],
|
|
47
|
+
"agent_exception": [],
|
|
48
|
+
"version_check": [],
|
|
49
|
+
"edit_file": [],
|
|
50
|
+
"create_file": [],
|
|
51
|
+
"replace_in_file": [],
|
|
52
|
+
"delete_snippet": [],
|
|
53
|
+
"delete_file": [],
|
|
54
|
+
"run_shell_command": [],
|
|
55
|
+
"load_model_config": [],
|
|
56
|
+
"load_models_config": [],
|
|
57
|
+
"load_prompt": [],
|
|
58
|
+
"agent_reload": [],
|
|
59
|
+
"custom_command": [],
|
|
60
|
+
"custom_command_help": [],
|
|
61
|
+
"file_permission": [],
|
|
62
|
+
"pre_tool_call": [],
|
|
63
|
+
"post_tool_call": [],
|
|
64
|
+
"stream_event": [],
|
|
65
|
+
"register_tools": [],
|
|
66
|
+
"register_agents": [],
|
|
67
|
+
"register_model_type": [],
|
|
68
|
+
"get_model_system_prompt": [],
|
|
69
|
+
"agent_run_start": [],
|
|
70
|
+
"agent_run_end": [],
|
|
71
|
+
"register_mcp_catalog_servers": [],
|
|
72
|
+
"register_browser_types": [],
|
|
73
|
+
"get_motd": [],
|
|
74
|
+
"register_model_providers": [],
|
|
75
|
+
"message_history_processor_start": [],
|
|
76
|
+
"message_history_processor_end": [],
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
logger = logging.getLogger(__name__)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def register_callback(phase: PhaseType, func: CallbackFunc) -> None:
|
|
83
|
+
if phase not in _callbacks:
|
|
84
|
+
raise ValueError(
|
|
85
|
+
f"Unsupported phase: {phase}. Supported phases: {list(_callbacks.keys())}"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
if not callable(func):
|
|
89
|
+
raise TypeError(f"Callback must be callable, got {type(func)}")
|
|
90
|
+
|
|
91
|
+
# Prevent duplicate registration of the same callback function
|
|
92
|
+
# This can happen if plugins are accidentally loaded multiple times
|
|
93
|
+
if func in _callbacks[phase]:
|
|
94
|
+
logger.debug(
|
|
95
|
+
f"Callback {func.__name__} already registered for phase '{phase}', skipping"
|
|
96
|
+
)
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
_callbacks[phase].append(func)
|
|
100
|
+
logger.debug(f"Registered async callback {func.__name__} for phase '{phase}'")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def unregister_callback(phase: PhaseType, func: CallbackFunc) -> bool:
|
|
104
|
+
if phase not in _callbacks:
|
|
105
|
+
return False
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
_callbacks[phase].remove(func)
|
|
109
|
+
logger.debug(
|
|
110
|
+
f"Unregistered async callback {func.__name__} from phase '{phase}'"
|
|
111
|
+
)
|
|
112
|
+
return True
|
|
113
|
+
except ValueError:
|
|
114
|
+
return False
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def clear_callbacks(phase: Optional[PhaseType] = None) -> None:
|
|
118
|
+
if phase is None:
|
|
119
|
+
for p in _callbacks:
|
|
120
|
+
_callbacks[p].clear()
|
|
121
|
+
logger.debug("Cleared all async callbacks")
|
|
122
|
+
else:
|
|
123
|
+
if phase in _callbacks:
|
|
124
|
+
_callbacks[phase].clear()
|
|
125
|
+
logger.debug(f"Cleared async callbacks for phase '{phase}'")
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def get_callbacks(phase: PhaseType) -> List[CallbackFunc]:
|
|
129
|
+
return _callbacks.get(phase, []).copy()
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def count_callbacks(phase: Optional[PhaseType] = None) -> int:
|
|
133
|
+
if phase is None:
|
|
134
|
+
return sum(len(callbacks) for callbacks in _callbacks.values())
|
|
135
|
+
return len(_callbacks.get(phase, []))
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _trigger_callbacks_sync(phase: PhaseType, *args, **kwargs) -> List[Any]:
|
|
139
|
+
callbacks = get_callbacks(phase)
|
|
140
|
+
if not callbacks:
|
|
141
|
+
logger.debug(f"No callbacks registered for phase '{phase}'")
|
|
142
|
+
return []
|
|
143
|
+
|
|
144
|
+
results = []
|
|
145
|
+
for callback in callbacks:
|
|
146
|
+
try:
|
|
147
|
+
result = callback(*args, **kwargs)
|
|
148
|
+
# Handle async callbacks - if we get a coroutine, run it
|
|
149
|
+
if asyncio.iscoroutine(result):
|
|
150
|
+
# Try to get the running event loop
|
|
151
|
+
try:
|
|
152
|
+
asyncio.get_running_loop()
|
|
153
|
+
# We're in an async context already - this shouldn't happen for sync triggers
|
|
154
|
+
# but if it does, we can't use run_until_complete
|
|
155
|
+
logger.warning(
|
|
156
|
+
f"Async callback {callback.__name__} called from async context in sync trigger"
|
|
157
|
+
)
|
|
158
|
+
results.append(None)
|
|
159
|
+
continue
|
|
160
|
+
except RuntimeError:
|
|
161
|
+
# No running loop - we're in a sync/worker thread context
|
|
162
|
+
# Use asyncio.run() which is safe here since we're in an isolated thread
|
|
163
|
+
result = asyncio.run(result)
|
|
164
|
+
results.append(result)
|
|
165
|
+
logger.debug(f"Successfully executed callback {callback.__name__}")
|
|
166
|
+
except Exception as e:
|
|
167
|
+
logger.error(
|
|
168
|
+
f"Callback {callback.__name__} failed in phase '{phase}': {e}\n"
|
|
169
|
+
f"{traceback.format_exc()}"
|
|
170
|
+
)
|
|
171
|
+
results.append(None)
|
|
172
|
+
|
|
173
|
+
return results
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
async def _trigger_callbacks(phase: PhaseType, *args, **kwargs) -> List[Any]:
|
|
177
|
+
callbacks = get_callbacks(phase)
|
|
178
|
+
|
|
179
|
+
if not callbacks:
|
|
180
|
+
logger.debug(f"No callbacks registered for phase '{phase}'")
|
|
181
|
+
return []
|
|
182
|
+
|
|
183
|
+
logger.debug(f"Triggering {len(callbacks)} async callbacks for phase '{phase}'")
|
|
184
|
+
|
|
185
|
+
results = []
|
|
186
|
+
for callback in callbacks:
|
|
187
|
+
try:
|
|
188
|
+
result = callback(*args, **kwargs)
|
|
189
|
+
if asyncio.iscoroutine(result):
|
|
190
|
+
result = await result
|
|
191
|
+
results.append(result)
|
|
192
|
+
logger.debug(f"Successfully executed async callback {callback.__name__}")
|
|
193
|
+
except Exception as e:
|
|
194
|
+
logger.error(
|
|
195
|
+
f"Async callback {callback.__name__} failed in phase '{phase}': {e}\n"
|
|
196
|
+
f"{traceback.format_exc()}"
|
|
197
|
+
)
|
|
198
|
+
results.append(None)
|
|
199
|
+
|
|
200
|
+
return results
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
async def on_startup() -> List[Any]:
|
|
204
|
+
return await _trigger_callbacks("startup")
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
async def on_shutdown() -> List[Any]:
|
|
208
|
+
return await _trigger_callbacks("shutdown")
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
async def on_invoke_agent(*args, **kwargs) -> List[Any]:
|
|
212
|
+
return await _trigger_callbacks("invoke_agent", *args, **kwargs)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
async def on_agent_exception(exception: Exception, *args, **kwargs) -> List[Any]:
|
|
216
|
+
return await _trigger_callbacks("agent_exception", exception, *args, **kwargs)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
async def on_version_check(*args, **kwargs) -> List[Any]:
|
|
220
|
+
return await _trigger_callbacks("version_check", *args, **kwargs)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def on_load_model_config(*args, **kwargs) -> List[Any]:
|
|
224
|
+
return _trigger_callbacks_sync("load_model_config", *args, **kwargs)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def on_load_models_config() -> List[Any]:
|
|
228
|
+
"""Trigger callbacks to load additional model configurations.
|
|
229
|
+
|
|
230
|
+
Plugins can register callbacks that return a dict of model configurations
|
|
231
|
+
to be merged with the built-in models.json. Plugin models override built-in
|
|
232
|
+
models with the same name.
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
List of model config dicts from all registered callbacks.
|
|
236
|
+
"""
|
|
237
|
+
return _trigger_callbacks_sync("load_models_config")
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def on_edit_file(*args, **kwargs) -> Any:
|
|
241
|
+
return _trigger_callbacks_sync("edit_file", *args, **kwargs)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def on_create_file(*args, **kwargs) -> Any:
|
|
245
|
+
return _trigger_callbacks_sync("create_file", *args, **kwargs)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def on_replace_in_file(*args, **kwargs) -> Any:
|
|
249
|
+
return _trigger_callbacks_sync("replace_in_file", *args, **kwargs)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def on_delete_snippet(*args, **kwargs) -> Any:
|
|
253
|
+
return _trigger_callbacks_sync("delete_snippet", *args, **kwargs)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def on_delete_file(*args, **kwargs) -> Any:
|
|
257
|
+
return _trigger_callbacks_sync("delete_file", *args, **kwargs)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
async def on_run_shell_command(*args, **kwargs) -> Any:
|
|
261
|
+
return await _trigger_callbacks("run_shell_command", *args, **kwargs)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def on_agent_reload(*args, **kwargs) -> Any:
|
|
265
|
+
return _trigger_callbacks_sync("agent_reload", *args, **kwargs)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def on_load_prompt():
|
|
269
|
+
return _trigger_callbacks_sync("load_prompt")
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def on_custom_command_help() -> List[Any]:
|
|
273
|
+
"""Collect custom command help entries from plugins.
|
|
274
|
+
|
|
275
|
+
Each callback should return a list of tuples [(name, description), ...]
|
|
276
|
+
or a single tuple, or None. We'll flatten and sanitize results.
|
|
277
|
+
"""
|
|
278
|
+
return _trigger_callbacks_sync("custom_command_help")
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def on_custom_command(command: str, name: str) -> List[Any]:
|
|
282
|
+
"""Trigger custom command callbacks.
|
|
283
|
+
|
|
284
|
+
This allows plugins to register handlers for slash commands
|
|
285
|
+
that are not built into the core command handler.
|
|
286
|
+
|
|
287
|
+
Args:
|
|
288
|
+
command: The full command string (e.g., "/foo bar baz").
|
|
289
|
+
name: The primary command name without the leading slash (e.g., "foo").
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
Implementations may return:
|
|
293
|
+
- True if the command was handled (and no further action is needed)
|
|
294
|
+
- A string to be processed as user input by the caller
|
|
295
|
+
- None to indicate not handled
|
|
296
|
+
"""
|
|
297
|
+
return _trigger_callbacks_sync("custom_command", command, name)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def on_file_permission(
|
|
301
|
+
context: Any,
|
|
302
|
+
file_path: str,
|
|
303
|
+
operation: str,
|
|
304
|
+
preview: str | None = None,
|
|
305
|
+
message_group: str | None = None,
|
|
306
|
+
operation_data: Any = None,
|
|
307
|
+
) -> List[Any]:
|
|
308
|
+
"""Trigger file permission callbacks.
|
|
309
|
+
|
|
310
|
+
This allows plugins to register handlers for file permission checks
|
|
311
|
+
before file operations are performed.
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
context: The operation context
|
|
315
|
+
file_path: Path to the file being operated on
|
|
316
|
+
operation: Description of the operation
|
|
317
|
+
preview: Optional preview of changes (deprecated - use operation_data instead)
|
|
318
|
+
message_group: Optional message group
|
|
319
|
+
operation_data: Operation-specific data for preview generation (recommended)
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
List of boolean results from permission handlers.
|
|
323
|
+
Returns True if permission should be granted, False if denied.
|
|
324
|
+
"""
|
|
325
|
+
# For backward compatibility, if operation_data is provided, prefer it over preview
|
|
326
|
+
if operation_data is not None:
|
|
327
|
+
preview = None
|
|
328
|
+
return _trigger_callbacks_sync(
|
|
329
|
+
"file_permission",
|
|
330
|
+
context,
|
|
331
|
+
file_path,
|
|
332
|
+
operation,
|
|
333
|
+
preview,
|
|
334
|
+
message_group,
|
|
335
|
+
operation_data,
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
async def on_pre_tool_call(
|
|
340
|
+
tool_name: str, tool_args: dict, context: Any = None
|
|
341
|
+
) -> List[Any]:
|
|
342
|
+
"""Trigger callbacks before a tool is called.
|
|
343
|
+
|
|
344
|
+
This allows plugins to inspect, modify, or log tool calls before
|
|
345
|
+
they are executed.
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
tool_name: Name of the tool being called
|
|
349
|
+
tool_args: Arguments being passed to the tool
|
|
350
|
+
context: Optional context data for the tool call
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
List of results from registered callbacks.
|
|
354
|
+
"""
|
|
355
|
+
return await _trigger_callbacks("pre_tool_call", tool_name, tool_args, context)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
async def on_post_tool_call(
|
|
359
|
+
tool_name: str,
|
|
360
|
+
tool_args: dict,
|
|
361
|
+
result: Any,
|
|
362
|
+
duration_ms: float,
|
|
363
|
+
context: Any = None,
|
|
364
|
+
) -> List[Any]:
|
|
365
|
+
"""Trigger callbacks after a tool completes.
|
|
366
|
+
|
|
367
|
+
This allows plugins to inspect tool results, log execution times,
|
|
368
|
+
or perform post-processing.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
tool_name: Name of the tool that was called
|
|
372
|
+
tool_args: Arguments that were passed to the tool
|
|
373
|
+
result: The result returned by the tool
|
|
374
|
+
duration_ms: Execution time in milliseconds
|
|
375
|
+
context: Optional context data for the tool call
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
List of results from registered callbacks.
|
|
379
|
+
"""
|
|
380
|
+
return await _trigger_callbacks(
|
|
381
|
+
"post_tool_call", tool_name, tool_args, result, duration_ms, context
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
async def on_stream_event(
|
|
386
|
+
event_type: str, event_data: Any, agent_session_id: str | None = None
|
|
387
|
+
) -> List[Any]:
|
|
388
|
+
"""Trigger callbacks for streaming events.
|
|
389
|
+
|
|
390
|
+
This allows plugins to react to streaming events in real-time,
|
|
391
|
+
such as tokens being generated, tool calls starting, etc.
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
event_type: Type of the streaming event
|
|
395
|
+
event_data: Data associated with the event
|
|
396
|
+
agent_session_id: Optional session ID of the agent emitting the event
|
|
397
|
+
|
|
398
|
+
Returns:
|
|
399
|
+
List of results from registered callbacks.
|
|
400
|
+
"""
|
|
401
|
+
return await _trigger_callbacks(
|
|
402
|
+
"stream_event", event_type, event_data, agent_session_id
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def on_register_tools() -> List[Dict[str, Any]]:
|
|
407
|
+
"""Collect custom tool registrations from plugins.
|
|
408
|
+
|
|
409
|
+
Each callback should return a list of dicts with:
|
|
410
|
+
- "name": str - the tool name
|
|
411
|
+
- "register_func": callable - function that takes an agent and registers the tool
|
|
412
|
+
|
|
413
|
+
Example return: [{"name": "my_tool", "register_func": register_my_tool}]
|
|
414
|
+
"""
|
|
415
|
+
return _trigger_callbacks_sync("register_tools")
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def on_register_agents() -> List[Dict[str, Any]]:
|
|
419
|
+
"""Collect custom agent registrations from plugins.
|
|
420
|
+
|
|
421
|
+
Each callback should return a list of dicts with either:
|
|
422
|
+
- "name": str, "class": Type[BaseAgent] - for Python agent classes
|
|
423
|
+
- "name": str, "json_path": str - for JSON agent files
|
|
424
|
+
|
|
425
|
+
Example return: [{"name": "my-agent", "class": MyAgentClass}]
|
|
426
|
+
"""
|
|
427
|
+
return _trigger_callbacks_sync("register_agents")
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def on_register_model_types() -> List[Dict[str, Any]]:
|
|
431
|
+
"""Collect custom model type registrations from plugins.
|
|
432
|
+
|
|
433
|
+
This hook allows plugins to register custom model types that can be used
|
|
434
|
+
in model configurations. Each callback should return a list of dicts with:
|
|
435
|
+
- "type": str - the model type name (e.g., "antigravity", "claude_code")
|
|
436
|
+
- "handler": callable - function(model_name, model_config, config) -> model instance
|
|
437
|
+
|
|
438
|
+
The handler function receives:
|
|
439
|
+
- model_name: str - the name of the model being created
|
|
440
|
+
- model_config: dict - the model's configuration from models.json
|
|
441
|
+
- config: dict - the full models configuration
|
|
442
|
+
|
|
443
|
+
The handler should return a model instance or None if creation fails.
|
|
444
|
+
|
|
445
|
+
Example callback:
|
|
446
|
+
def register_my_model_types():
|
|
447
|
+
return [{
|
|
448
|
+
"type": "my_custom_type",
|
|
449
|
+
"handler": create_my_custom_model,
|
|
450
|
+
}]
|
|
451
|
+
|
|
452
|
+
Example return: [{"type": "antigravity", "handler": create_antigravity_model}]
|
|
453
|
+
"""
|
|
454
|
+
return _trigger_callbacks_sync("register_model_type")
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
def on_get_model_system_prompt(
|
|
458
|
+
model_name: str, default_system_prompt: str, user_prompt: str
|
|
459
|
+
) -> List[Dict[str, Any]]:
|
|
460
|
+
"""Allow plugins to provide custom system prompts for specific model types.
|
|
461
|
+
|
|
462
|
+
This hook allows plugins to override the system prompt handling for custom
|
|
463
|
+
model types (like claude_code or antigravity models). Each callback receives
|
|
464
|
+
the model name and should return a dict if it handles that model type, or None.
|
|
465
|
+
|
|
466
|
+
Args:
|
|
467
|
+
model_name: The name of the model being used (e.g., "claude-code-sonnet")
|
|
468
|
+
default_system_prompt: The default system prompt from the agent
|
|
469
|
+
user_prompt: The user's prompt/message
|
|
470
|
+
|
|
471
|
+
Each callback should return a dict with:
|
|
472
|
+
- "instructions": str - the system prompt/instructions to use
|
|
473
|
+
- "user_prompt": str - the (possibly modified) user prompt
|
|
474
|
+
- "handled": bool - True if this callback handled the model
|
|
475
|
+
|
|
476
|
+
Or return None if the callback doesn't handle this model type.
|
|
477
|
+
|
|
478
|
+
Example callback:
|
|
479
|
+
def get_my_model_system_prompt(model_name, default_system_prompt, user_prompt):
|
|
480
|
+
if model_name.startswith("my-custom-"):
|
|
481
|
+
return {
|
|
482
|
+
"instructions": "You are MyCustomBot.",
|
|
483
|
+
"user_prompt": f"{default_system_prompt}\n\n{user_prompt}",
|
|
484
|
+
"handled": True,
|
|
485
|
+
}
|
|
486
|
+
return None # Not handled by this callback
|
|
487
|
+
|
|
488
|
+
Returns:
|
|
489
|
+
List of results from registered callbacks (dicts or None values).
|
|
490
|
+
"""
|
|
491
|
+
return _trigger_callbacks_sync(
|
|
492
|
+
"get_model_system_prompt", model_name, default_system_prompt, user_prompt
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
async def on_agent_run_start(
|
|
497
|
+
agent_name: str,
|
|
498
|
+
model_name: str,
|
|
499
|
+
session_id: str | None = None,
|
|
500
|
+
) -> List[Any]:
|
|
501
|
+
"""Trigger callbacks when an agent run starts.
|
|
502
|
+
|
|
503
|
+
This fires at the beginning of run_with_mcp, before the agent task is created.
|
|
504
|
+
Useful for:
|
|
505
|
+
- Starting background tasks (like token refresh heartbeats)
|
|
506
|
+
- Logging/analytics
|
|
507
|
+
- Resource allocation
|
|
508
|
+
|
|
509
|
+
Args:
|
|
510
|
+
agent_name: Name of the agent starting
|
|
511
|
+
model_name: Name of the model being used
|
|
512
|
+
session_id: Optional session identifier
|
|
513
|
+
|
|
514
|
+
Returns:
|
|
515
|
+
List of results from registered callbacks.
|
|
516
|
+
"""
|
|
517
|
+
return await _trigger_callbacks(
|
|
518
|
+
"agent_run_start", agent_name, model_name, session_id
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
async def on_agent_run_end(
|
|
523
|
+
agent_name: str,
|
|
524
|
+
model_name: str,
|
|
525
|
+
session_id: str | None = None,
|
|
526
|
+
success: bool = True,
|
|
527
|
+
error: Exception | None = None,
|
|
528
|
+
response_text: str | None = None,
|
|
529
|
+
metadata: dict | None = None,
|
|
530
|
+
) -> List[Any]:
|
|
531
|
+
"""Trigger callbacks when an agent run ends.
|
|
532
|
+
|
|
533
|
+
This fires at the end of run_with_mcp, in the finally block.
|
|
534
|
+
Always fires regardless of success/failure/cancellation.
|
|
535
|
+
|
|
536
|
+
Useful for:
|
|
537
|
+
- Stopping background tasks (like token refresh heartbeats)
|
|
538
|
+
- Workflow orchestration (like Ralph's autonomous loop)
|
|
539
|
+
- Logging/analytics
|
|
540
|
+
- Resource cleanup
|
|
541
|
+
- Detecting completion signals in responses
|
|
542
|
+
|
|
543
|
+
Args:
|
|
544
|
+
agent_name: Name of the agent that finished
|
|
545
|
+
model_name: Name of the model that was used
|
|
546
|
+
session_id: Optional session identifier
|
|
547
|
+
success: Whether the run completed successfully
|
|
548
|
+
error: Exception if the run failed, None otherwise
|
|
549
|
+
response_text: The final text response from the agent (if successful)
|
|
550
|
+
metadata: Optional dict with additional context (tokens used, etc.)
|
|
551
|
+
|
|
552
|
+
Returns:
|
|
553
|
+
List of results from registered callbacks.
|
|
554
|
+
"""
|
|
555
|
+
return await _trigger_callbacks(
|
|
556
|
+
"agent_run_end",
|
|
557
|
+
agent_name,
|
|
558
|
+
model_name,
|
|
559
|
+
session_id,
|
|
560
|
+
success,
|
|
561
|
+
error,
|
|
562
|
+
response_text,
|
|
563
|
+
metadata,
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
def on_register_mcp_catalog_servers() -> List[Any]:
|
|
568
|
+
"""Trigger callbacks to register additional MCP catalog servers.
|
|
569
|
+
|
|
570
|
+
Plugins can register callbacks that return List[MCPServerTemplate] to add
|
|
571
|
+
servers to the MCP catalog/marketplace.
|
|
572
|
+
|
|
573
|
+
Returns:
|
|
574
|
+
List of results from all registered callbacks (each should be a list of MCPServerTemplate).
|
|
575
|
+
"""
|
|
576
|
+
return _trigger_callbacks_sync("register_mcp_catalog_servers")
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def on_register_browser_types() -> List[Any]:
|
|
580
|
+
"""Trigger callbacks to register custom browser types/providers.
|
|
581
|
+
|
|
582
|
+
Plugins can register callbacks that return a dict mapping browser type names
|
|
583
|
+
to initialization functions. This allows plugins to provide custom browser
|
|
584
|
+
implementations (like Camoufox for stealth browsing).
|
|
585
|
+
|
|
586
|
+
Each callback should return a dict with:
|
|
587
|
+
- key: str - the browser type name (e.g., "camoufox", "firefox-stealth")
|
|
588
|
+
- value: callable - async initialization function that takes (manager, **kwargs)
|
|
589
|
+
and sets up the browser on the manager instance
|
|
590
|
+
|
|
591
|
+
Example callback:
|
|
592
|
+
def register_my_browser_types():
|
|
593
|
+
return {
|
|
594
|
+
"camoufox": initialize_camoufox,
|
|
595
|
+
"my-stealth-browser": initialize_my_stealth,
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
Returns:
|
|
599
|
+
List of dicts from all registered callbacks.
|
|
600
|
+
"""
|
|
601
|
+
return _trigger_callbacks_sync("register_browser_types")
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
def on_get_motd() -> List[Any]:
|
|
605
|
+
"""Trigger callbacks to get custom MOTD content.
|
|
606
|
+
|
|
607
|
+
Plugins can register callbacks that return a tuple of (message, version).
|
|
608
|
+
The last non-None result will be used as the MOTD.
|
|
609
|
+
|
|
610
|
+
Returns:
|
|
611
|
+
List of (message, version) tuples from registered callbacks.
|
|
612
|
+
"""
|
|
613
|
+
return _trigger_callbacks_sync("get_motd")
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
def on_register_model_providers() -> List[Any]:
|
|
617
|
+
"""Trigger callbacks to register custom model provider classes.
|
|
618
|
+
|
|
619
|
+
Plugins can register callbacks that return a dict mapping provider names
|
|
620
|
+
to model classes. Example: {"walmart_gemini": WalmartGeminiModel}
|
|
621
|
+
|
|
622
|
+
Returns:
|
|
623
|
+
List of dicts from all registered callbacks.
|
|
624
|
+
"""
|
|
625
|
+
return _trigger_callbacks_sync("register_model_providers")
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
def on_message_history_processor_start(
|
|
629
|
+
agent_name: str,
|
|
630
|
+
session_id: str | None,
|
|
631
|
+
message_history: List[Any],
|
|
632
|
+
incoming_messages: List[Any],
|
|
633
|
+
) -> List[Any]:
|
|
634
|
+
"""Trigger callbacks at the start of message history processing.
|
|
635
|
+
|
|
636
|
+
This hook fires at the beginning of the message_history_accumulator,
|
|
637
|
+
before any deduplication or processing occurs. Useful for:
|
|
638
|
+
- Logging/debugging message flow
|
|
639
|
+
- Observing raw incoming messages
|
|
640
|
+
- Analytics on message history growth
|
|
641
|
+
|
|
642
|
+
Args:
|
|
643
|
+
agent_name: Name of the agent processing messages
|
|
644
|
+
session_id: Optional session identifier
|
|
645
|
+
message_history: Current message history (before processing)
|
|
646
|
+
incoming_messages: New messages being added
|
|
647
|
+
|
|
648
|
+
Returns:
|
|
649
|
+
List of results from registered callbacks.
|
|
650
|
+
"""
|
|
651
|
+
return _trigger_callbacks_sync(
|
|
652
|
+
"message_history_processor_start",
|
|
653
|
+
agent_name,
|
|
654
|
+
session_id,
|
|
655
|
+
message_history,
|
|
656
|
+
incoming_messages,
|
|
657
|
+
)
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
def on_message_history_processor_end(
|
|
661
|
+
agent_name: str,
|
|
662
|
+
session_id: str | None,
|
|
663
|
+
message_history: List[Any],
|
|
664
|
+
messages_added: int,
|
|
665
|
+
messages_filtered: int,
|
|
666
|
+
) -> List[Any]:
|
|
667
|
+
"""Trigger callbacks at the end of message history processing.
|
|
668
|
+
|
|
669
|
+
This hook fires at the end of the message_history_accumulator,
|
|
670
|
+
after deduplication and filtering has been applied. Useful for:
|
|
671
|
+
- Logging/debugging final message state
|
|
672
|
+
- Analytics on deduplication effectiveness
|
|
673
|
+
- Observing what was actually added to history
|
|
674
|
+
|
|
675
|
+
Args:
|
|
676
|
+
agent_name: Name of the agent processing messages
|
|
677
|
+
session_id: Optional session identifier
|
|
678
|
+
message_history: Final message history (after processing)
|
|
679
|
+
messages_added: Count of new messages that were added
|
|
680
|
+
messages_filtered: Count of messages that were filtered out (dupes/empty)
|
|
681
|
+
|
|
682
|
+
Returns:
|
|
683
|
+
List of results from registered callbacks.
|
|
684
|
+
"""
|
|
685
|
+
return _trigger_callbacks_sync(
|
|
686
|
+
"message_history_processor_end",
|
|
687
|
+
agent_name,
|
|
688
|
+
session_id,
|
|
689
|
+
message_history,
|
|
690
|
+
messages_added,
|
|
691
|
+
messages_filtered,
|
|
692
|
+
)
|