Skip to content

Commit 49531da

Browse files
feat: add on_agent_begin, on_using_llm_tool, on_llm_tool_respond, on_agent_done event hooks (AstrBotDevs#7540)
* feat: add on_agent_begin, on_using_llm_tool, on_llm_tool_respond, on_agent_done event hooks * docs: add version requirement for event hooks in message event guide * Update astrbot/core/star/star_handler.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update astrbot/core/astr_agent_hooks.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * feat: rename event types to include 'Event' suffix for consistency * chore: ruff format --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 625eab2 commit 49531da

9 files changed

Lines changed: 367 additions & 0 deletions

File tree

astrbot/api/event/filter/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
from astrbot.core.star.register import register_custom_filter as custom_filter
1515
from astrbot.core.star.register import register_event_message_type as event_message_type
1616
from astrbot.core.star.register import register_llm_tool as llm_tool
17+
from astrbot.core.star.register import register_on_agent_begin as on_agent_begin
18+
from astrbot.core.star.register import register_on_agent_done as on_agent_done
1719
from astrbot.core.star.register import register_on_astrbot_loaded as on_astrbot_loaded
1820
from astrbot.core.star.register import (
1921
register_on_decorating_result as on_decorating_result,
@@ -51,6 +53,8 @@
5153
"custom_filter",
5254
"event_message_type",
5355
"llm_tool",
56+
"on_agent_begin",
57+
"on_agent_done",
5458
"on_astrbot_loaded",
5559
"on_decorating_result",
5660
"on_llm_request",

astrbot/core/astr_agent_hooks.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@
1212

1313

1414
class MainAgentHooks(BaseAgentRunHooks[AstrAgentContext]):
15+
async def on_agent_begin(
16+
self, run_context: ContextWrapper[AstrAgentContext]
17+
) -> None:
18+
await call_event_hook(
19+
run_context.context.event,
20+
EventType.OnAgentBeginEvent,
21+
run_context,
22+
)
23+
1524
async def on_agent_done(self, run_context, llm_response) -> None:
1625
# 执行事件钩子
1726
if llm_response and llm_response.reasoning_content:
@@ -25,6 +34,12 @@ async def on_agent_done(self, run_context, llm_response) -> None:
2534
EventType.OnLLMResponseEvent,
2635
llm_response,
2736
)
37+
await call_event_hook(
38+
run_context.context.event,
39+
EventType.OnAgentDoneEvent,
40+
run_context,
41+
llm_response,
42+
)
2843

2944
async def on_tool_start(
3045
self,

astrbot/core/star/register/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
register_custom_filter,
88
register_event_message_type,
99
register_llm_tool,
10+
register_on_agent_begin,
11+
register_on_agent_done,
1012
register_on_astrbot_loaded,
1113
register_on_decorating_result,
1214
register_on_llm_request,
@@ -31,6 +33,8 @@
3133
"register_custom_filter",
3234
"register_event_message_type",
3335
"register_llm_tool",
36+
"register_on_agent_begin",
37+
"register_on_agent_done",
3438
"register_on_astrbot_loaded",
3539
"register_on_decorating_result",
3640
"register_on_llm_request",

astrbot/core/star/register/star_handler.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,64 @@ def decorator(awaitable):
460460
return decorator
461461

462462

463+
def register_on_agent_begin(**kwargs):
464+
"""当 Agent 开始运行时的事件
465+
466+
Examples:
467+
```py
468+
from astrbot.core.agent.run_context import ContextWrapper
469+
from astrbot.core.astr_agent_context import AstrAgentContext
470+
471+
@on_agent_begin()
472+
async def test(
473+
self,
474+
event: AstrMessageEvent,
475+
run_context: ContextWrapper[AstrAgentContext],
476+
) -> None:
477+
...
478+
```
479+
480+
请务必接收两个参数:event, run_context
481+
482+
"""
483+
484+
def decorator(awaitable):
485+
_ = get_handler_or_create(awaitable, EventType.OnAgentBeginEvent, **kwargs)
486+
return awaitable
487+
488+
return decorator
489+
490+
491+
def register_on_agent_done(**kwargs):
492+
"""当 Agent 运行完成后的事件
493+
494+
Examples:
495+
```py
496+
from astrbot.core.agent.run_context import ContextWrapper
497+
from astrbot.core.astr_agent_context import AstrAgentContext
498+
from astrbot.api.provider import LLMResponse
499+
500+
@on_agent_done()
501+
async def test(
502+
self,
503+
event: AstrMessageEvent,
504+
run_context: ContextWrapper[AstrAgentContext],
505+
response: LLMResponse,
506+
) -> None:
507+
...
508+
```
509+
510+
请务必接收三个参数:event, run_context, response
511+
512+
"""
513+
514+
def decorator(awaitable):
515+
_ = get_handler_or_create(awaitable, EventType.OnAgentDoneEvent, **kwargs)
516+
return awaitable
517+
518+
return decorator
519+
520+
463521
def register_on_using_llm_tool(**kwargs):
464522
"""当调用函数工具前的事件。
465523
会传入 tool 和 tool_args 参数。

astrbot/core/star/star_handler.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,22 @@ def get_handlers_by_event_type(
7171
plugins_name: list[str] | None = None,
7272
) -> list[StarHandlerMetadata[Callable[..., Awaitable[Any]]]]: ...
7373

74+
@overload
75+
def get_handlers_by_event_type(
76+
self,
77+
event_type: Literal[EventType.OnAgentBeginEvent],
78+
only_activated=True,
79+
plugins_name: list[str] | None = None,
80+
) -> list[StarHandlerMetadata[Callable[..., Awaitable[Any]]]]: ...
81+
82+
@overload
83+
def get_handlers_by_event_type(
84+
self,
85+
event_type: Literal[EventType.OnAgentDoneEvent],
86+
only_activated=True,
87+
plugins_name: list[str] | None = None,
88+
) -> list[StarHandlerMetadata[Callable[..., Awaitable[Any]]]]: ...
89+
7490
@overload
7591
def get_handlers_by_event_type(
7692
self,
@@ -213,6 +229,8 @@ class EventType(enum.Enum):
213229
OnWaitingLLMRequestEvent = enum.auto() # 等待调用 LLM(在获取锁之前,仅通知)
214230
OnLLMRequestEvent = enum.auto() # 收到 LLM 请求(可以是用户也可以是插件)
215231
OnLLMResponseEvent = enum.auto() # LLM 响应后
232+
OnAgentBeginEvent = enum.auto() # Agent 开始运行
233+
OnAgentDoneEvent = enum.auto() # Agent 运行完成
216234
OnDecoratingResultEvent = enum.auto() # 发送消息前
217235
OnCallingFuncToolEvent = enum.auto() # 调用函数工具
218236
OnUsingLLMToolEvent = enum.auto() # 使用 LLM 工具

astrbot/dashboard/routes/plugin.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ def __init__(
7979
EventType.AdapterMessageEvent: "平台消息下发时",
8080
EventType.OnLLMRequestEvent: "LLM 请求时",
8181
EventType.OnLLMResponseEvent: "LLM 响应后",
82+
EventType.OnAgentBeginEvent: "Agent 开始运行时",
83+
EventType.OnAgentDoneEvent: "Agent 运行完成后",
8284
EventType.OnDecoratingResultEvent: "回复消息前",
8385
EventType.OnCallingFuncToolEvent: "函数工具",
8486
EventType.OnAfterMessageSentEvent: "发送消息后",

docs/en/dev/star/guides/listen-message-event.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,94 @@ async def on_llm_resp(self, event: AstrMessageEvent, resp: LLMResponse): # Note
289289

290290
> You cannot use yield to send messages here. If you need to send, please use the `event.send()` method directly.
291291
292+
#### On Agent Begin
293+
294+
> Requires AstrBot version > v4.23.1
295+
296+
When the Agent starts running, the `on_agent_begin` hook is triggered.
297+
298+
```python
299+
from astrbot.api.event import filter, AstrMessageEvent
300+
from astrbot.core.agent.run_context import ContextWrapper
301+
from astrbot.core.astr_agent_context import AstrAgentContext
302+
303+
@filter.on_agent_begin()
304+
async def on_agent_begin(self, event: AstrMessageEvent, run_context: ContextWrapper[AstrAgentContext]): # Note there are three parameters
305+
print("Agent started")
306+
```
307+
308+
> You cannot use yield to send messages here. If you need to send, please use the `event.send()` method directly.
309+
310+
#### Before LLM Tool Call
311+
312+
> Requires AstrBot version > v4.23.1
313+
314+
When the Agent is about to call an LLM tool, the `on_using_llm_tool` hook is triggered.
315+
316+
You can obtain the `FunctionTool` object and tool call arguments.
317+
318+
```python
319+
from astrbot.api.event import filter, AstrMessageEvent
320+
from astrbot.core.agent.tool import FunctionTool
321+
322+
@filter.on_using_llm_tool()
323+
async def on_using_llm_tool(
324+
self,
325+
event: AstrMessageEvent,
326+
tool: FunctionTool,
327+
tool_args: dict | None,
328+
):
329+
print(tool.name, tool_args)
330+
```
331+
332+
> You cannot use yield to send messages here. If you need to send, please use the `event.send()` method directly.
333+
334+
#### After LLM Tool Call
335+
336+
> Requires AstrBot version > v4.23.1
337+
338+
After the LLM tool call completes, the `on_llm_tool_respond` hook is triggered.
339+
340+
You can obtain the `FunctionTool` object, tool call arguments, and tool call result.
341+
342+
```python
343+
from mcp.types import CallToolResult
344+
345+
from astrbot.api.event import filter, AstrMessageEvent
346+
from astrbot.core.agent.tool import FunctionTool
347+
348+
@filter.on_llm_tool_respond()
349+
async def on_llm_tool_respond(
350+
self,
351+
event: AstrMessageEvent,
352+
tool: FunctionTool,
353+
tool_args: dict | None,
354+
tool_result: CallToolResult | None,
355+
):
356+
print(tool.name, tool_args, tool_result)
357+
```
358+
359+
> You cannot use yield to send messages here. If you need to send, please use the `event.send()` method directly.
360+
361+
#### On Agent Done
362+
363+
> Requires AstrBot version > v4.23.1
364+
365+
After the Agent finishes running, the `on_agent_done` hook is triggered. This hook is triggered after `on_llm_response`.
366+
367+
```python
368+
from astrbot.api.event import filter, AstrMessageEvent
369+
from astrbot.api.provider import LLMResponse
370+
from astrbot.core.agent.run_context import ContextWrapper
371+
from astrbot.core.astr_agent_context import AstrAgentContext
372+
373+
@filter.on_agent_done()
374+
async def on_agent_done(self, event: AstrMessageEvent, run_context: ContextWrapper[AstrAgentContext], resp: LLMResponse): # Note there are four parameters
375+
print(resp)
376+
```
377+
378+
> You cannot use yield to send messages here. If you need to send, please use the `event.send()` method directly.
379+
292380
#### Before Sending Message
293381

294382
Before sending a message, the `on_decorating_result` hook is triggered.

docs/zh/dev/star/guides/listen-message-event.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,94 @@ async def on_llm_resp(self, event: AstrMessageEvent, resp: LLMResponse): # 请
305305

306306
> 这里不能使用 yield 来发送消息。如需发送,请直接使用 `event.send()` 方法。
307307
308+
#### Agent 开始运行时
309+
310+
> 适用于 AstrBot 版本 > v4.23.1
311+
312+
在 Agent 开始运行时,会触发 `on_agent_begin` 钩子。
313+
314+
```python
315+
from astrbot.api.event import filter, AstrMessageEvent
316+
from astrbot.core.agent.run_context import ContextWrapper
317+
from astrbot.core.astr_agent_context import AstrAgentContext
318+
319+
@filter.on_agent_begin()
320+
async def on_agent_begin(self, event: AstrMessageEvent, run_context: ContextWrapper[AstrAgentContext]):
321+
print("Agent 开始运行")
322+
```
323+
324+
> 这里不能使用 yield 来发送消息。如需发送,请直接使用 `event.send()` 方法。
325+
326+
#### LLM 工具调用前
327+
328+
> 适用于 AstrBot 版本 > v4.23.1
329+
330+
在 Agent 准备调用 LLM 工具时,会触发 `on_using_llm_tool` 钩子。
331+
332+
可以获取到 `FunctionTool` 对象和工具调用参数。
333+
334+
```python
335+
from astrbot.api.event import filter, AstrMessageEvent
336+
from astrbot.core.agent.tool import FunctionTool
337+
338+
@filter.on_using_llm_tool()
339+
async def on_using_llm_tool(
340+
self,
341+
event: AstrMessageEvent,
342+
tool: FunctionTool,
343+
tool_args: dict | None,
344+
):
345+
print(tool.name, tool_args)
346+
```
347+
348+
> 这里不能使用 yield 来发送消息。如需发送,请直接使用 `event.send()` 方法。
349+
350+
#### LLM 工具调用后
351+
352+
> 适用于 AstrBot 版本 > v4.23.1
353+
354+
在 LLM 工具调用完成后,会触发 `on_llm_tool_respond` 钩子。
355+
356+
可以获取到 `FunctionTool` 对象、工具调用参数和工具调用结果。
357+
358+
```python
359+
from mcp.types import CallToolResult
360+
361+
from astrbot.api.event import filter, AstrMessageEvent
362+
from astrbot.core.agent.tool import FunctionTool
363+
364+
@filter.on_llm_tool_respond()
365+
async def on_llm_tool_respond(
366+
self,
367+
event: AstrMessageEvent,
368+
tool: FunctionTool,
369+
tool_args: dict | None,
370+
tool_result: CallToolResult | None,
371+
):
372+
print(tool.name, tool_args, tool_result)
373+
```
374+
375+
> 这里不能使用 yield 来发送消息。如需发送,请直接使用 `event.send()` 方法。
376+
377+
#### Agent 运行完成时
378+
379+
> 适用于 AstrBot 版本 > v4.23.1
380+
381+
在 Agent 运行完成后,会触发 `on_agent_done` 钩子。这个钩子会在 `on_llm_response` 之后触发。本质上和 `on_llm_response` 一样。
382+
383+
```python
384+
from astrbot.api.event import filter, AstrMessageEvent
385+
from astrbot.api.provider import LLMResponse
386+
from astrbot.core.agent.run_context import ContextWrapper
387+
from astrbot.core.astr_agent_context import AstrAgentContext
388+
389+
@filter.on_agent_done()
390+
async def on_agent_done(self, event: AstrMessageEvent, run_context: ContextWrapper[AstrAgentContext], resp: LLMResponse):
391+
print(resp)
392+
```
393+
394+
> 这里不能使用 yield 来发送消息。如需发送,请直接使用 `event.send()` 方法。
395+
308396
#### 发送消息前
309397

310398
在发送消息前,会触发 `on_decorating_result` 钩子。

0 commit comments

Comments
 (0)