Skip to content

feat(hooks): add BeforeStreamChunkEvent for stream chunk interception#1761

Open
fede-kamel wants to merge 1 commit intostrands-agents:mainfrom
fede-kamel:feat/stream-chunk-interception-hook
Open

feat(hooks): add BeforeStreamChunkEvent for stream chunk interception#1761
fede-kamel wants to merge 1 commit intostrands-agents:mainfrom
fede-kamel:feat/stream-chunk-interception-hook

Conversation

@fede-kamel
Copy link

@fede-kamel fede-kamel commented Feb 24, 2026

Motivation

There's currently no way to intercept stream chunks before they're processed. Hooks fire after processing, so modifications don't affect the TextStreamEvent or final message content.

The current hook lifecycle has a gap during streaming:

BeforeModelCallEvent
    ↓
[MODEL STREAMS CHUNKS]  ← no hook here currently
    ↓
AfterModelCallEvent

BeforeModelCallEvent fires before chunks exist. AfterModelCallEvent fires after chunks have already been streamed to the user. Neither allows chunk interception.

This adds BeforeStreamChunkEvent that fires before each chunk is processed, allowing:

  • Chunk modification (affects downstream processing and final message)
  • Chunk filtering via skip=True (excludes from all events and final message)
  • Access to invocation_state for context

Resolves #1760

Use Cases

  • Content redaction: Modify sensitive data before it reaches the user
  • Filtering: Skip certain chunks entirely (skip=True)
  • Real-time monitoring: Observe streaming without modifying
  • Content transformation: Translation, formatting, etc.

Public API Changes

New event: BeforeStreamChunkEvent

from strands.hooks import BeforeStreamChunkEvent

async def redact_chunks(event: BeforeStreamChunkEvent):
    if "contentBlockDelta" in event.chunk:
        delta = event.chunk["contentBlockDelta"]["delta"]
        if "text" in delta:
            # modify the chunk - affects TextStreamEvent and final message
            event.chunk = {"contentBlockDelta": {"delta": {"text": "[REDACTED]"}}}
            # or skip entirely
            # event.skip = True

agent.hooks.add_callback(BeforeStreamChunkEvent, redact_chunks)

Properties:

  • chunk (writable) - the raw stream chunk
  • skip (writable) - set True to exclude chunk from processing
  • invocation_state (read-only) - context dict from invocation

Reproduction and Demonstration

Issue reproduction (main branch): https://gist.github.com/fede-kamel/9d93429a3d6d7676906e41eb60890d46

Working demonstration (feature branch): https://gist.github.com/fede-kamel/a6a78d8d35eb9707d80c2327cd17b462

Type of Change

New feature

Testing

  • I ran hatch run prepare (lint, format, tests all pass)

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

…ption

Add BeforeStreamChunkEvent hook that fires BEFORE each stream chunk is
processed, enabling true interception capabilities:

- Monitor streaming progress in real-time
- Modify chunk content before processing (affects final message)
- Skip chunks entirely by setting skip=True (excluded from final message)
- Implement content transformation (e.g., redaction, translation)

Implementation details:
- Added ChunkInterceptor callback type to streaming.py
- Modified process_stream() to invoke interceptor BEFORE processing
- Modified stream_messages() to accept chunk_interceptor parameter
- event_loop.py creates interceptor that invokes BeforeStreamChunkEvent

When skip=True:
- The chunk is not processed at all
- No events (ModelStreamChunkEvent, TextStreamEvent) are yielded
- The chunk does not contribute to the final message

When chunk is modified:
- The modified chunk is used for all downstream processing
- TextStreamEvent will contain the modified text
- The final message will contain the modified content
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Add BeforeStreamChunkEvent hook for stream chunk interception

1 participant