Skip to content

feat: add context compression hooks for plugin extensibility -还未自测,但是修改内容不多,如果可以的话可以直接合并#5291

Draft
evpeople wants to merge 3 commits intoAstrBotDevs:masterfrom
evpeople:feat/add-context-compression-hook
Draft

feat: add context compression hooks for plugin extensibility -还未自测,但是修改内容不多,如果可以的话可以直接合并#5291
evpeople wants to merge 3 commits intoAstrBotDevs:masterfrom
evpeople:feat/add-context-compression-hook

Conversation

@evpeople
Copy link
Contributor

@evpeople evpeople commented Feb 21, 2026

Add two new event types:

  • OnBeforeContextCompressionEvent: triggered before context compression
  • OnAfterContextCompressionEvent: triggered after context compression

Plugins can now register handlers to execute custom logic during context compression, enabling features like logging, analytics, or preserving specific conversation history.

添加了对话压缩前后两个钩子 #5290

Modifications / 改动点

astrbot/core/star/star_handler.py 新加两个事件

astrbot/core/agent/runners/tool_loop_agent_runner.py 在context_manager.process中,新传入一个参数

astrbot/core/agent/context/manager.py 处理上文传入的参数

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果


Checklist / 检查清单

  • 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 👀 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

Add two new event types:
- OnBeforeContextCompressionEvent: triggered before context compression
- OnAfterContextCompressionEvent: triggered after context compression

Plugins can now register handlers to execute custom logic during
context compression, enabling features like logging, analytics,
or preserving specific conversation history.
@dosubot dosubot bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Feb 21, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @evpeople, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the system's extensibility by introducing new event hooks around the context compression process. This allows external plugins to tap into critical stages of conversation context management, enabling custom functionalities such as logging, analytics, or specialized handling of conversation history before and after compression occurs. The changes provide a more flexible and modular architecture for managing conversational context.

Highlights

  • New Event Hooks: Introduced two new event types, OnBeforeContextCompressionEvent and OnAfterContextCompressionEvent, which are triggered before and after context compression, respectively.
  • Plugin Extensibility: Enabled plugins to register handlers for these new events, allowing custom logic to be executed during the context compression lifecycle.
  • Context Manager Integration: Modified the context management process to accept and utilize an optional event object, facilitating the triggering of these new hooks.
Changelog
  • astrbot/core/agent/context/manager.py
    • Imported call_event_hook, AstrMessageEvent, and EventType to support event handling.
    • Updated the process method signature to accept an optional event parameter.
    • Modified the _run_compression method signature to accept an optional event parameter.
    • Integrated calls to OnBeforeContextCompressionEvent and OnAfterContextCompressionEvent within the _run_compression method.
  • astrbot/core/agent/runners/tool_loop_agent_runner.py
    • Modified the step method to retrieve an event object from the run context.
    • Passed the retrieved event object to the context_manager.process method.
  • astrbot/core/star/star_handler.py
    • Added OnBeforeContextCompressionEvent to the EventType enum.
    • Added OnAfterContextCompressionEvent to the EventType enum.
Activity
  • No human activity (comments, reviews, etc.) has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@dosubot dosubot bot added the area:core The bug / feature is about astrbot's core, backend label Feb 21, 2026
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了两个问题,并给出了一些高层次的反馈:

  • 建议在 _run_compression 中对 call_event_hook 的调用加一层 try/except,这样即使插件的 hook 失败,也不会破坏核心的上下文压缩逻辑。
  • tool_loop_agent_runner.step 中,把 hasattr(self.run_context.context, "event") 这个检查换成 getattr(self.run_context.context, "event", None) 会更简洁、更清晰,用来在调用 context_manager.process 时传入 event。
给 AI Agents 的提示词
Please address the comments from this code review:

## Overall Comments
- Consider wrapping the `call_event_hook` invocations in `_run_compression` with a try/except so that plugin hook failures don’t break core context compression behavior.
- In `tool_loop_agent_runner.step`, the `hasattr(self.run_context.context, "event")` check could be simplified and made clearer with `getattr(self.run_context.context, "event", None)` when passing the event into `context_manager.process`.

## Individual Comments

### Comment 1
<location> `astrbot/core/agent/context/manager.py:141-147` </location>
<code_context>
             # still need compress, truncate by half
             messages = self.truncator.truncate_by_halving(messages)

+        # Trigger after compression hook
+        if event:
+            await call_event_hook(
+                event,
+                EventType.OnAfterContextCompressionEvent,
+                messages,
+                tokens_after_summary,
+            )
+
</code_context>

<issue_to_address>
**issue:** After-compression hook receives token count before truncation, which may be misleading.

