Skip to content

[STG-1607] Yield finished SSE event instead of silently dropping it#1846

Merged
shrey150 merged 2 commits intomainfrom
aq17/stg-1607
Mar 18, 2026
Merged

[STG-1607] Yield finished SSE event instead of silently dropping it#1846
shrey150 merged 2 commits intomainfrom
aq17/stg-1607

Conversation

@aq17
Copy link
Contributor

@aq17 aq17 commented Mar 18, 2026

why

Customer reported a bug in the Python SDK (stagehand-python v3.6.0).

In src/stagehand/_streaming.py, both the sync Stream.stream() (line 62-63) and async AsyncStream.stream() (line 147-148) have:

python
if sse.data.startswith('{"data":{"status":"finished"'):
    break  # ← drops the event without yielding it

When the server sends the finished SSE event (which contains success, message, actions, usage, and messages), the SDK immediately breaks out of the loop without yielding the event to the caller. This means the final result payload is silently dropped.

what changed

The streaming on_event config had handle: done for the {"data":{"status":"finished"...}} event. Stainless generates this as a bare break, which exits the SSE loop without yielding the event – silently dropping the final result payload (success status, message, actions, usage, and messages) from every streaming response.

Fix – Changed to handle: yield so the finished event is delivered to callers before the stream terminates. This is safe because the server explicitly calls reply.raw.end() immediately after sending the finished event (packages/server-v3/src/lib/stream.ts), so the SSE connection closes right after the yield and the loop exits naturally on EOF – no hang risk.

test plan

Regenerate SDKs and confirm fix

@aq17 aq17 requested a review from a team March 18, 2026 17:40
@aq17 aq17 self-assigned this Mar 18, 2026
@changeset-bot
Copy link

changeset-bot bot commented Mar 18, 2026

🦋 Changeset detected

Latest commit: 066c4c5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@browserbasehq/stagehand Patch
@browserbasehq/browse-cli Patch
@browserbasehq/stagehand-evals Patch
@browserbasehq/stagehand-server-v3 Patch
@browserbasehq/stagehand-server-v4 Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Contributor

github-actions bot commented Mar 18, 2026

✱ Stainless preview builds

This PR will update the stagehand SDKs with the following commit message.

feat: [STG-1607] Yield finished SSE event instead of silently dropping it
stagehand-ruby studio · code

Your SDK build had at least one "note" diagnostic.
generate ✅build ⏭️lint ✅test ✅

stagehand-openapi studio · code

Your SDK build had at least one "note" diagnostic.
generate ✅

stagehand-php studio · code

Your SDK build had at least one "note" diagnostic.
generate ✅lint ✅test ✅

stagehand-go studio · code

Your SDK build had at least one "note" diagnostic.
generate ✅build ⏭️lint ✅test ✅

go get github.com/stainless-sdks/stagehand-go@0d81aaac2388be111da866e09feee7ffc12552d3
stagehand-kotlin studio · code

Your SDK build had at least one "note" diagnostic.
generate ✅build ✅lint ✅test ✅

stagehand-typescript studio · code

generate ✅build ⏳lint ✅test ⏳

stagehand-python studio · code

Your SDK build had at least one "note" diagnostic.
generate ✅build ✅lint ✅test ✅

pip install https://pkg.stainless.com/s/stagehand-python/0bba1e9c657cffbbe306a2bc6520ab2992295773/stagehand-3.6.0-py3-none-any.whl
stagehand-java studio · code

Your SDK build had at least one "note" diagnostic.
generate ✅build ✅lint ✅test ✅

Add the following URL as a Maven source: 'https://pkg.stainless.com/s/stagehand-java/72fa6531d9996c0653fa610b5b05e8027c3a450b/mvn'
⚠️ stagehand-csharp studio · code

Your SDK build had a failure in the build CI job, which is a regression from the base state.
generate ⚠️build ❗lint ❗test ✅

⏳ These are partial results; builds are still running.


This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-03-18 18:36:28 UTC

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 18, 2026

Greptile Summary

This PR fixes a bug where the terminal SSE event (status: "finished") — which carries the final result, actionId, and success metadata — was silently dropped by all Stainless-generated SDKs (Python, Go, Java, Kotlin, Ruby, TypeScript, PHP, C#) instead of being delivered to the caller.

Root cause: stainless.yml had handle: done for the finished event, which Stainless generates as a bare break that exits the SSE loop without yielding the event.

Fix: Changing to handle: yield makes Stainless generate code that yields the finished event to the caller before the loop exits. This is safe because packages/server-v3/src/lib/stream.ts (and server-v4) calls reply.raw.end() immediately after emitting the finished event, so the client loop terminates naturally on EOF with no hang risk.

Key changes:

  • stainless.yml: One-line fix — handle: donehandle: yield for the {"data":{"status":"finished" SSE event pattern
  • Applies globally to all SDK targets (Python, Go, Java, Kotlin, Ruby, TypeScript, PHP, C#) through the top-level streaming.on_event configuration

Confidence Score: 5/5

  • This PR is safe to merge — it is a minimal, well-reasoned one-line config fix that restores correct SSE behavior across all generated SDKs.
  • The change is a single-line fix in the Stainless code-generation config. The server-side code in both server-v3 and server-v4 confirms that reply.raw.end() is called immediately after the finished event is sent, making the handle: yield approach safe with no hang risk. The fix correctly addresses the root cause of the silent payload drop reported by Monarch Money.
  • No files require special attention.

Important Files Changed

Filename Overview
stainless.yml Changes the streaming on_event handler for the finished SSE event from done (break without yielding) to yield (deliver event, then exit naturally on EOF), fixing the silent drop of the final result payload across all generated SDKs.

Sequence Diagram

sequenceDiagram
    participant C as SDK Client
    participant S as Server (stream.ts)

    Note over C,S: BEFORE (handle: done)
    S->>C: SSE: {"data":{"status":"starting",...}}
    S->>C: SSE: {"data":{"status":"connected",...}}
    S->>C: SSE: {"data":{"status":"running",...}} (0..n)
    S->>C: SSE: {"data":{"status":"finished", result, actionId}}
    Note over C: break — event silently dropped ❌
    S-->>C: EOF (reply.raw.end())
    Note over C: Caller never receives result

    Note over C,S: AFTER (handle: yield)
    S->>C: SSE: {"data":{"status":"starting",...}}
    S->>C: SSE: {"data":{"status":"connected",...}}
    S->>C: SSE: {"data":{"status":"running",...}} (0..n)
    S->>C: SSE: {"data":{"status":"finished", result, actionId}}
    Note over C: yield — event delivered to caller ✅
    S-->>C: EOF (reply.raw.end())
    Note over C: Loop exits naturally on EOF
Loading

Last reviewed commit: "fix: yield finished ..."

Copy link
Contributor

@cubic-dev-ai cubic-dev-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.

cubic analysis

No issues found across 1 file

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Linked issue analysis

Linked issue: STG-1607: Fix bug in Python SDK to yield finished SSE events

Status Acceptance criteria Notes
Change streaming handling so the finished SSE event is yielded instead of dropped Updated stainless.yml to use handle: yield for finished event
Apply the fix to both sync Stream.__stream__() and async AsyncStream.__stream__() in the Python SDK No modifications to src/stagehand/_streaming.py shown in PR
⚠️ Ensure yielding the finished event does not hang the stream (stream terminates naturally on EOF) PR rationale explains safety but no tests or server changes included
Regenerate SDKs and confirm the Python fix (test plan: regenerated SDKs and confirm python fix) No regenerated SDK files or test confirmations present in diffs

Copy link
Contributor

@shrey150 shrey150 left a comment

Choose a reason for hiding this comment

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

Nice! As a sanity check, I'd have @monadoid take a look, but this fix makes sense to me. Can you add a changeset so a patch version is generated & reported in changelog?

@shrey150 shrey150 merged commit 335cf47 into main Mar 18, 2026
31 checks passed
@aq17 aq17 deleted the aq17/stg-1607 branch March 18, 2026 18:26
@github-actions github-actions bot mentioned this pull request Mar 17, 2026
@pirate
Copy link
Member

pirate commented Mar 18, 2026

great catch, thank you for debugging + fixing this @aq17!

miguelg719 pushed a commit that referenced this pull request Mar 18, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @browserbasehq/browse-cli@0.2.0

### Minor Changes

- [#1816](#1816)
[`687d54a`](687d54a)
Thanks [@shrey150](https://github.com/shrey150)! - Add `--context-id`
and `--persist` flags to `browse open` for loading and persisting
Browserbase Contexts across sessions

- [#1793](#1793)
[`e38c13b`](e38c13b)
Thanks [@shrey150](https://github.com/shrey150)! - Initial release of
browse CLI - browser automation for AI agents

### Patch Changes

- [#1806](#1806)
[`f8c7738`](f8c7738)
Thanks [@shrey150](https://github.com/shrey150)! - Fix `browse env`
showing stale mode after `browse env remote`

- Updated dependencies
\[[`505e8c6`](505e8c6),
[`2f43ffa`](2f43ffa),
[`63ee247`](63ee247),
[`7dc35f5`](7dc35f5),
[`335cf47`](335cf47),
[`6ba0a1d`](6ba0a1d),
[`4ff3bb8`](4ff3bb8),
[`c27054b`](c27054b),
[`2abf5b9`](2abf5b9),
[`7817fcc`](7817fcc),
[`7390508`](7390508),
[`611f43a`](611f43a),
[`521a10e`](521a10e),
[`2402a3c`](2402a3c)]:
    -   @browserbasehq/stagehand@3.2.0

## @browserbasehq/stagehand@3.2.0

### Minor Changes

- [#1779](#1779)
[`2f43ffa`](2f43ffa)
Thanks [@shrey150](https://github.com/shrey150)! - feat: add
`cdpHeaders` option to `localBrowserLaunchOptions` for passing custom
HTTP headers when connecting to an existing browser via CDP URL

- [#1834](#1834)
[`63ee247`](63ee247)
Thanks [@tkattkat](https://github.com/tkattkat)! - Update stagehand
agents search tool

- [#1774](#1774)
[`521a10e`](521a10e)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add new
page.setExtraHTTPHeaders() method

### Patch Changes

- [#1759](#1759)
[`505e8c6`](505e8c6)
Thanks [@shrey150](https://github.com/shrey150)! - Add bedrock to the
provider enum in model configuration schemas and regenerate OpenAPI
spec.

- [#1814](#1814)
[`7dc35f5`](7dc35f5)
Thanks [@tkattkat](https://github.com/tkattkat)! - Change usage of
openai provider in agent to default to store:false

- [#1846](#1846)
[`335cf47`](335cf47)
Thanks [@aq17](https://github.com/aq17)! - Fix streaming finished event
being silently dropped. The final SSE event containing the result
payload (success status, message, actions, usage, and messages) was
previously discarded instead of being yielded to the caller.

- [#1764](#1764)
[`6ba0a1d`](6ba0a1d)
Thanks [@shrey150](https://github.com/shrey150)! - Expose `headers` in
`GoogleVertexProviderSettings` so model configs can pass custom provider
headers (for example `X-Goog-Priority`) without TypeScript errors.

- [#1847](#1847)
[`4ff3bb8`](4ff3bb8)
Thanks [@miguelg719](https://github.com/miguelg719)! - Enable FlowLogger
on BROWSERBASE_FLOW_LOGS=1

- [#1752](#1752)
[`c27054b`](c27054b)
Thanks [@derekmeegan](https://github.com/derekmeegan)! - fix: pause
Browserbase agents while captcha solving is active and improve CUA
recovery after the solve completes

- [#1800](#1800)
[`2abf5b9`](2abf5b9)
Thanks [@shrey150](https://github.com/shrey150)! - Make projectId
optional for Browserbase sessions — only BROWSERBASE_API_KEY is required

- [#1766](#1766)
[`7817fcc`](7817fcc)
Thanks [@tkattkat](https://github.com/tkattkat)! - Add configurable
timeout to tools in agent

- [#1749](#1749)
[`7390508`](7390508)
Thanks [@pirate](https://github.com/pirate)! - When connecting to a
browser session that has zero open tabs, Stagehand now automatically
creates an initial `about:blank` tab so the connection can continue.

- [#1761](#1761)
[`611f43a`](611f43a)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix issue
where handlePossibleNavigation was producing unnecessary error logs on
clicks that trigger page close

- [#1817](#1817)
[`2402a3c`](2402a3c)
Thanks [@tkattkat](https://github.com/tkattkat)! - Add support for
passing custom headers in clientOptions

## @browserbasehq/stagehand-evals@1.1.9

### Patch Changes

- Updated dependencies
\[[`505e8c6`](505e8c6),
[`2f43ffa`](2f43ffa),
[`63ee247`](63ee247),
[`7dc35f5`](7dc35f5),
[`335cf47`](335cf47),
[`6ba0a1d`](6ba0a1d),
[`4ff3bb8`](4ff3bb8),
[`c27054b`](c27054b),
[`2abf5b9`](2abf5b9),
[`7817fcc`](7817fcc),
[`7390508`](7390508),
[`611f43a`](611f43a),
[`521a10e`](521a10e),
[`2402a3c`](2402a3c)]:
    -   @browserbasehq/stagehand@3.2.0

## @browserbasehq/stagehand-server-v3@3.6.1

### Patch Changes

- [#1759](#1759)
[`505e8c6`](505e8c6)
Thanks [@shrey150](https://github.com/shrey150)! - Add bedrock to the
provider enum in model configuration schemas and regenerate OpenAPI
spec.

- Updated dependencies
\[[`505e8c6`](505e8c6),
[`2f43ffa`](2f43ffa),
[`63ee247`](63ee247),
[`7dc35f5`](7dc35f5),
[`335cf47`](335cf47),
[`6ba0a1d`](6ba0a1d),
[`4ff3bb8`](4ff3bb8),
[`c27054b`](c27054b),
[`2abf5b9`](2abf5b9),
[`7817fcc`](7817fcc),
[`7390508`](7390508),
[`611f43a`](611f43a),
[`521a10e`](521a10e),
[`2402a3c`](2402a3c)]:
    -   @browserbasehq/stagehand@3.2.0

## @browserbasehq/stagehand-server-v4@3.6.1

### Patch Changes

- Updated dependencies
\[[`505e8c6`](505e8c6),
[`2f43ffa`](2f43ffa),
[`63ee247`](63ee247),
[`7dc35f5`](7dc35f5),
[`335cf47`](335cf47),
[`6ba0a1d`](6ba0a1d),
[`4ff3bb8`](4ff3bb8),
[`c27054b`](c27054b),
[`2abf5b9`](2abf5b9),
[`7817fcc`](7817fcc),
[`7390508`](7390508),
[`611f43a`](611f43a),
[`521a10e`](521a10e),
[`2402a3c`](2402a3c)]:
    -   @browserbasehq/stagehand@3.2.0

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

4 participants