Skip to content

fix: fire notification hooks for approvals#2284

Open
he-yufeng wants to merge 1 commit into
MoonshotAI:mainfrom
he-yufeng:fix/notification-hook-approval
Open

fix: fire notification hooks for approvals#2284
he-yufeng wants to merge 1 commit into
MoonshotAI:mainfrom
he-yufeng:fix/notification-hook-approval

Conversation

@he-yufeng
Copy link
Copy Markdown

@he-yufeng he-yufeng commented May 14, 2026

Summary

  • fire Notification hooks when an approval request is created
  • use permission_prompt as the matcher value for approval-needed notifications
  • include approval request details in the hook payload

Fixes #2281.

To verify

  • uv run python -m pytest tests\core\test_approval_runtime.py tests\hooks\test_integration.py::test_notification_hook -q --basetemp .tmp\pytest -p no:cacheprovider
  • uv run ruff check src\kimi_cli\soul\kimisoul.py tests\core\test_approval_runtime.py
  • git diff --check

Open in Devin Review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5a486b111a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +217 to +219
self._approval_hook_subscription = self._runtime.approval_runtime.subscribe(
self._on_approval_runtime_event
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Unsubscribe approval-event listener when creating souls

Avoid registering a permanent approval-runtime subscriber in KimiSoul.__init__ without removing it later. ApprovalRuntime.subscribe() stores the bound callback strongly, and this class currently has no corresponding unsubscribe(), so temporary root souls (for example /init, which creates KimiSoul(soul.agent, ...) in src/kimi_cli/soul/slash.py) accumulate listeners. After each /init, every new approval request will fire the Notification hook multiple times and keep old soul instances alive in memory.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 2 additional findings in Devin Review.

Open in Devin Review

Comment on lines +213 to +219
self._approval_hook_subscription: str | None = None
if self.is_root:
self._runtime.notifications.ack_ids("llm", extract_notification_ids(context.history))
if self._runtime.approval_runtime is not None:
self._approval_hook_subscription = self._runtime.approval_runtime.subscribe(
self._on_approval_runtime_event
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Approval runtime subscription is never unsubscribed, causing resource leak

The subscription token is stored in _approval_hook_subscription but unsubscribe() is never called anywhere in KimiSoul's lifecycle. The class has no cleanup/close method. This leaks the subscription callback (a bound method holding a strong reference to self) for the lifetime of the ApprovalRuntime.

The concrete impact is in src/kimi_cli/soul/slash.py:44 where the /init command creates a temporary KimiSoul sharing the same root runtime. That temporary soul subscribes at line 217, but when it goes out of scope, the subscription keeps it alive. Every subsequent create_request() call invokes the leaked callback, which calls fire_and_forget_trigger on a stale, empty HookEngine. The established pattern in this codebase (see src/kimi_cli/background/agent_runner.py:128) is to always pair subscribe() with unsubscribe() in a cleanup block.

Prompt for agents
The _approval_hook_subscription token is stored but never used to unsubscribe from the ApprovalRuntime. KimiSoul has no cleanup/close method.

The most straightforward fix is to add a cleanup method (e.g. close() or dispose()) to KimiSoul that calls self._runtime.approval_runtime.unsubscribe(self._approval_hook_subscription) when the token is not None. Then ensure this cleanup is called wherever KimiSoul instances are discarded — notably in src/kimi_cli/soul/slash.py:44-45 (the /init command creates a temporary KimiSoul that goes out of scope after the with block).

Alternatively, the /init path could be fixed by having the temporary soul not subscribe (e.g. by passing a flag), or by wrapping the temporary soul usage in a try/finally that calls unsubscribe.

See src/kimi_cli/background/agent_runner.py:128 for the established pattern of pairing subscribe() with unsubscribe() in a finally block.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@he-yufeng he-yufeng force-pushed the fix/notification-hook-approval branch from 5a486b1 to f4d4a72 Compare May 14, 2026 15:52
Copy link
Copy Markdown
Author

Addressed the subscription cleanup review in f4d4a72.

Changes:

  • added an idempotent KimiSoul.close() that unsubscribes the approval-runtime listener;
  • made /init close its temporary KimiSoul in a finally block;
  • added a regression test that verifies a closed soul no longer receives approval-created events.

Validated locally:

  • uv run python -m pytest tests\core\test_approval_runtime.py::test_kimisoul_triggers_notification_hook_for_approval_requests tests\core\test_approval_runtime.py::test_kimisoul_close_unsubscribes_approval_hook tests\hooks\test_integration.py::test_notification_hook -q --basetemp .tmp\pytest -p no:cacheprovider
  • uv run ruff check src\kimi_cli\soul\kimisoul.py src\kimi_cli\soul\slash.py tests\core\test_approval_runtime.py
  • uv run ruff format --check src\kimi_cli\soul\kimisoul.py src\kimi_cli\soul\slash.py tests\core\test_approval_runtime.py
  • uv run python -m py_compile src\kimi_cli\soul\kimisoul.py src\kimi_cli\soul\slash.py tests\core\test_approval_runtime.py
  • git diff --check

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

hook "Notification" never work

1 participant