Here `tokens_after_summary` is the count immediately after compression but before truncation, so if `truncator` halves the messages further, the final context can have many fewer tokens than reported to `OnAfterContextCompressionEvent` consumers. Either recompute the token count after all truncation steps and pass that, or clarify in the event/parameter naming that this is the post-compression, pre-truncation token count.
</issue_to_address>

### Comment 2
<location> `astrbot/core/agent/runners/tool_loop_agent_runner.py:298-304` </location>
<code_context>
         # do truncate and compress
         token_usage = self.req.conversation.token_usage if self.req.conversation else 0
         self._simple_print_message_role("[BefCompact]")
+        event = (
+            self.run_context.context.event
+            if hasattr(self.run_context.context, "event")
+            else None
+        )
         self.run_context.messages = await self.context_manager.process(
</code_context>

<issue_to_address>
**suggestion:** Simplify and make the event extraction more robust using getattr with a default.

Instead of the `hasattr` check and multiline conditional, use `event = getattr(self.run_context.context, "event", None)`. This is clearer and avoids issues if `context` overrides attribute access with side effects.

```suggestion
        self._simple_print_message_role("[BefCompact]")
        event = getattr(self.run_context.context, "event", None)
        self.run_context.messages = await self.context_manager.process(
```
</issue_to_address>

Sourcery 对开源项目是免费的——如果你觉得我们的 Review 有帮助,请考虑帮忙分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进以后的 Review。
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • Consider wrapping the call_event_hook invocations in _run_compression with a try/except so that plugin hook failures don’t break core context compression behavior.
  • In tool_loop_agent_runner.step, the hasattr(self.run_context.context, "event") check could be simplified and made clearer with getattr(self.run_context.context, "event", None) when passing the event into context_manager.process.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider wrapping the `call_event_hook` invocations in `_run_compression` with a try/except so that plugin hook failures don’t break core context compression behavior.
- In `tool_loop_agent_runner.step`, the `hasattr(self.run_context.context, "event")` check could be simplified and made clearer with `getattr(self.run_context.context, "event", None)` when passing the event into `context_manager.process`.

## Individual Comments

### Comment 1
<location> `astrbot/core/agent/context/manager.py:141-147` </location>
<code_context>
             # still need compress, truncate by half
             messages = self.truncator.truncate_by_halving(messages)

+        # Trigger after compression hook
+        if event:
+            await call_event_hook(
+                event,
+                EventType.OnAfterContextCompressionEvent,
+                messages,
+                tokens_after_summary,
+            )
+
</code_context>

<issue_to_address>
**issue:** After-compression hook receives token count before truncation, which may be misleading.

Here `tokens_after_summary` is the count immediately after compression but before truncation, so if `truncator` halves the messages further, the final context can have many fewer tokens than reported to `OnAfterContextCompressionEvent` consumers. Either recompute the token count after all truncation steps and pass that, or clarify in the event/parameter naming that this is the post-compression, pre-truncation token count.
</issue_to_address>

### Comment 2
<location> `astrbot/core/agent/runners/tool_loop_agent_runner.py:298-304` </location>
<code_context>
         # do truncate and compress
         token_usage = self.req.conversation.token_usage if self.req.conversation else 0
         self._simple_print_message_role("[BefCompact]")
+        event = (
+            self.run_context.context.event
+            if hasattr(self.run_context.context, "event")
+            else None
+        )
         self.run_context.messages = await self.context_manager.process(
</code_context>

<issue_to_address>
**suggestion:** Simplify and make the event extraction more robust using getattr with a default.

Instead of the `hasattr` check and multiline conditional, use `event = getattr(self.run_context.context, "event", None)`. This is clearer and avoids issues if `context` overrides attribute access with side effects.

```suggestion
        self._simple_print_message_role("[BefCompact]")
        event = getattr(self.run_context.context, "event", None)
        self.run_context.messages = await self.context_manager.process(
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@dosubot
Copy link

dosubot bot commented Feb 21, 2026

Related Documentation

Checked 1 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

- Wrap hook calls in try/except to prevent plugin failures from breaking
  core compression behavior
- Recalculate token count after all truncation steps for accurate reporting
- Simplify event extraction using getattr with default value
@evpeople evpeople marked this pull request as draft February 21, 2026 13:22
Move call_event_hook and EventType imports inside the hook
functions to avoid circular import at module load time.
@evpeople evpeople changed the title feat: add context compression hooks for plugin extensibility feat: add context compression hooks for plugin extensibility -还未自测,但是修改内容不多,如果可以的话可以直接合并 Feb 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core The bug / feature is about astrbot's core, backend size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant