feat(talon): audit reaction approval attempts - #4348
Merged
John Kennedy (jkennedyvz) merged 1 commit intoJun 28, 2026
Conversation
John Kennedy (jkennedyvz)
marked this pull request as ready for review
June 27, 2026 22:57
John Kennedy (jkennedyvz)
force-pushed
the
john/talon/reaction-approval-audit
branch
from
June 28, 2026 22:17
7388ba9 to
7d83caa
Compare
This was referenced Jun 28, 2026
John Kennedy (jkennedyvz)
pushed a commit
that referenced
this pull request
Jun 30, 2026
> [!CAUTION] > Merging this PR will automatically publish to **PyPI** and create a **GitHub release**. For the full release process, see [`.github/RELEASING.md`](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md). --- _Everything below this line will be the GitHub release body._ --- ## [0.0.2](deepagents-talon==0.0.1...deepagents-talon==0.0.2) (2026-06-30) ### Features * **talon:** `DEEPAGENTS_TALON_RECURSION_LIMIT` env var ([#4354](#4354)) ([82d1eac](82d1eac)) * **talon:** add reaction approval routing ([#4345](#4345)) ([3fe8c0c](3fe8c0c)) * **talon:** add Telegram channel adapter, CLI wiring, and offset persistence ([#4097](#4097)) ([7c87cec](7c87cec)) * **talon:** add tool approval env override ([#4349](#4349)) ([d26481d](d26481d)) * **talon:** audit reaction approval attempts ([#4348](#4348)) ([d7895c4](d7895c4)) * **talon:** ingest Telegram approval reactions ([#4346](#4346)) ([437af0b](437af0b)) ### Bug Fixes * **talon:** default workspace to current directory ([#4099](#4099)) ([5e337ae](5e337ae)) --- _Everything above this line will be the GitHub release body._ --- > [!NOTE] > A **New Contributors** section is appended to the GitHub release notes automatically at publish time (see [Release Pipeline](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md#release-pipeline), step 2). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Marcelo5444
pushed a commit
to Marcelo5444/deepagents
that referenced
this pull request
Jul 30, 2026
Stacked on langchain-ai#4345. Adds host-side `tool_approval.reaction` audit events for reaction approval attempts. The event records provider, stable hashed channel conversation/prompt/sender references, emoji, decision, match status, and resolution mode. Raw provider IDs are included only when `DEEPAGENTS_TALON_APPROVAL_LOG_RAW_IDS=true`; raw provider metadata, approval prompt text, arbitrary message text, and tool arguments are not logged. Matched reaction approvals use `operator_reaction` as the resolution so they can be distinguished from text approvals. ## When this is useful Reaction approvals are a one-tap action that's easy to fire off and easy to miss-context (wrong message, wrong channel, stale prompt). Without an audit trail there's no way to answer "did someone try to approve that tool call, and why didn't it take?" after the fact. These events let operators and security reviewers trace every reaction attempt — matched or ignored — back to a specific provider, conversation, prompt message, and sender, without leaking raw IDs or prompt/message contents by default. Distinguishing `operator_reaction` from text `approve`/`deny` also makes it possible to monitor how often the reaction path is actually used versus the text fallback. ## Example An operator reacts 👍 to the approval prompt. The host emits a structured `tool_approval.reaction` event: ```json { "event": "tool_approval.reaction", "provider": "slack", "channel_conversation_ref": "9f1c…a4e2", "prompt_message_ref": "b7d3…0c91", "reacting_sender_ref": "e2a8…77f0", "emoji": "👍", "decision": "approve", "match_status": "matched", "resolution": "operator_reaction" } ``` Conversation/prompt/sender references are stable hashes (via `stable_log_ref`), so the same IDs correlate across events without exposing the underlying Slack IDs. Ignored attempts are logged too, with a precise `resolution` explaining why: - `no_pending_approval` — reaction arrived with no pending tool approval - `unsupported_emoji` — emoji wasn't 👍/👎 - `missing_prompt_message_id` — channel didn't supply a prompt message id (falls back to text) - `provider_mismatch` / `conversation_mismatch` / `message_mismatch` — reaction didn't target the prompt that issued the request - `sender_missing` / `sender_mismatch` — reactor wasn't the initiating operator (when sender is known) For debugging a specific incident, set `DEEPAGENTS_TALON_APPROVAL_LOG_RAW_IDS=true` to additionally include `raw_channel_conversation_id`, `raw_prompt_message_id`, and `raw_reacting_sender_id`. Sensitive values — provider metadata, approval prompt text, arbitrary message text, and tool arguments — are never logged regardless of that flag. Validation run: - `uv run --group test pytest --disable-socket --allow-unix-socket tests/test_host.py --timeout 10` - `make lint_diff` - `make test` Co-authored-by: Deep Agent <agent@deepagents.dev>
Marcelo5444
pushed a commit
to Marcelo5444/deepagents
that referenced
this pull request
Jul 30, 2026
> [!CAUTION] > Merging this PR will automatically publish to **PyPI** and create a **GitHub release**. For the full release process, see [`.github/RELEASING.md`](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md). --- _Everything below this line will be the GitHub release body._ --- ## [0.0.2](langchain-ai/deepagents@deepagents-talon==0.0.1...deepagents-talon==0.0.2) (2026-06-30) ### Features * **talon:** `DEEPAGENTS_TALON_RECURSION_LIMIT` env var ([langchain-ai#4354](langchain-ai#4354)) ([82d1eac](langchain-ai@82d1eac)) * **talon:** add reaction approval routing ([langchain-ai#4345](langchain-ai#4345)) ([3fe8c0c](langchain-ai@3fe8c0c)) * **talon:** add Telegram channel adapter, CLI wiring, and offset persistence ([langchain-ai#4097](langchain-ai#4097)) ([7c87cec](langchain-ai@7c87cec)) * **talon:** add tool approval env override ([langchain-ai#4349](langchain-ai#4349)) ([d26481d](langchain-ai@d26481d)) * **talon:** audit reaction approval attempts ([langchain-ai#4348](langchain-ai#4348)) ([d7895c4](langchain-ai@d7895c4)) * **talon:** ingest Telegram approval reactions ([langchain-ai#4346](langchain-ai#4346)) ([437af0b](langchain-ai@437af0b)) ### Bug Fixes * **talon:** default workspace to current directory ([langchain-ai#4099](langchain-ai#4099)) ([5e337ae](langchain-ai@5e337ae)) --- _Everything above this line will be the GitHub release body._ --- > [!NOTE] > A **New Contributors** section is appended to the GitHub release notes automatically at publish time (see [Release Pipeline](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md#release-pipeline), step 2). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #4345.
Adds host-side
tool_approval.reactionaudit events for reaction approval attempts. The event records provider, stable hashed channel conversation/prompt/sender references, emoji, decision, match status, and resolution mode. Raw provider IDs are included only whenDEEPAGENTS_TALON_APPROVAL_LOG_RAW_IDS=true; raw provider metadata, approval prompt text, arbitrary message text, and tool arguments are not logged. Matched reaction approvals useoperator_reactionas the resolution so they can be distinguished from text approvals.When this is useful
Reaction approvals are a one-tap action that's easy to fire off and easy to miss-context (wrong message, wrong channel, stale prompt). Without an audit trail there's no way to answer "did someone try to approve that tool call, and why didn't it take?" after the fact. These events let operators and security reviewers trace every reaction attempt — matched or ignored — back to a specific provider, conversation, prompt message, and sender, without leaking raw IDs or prompt/message contents by default. Distinguishing
operator_reactionfrom textapprove/denyalso makes it possible to monitor how often the reaction path is actually used versus the text fallback.Example
An operator reacts 👍 to the approval prompt. The host emits a structured
tool_approval.reactionevent:{ "event": "tool_approval.reaction", "provider": "slack", "channel_conversation_ref": "9f1c…a4e2", "prompt_message_ref": "b7d3…0c91", "reacting_sender_ref": "e2a8…77f0", "emoji": "👍", "decision": "approve", "match_status": "matched", "resolution": "operator_reaction" }Conversation/prompt/sender references are stable hashes (via
stable_log_ref), so the same IDs correlate across events without exposing the underlying Slack IDs. Ignored attempts are logged too, with a preciseresolutionexplaining why:no_pending_approval— reaction arrived with no pending tool approvalunsupported_emoji— emoji wasn't 👍/👎missing_prompt_message_id— channel didn't supply a prompt message id (falls back to text)provider_mismatch/conversation_mismatch/message_mismatch— reaction didn't target the prompt that issued the requestsender_missing/sender_mismatch— reactor wasn't the initiating operator (when sender is known)For debugging a specific incident, set
DEEPAGENTS_TALON_APPROVAL_LOG_RAW_IDS=trueto additionally includeraw_channel_conversation_id,raw_prompt_message_id, andraw_reacting_sender_id. Sensitive values — provider metadata, approval prompt text, arbitrary message text, and tool arguments — are never logged regardless of that flag.Validation run:
uv run --group test pytest --disable-socket --allow-unix-socket tests/test_host.py --timeout 10make lint_diffmake test