From e1025db18770bdf6d7f6e799e7b2a67777599747 Mon Sep 17 00:00:00 2001
From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Date: Sat, 22 Aug 2026 17:08:28 +0000
Subject: [PATCH 1/4] Document Python stream_abstraction option
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---
fern/products/sdks/deep-dives/sse-metadata.mdx | 15 +++++++++++++--
.../sdks/generators/python/configuration.mdx | 13 +++++++++++++
2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/fern/products/sdks/deep-dives/sse-metadata.mdx b/fern/products/sdks/deep-dives/sse-metadata.mdx
index 07007044ef..b1476a2be6 100644
--- a/fern/products/sdks/deep-dives/sse-metadata.mdx
+++ b/fern/products/sdks/deep-dives/sse-metadata.mdx
@@ -3,7 +3,7 @@ title: SSE metadata access
description: Access server-sent event metadata (event ID, event type, retry interval) in Fern-generated SDKs for stream resumption and protocol-level control.
---
-When your API uses [server-sent events](/learn/api-definitions/openapi/endpoints/sse#server-sent-events), iterating the generated SDK's streaming response yields parsed data objects. To also read the SSE protocol fields — event ID, event type, and retry interval — TypeScript and Go SDKs expose metadata-aware iteration, typically used to [resume a stream](#stream-resumption) by event ID.
+When your API uses [server-sent events](/learn/api-definitions/openapi/endpoints/sse#server-sent-events), iterating the generated SDK's streaming response yields parsed data objects. To also read the SSE protocol fields — event ID, event type, and retry interval — TypeScript, Python, and Go SDKs expose metadata-aware iteration, typically used to [resume a stream](#stream-resumption) by event ID.
## Metadata-aware iteration
@@ -22,6 +22,17 @@ Each event exposes the parsed data alongside its protocol fields. Default iterat
}
```
+
+ ```python
+ stream = client.plants.stream(query="fern")
+
+ for event in stream.with_metadata():
+ event.data # parsed response object (same type as default iteration)
+ event.id # SSE event ID (str | None)
+ event.event # SSE event type (str | None)
+ event.retry # SSE retry interval in ms (int | None)
+ ```
+
```go
stream := client.Plants.Stream(ctx, &PlantRequest{Query: "fern"})
@@ -45,7 +56,7 @@ Each event exposes the parsed data alongside its protocol fields. Default iterat
-`withMetadata()` requires TypeScript SDK generator version 3.73.0+, and `RecvEvent()` requires Go SDK generator version 1.32.0+.
+`withMetadata()` requires TypeScript SDK generator version 3.73.0+, and `RecvEvent()` requires Go SDK generator version 1.32.0+. In Python, `with_metadata()` requires generator version 5.29.0+ with [`stream_abstraction`](/learn/sdks/generators/python/configuration#stream_abstraction) enabled, which changes streaming methods to return a `Stream` (`AsyncStream` for async clients).
## Stream resumption
diff --git a/fern/products/sdks/generators/python/configuration.mdx b/fern/products/sdks/generators/python/configuration.mdx
index aed978aed4..3033a35f5b 100644
--- a/fern/products/sdks/generators/python/configuration.mdx
+++ b/fern/products/sdks/generators/python/configuration.mdx
@@ -246,6 +246,19 @@ When enabled, the generated SDK resolves the version it reports in the `X-Fern-S
When enabled, skips code formatting (like black) on the generated Python code.
+
+When enabled, streaming endpoints return a `Stream[T]` (`AsyncStream[T]` for async clients) instead of a generator. Iterating the stream yields the parsed payloads, while `with_metadata()` yields them wrapped in a `StreamEvent` that also exposes the [server-sent event metadata](/learn/sdks/deep-dives/sse-metadata): `id`, `event`, and `retry`.
+
+```python
+for event in client.plants.stream(query="fern").with_metadata():
+ print(event.id, event.data)
+```
+
+The request is still issued on first iteration, so errors surface when the stream is first consumed rather than at the call. The stream owns the underlying response and releases it when exhausted, when iteration raises, on `close()`, and on exiting a `with` block (`async with` for `AsyncStream`). `AsyncStream` is awaitable, so both `await client.plants.stream(...)` and a bare `async for` work.
+
+Enabling this changes the return type of streaming methods, which breaks existing callers, so it stays opt-in until the next major version of the generator.
+
+
Sets the client timeout in seconds, or `infinity` to disable timeouts.
From 00f2b9b56224821e501ff2e9cbb2a0a1b5bfce71 Mon Sep 17 00:00:00 2001
From: "devin.logan"
Date: Mon, 24 Aug 2026 17:12:54 +0000
Subject: [PATCH 2/4] docs(python): condense stream_abstraction description
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---
fern/products/sdks/deep-dives/sse-metadata.mdx | 2 +-
fern/products/sdks/generators/python/configuration.mdx | 6 ++----
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/fern/products/sdks/deep-dives/sse-metadata.mdx b/fern/products/sdks/deep-dives/sse-metadata.mdx
index b1476a2be6..52a4ce65c9 100644
--- a/fern/products/sdks/deep-dives/sse-metadata.mdx
+++ b/fern/products/sdks/deep-dives/sse-metadata.mdx
@@ -56,7 +56,7 @@ Each event exposes the parsed data alongside its protocol fields. Default iterat
-`withMetadata()` requires TypeScript SDK generator version 3.73.0+, and `RecvEvent()` requires Go SDK generator version 1.32.0+. In Python, `with_metadata()` requires generator version 5.29.0+ with [`stream_abstraction`](/learn/sdks/generators/python/configuration#stream_abstraction) enabled, which changes streaming methods to return a `Stream` (`AsyncStream` for async clients).
+`withMetadata()` requires TypeScript SDK generator version 3.73.0+, and `RecvEvent()` requires Go SDK generator version 1.32.0+. In Python, `with_metadata()` requires generator version 5.29.0+ with [`stream_abstraction`](/learn/sdks/generators/python/configuration#stream_abstraction) enabled.
## Stream resumption
diff --git a/fern/products/sdks/generators/python/configuration.mdx b/fern/products/sdks/generators/python/configuration.mdx
index 3033a35f5b..02227c8565 100644
--- a/fern/products/sdks/generators/python/configuration.mdx
+++ b/fern/products/sdks/generators/python/configuration.mdx
@@ -247,16 +247,14 @@ When enabled, skips code formatting (like black) on the generated Python code.
-When enabled, streaming endpoints return a `Stream[T]` (`AsyncStream[T]` for async clients) instead of a generator. Iterating the stream yields the parsed payloads, while `with_metadata()` yields them wrapped in a `StreamEvent` that also exposes the [server-sent event metadata](/learn/sdks/deep-dives/sse-metadata): `id`, `event`, and `retry`.
+When enabled, streaming endpoints return a `Stream[T]` (`AsyncStream[T]` for async clients) instead of a generator. Iterating yields the parsed payloads; `with_metadata()` wraps each one in a `StreamEvent` carrying the [server-sent event metadata](/learn/sdks/deep-dives/sse-metadata) fields `id`, `event`, and `retry`.
```python
for event in client.plants.stream(query="fern").with_metadata():
print(event.id, event.data)
```
-The request is still issued on first iteration, so errors surface when the stream is first consumed rather than at the call. The stream owns the underlying response and releases it when exhausted, when iteration raises, on `close()`, and on exiting a `with` block (`async with` for `AsyncStream`). `AsyncStream` is awaitable, so both `await client.plants.stream(...)` and a bare `async for` work.
-
-Enabling this changes the return type of streaming methods, which breaks existing callers, so it stays opt-in until the next major version of the generator.
+The stream stays lazy, issuing the request on first iteration, and releases the underlying response when exhausted, on error, on `close()`, or on exiting a `with` block (`async with` for `AsyncStream`, which is also awaitable). Enabling this option changes the return type of streaming methods, so it remains opt-in until the next major generator version.
From 18137db4d44da868788faac66185e287b7fec473 Mon Sep 17 00:00:00 2001
From: "devin.logan"
Date: Mon, 24 Aug 2026 17:18:24 +0000
Subject: [PATCH 3/4] docs(python): move stream lifecycle detail to SSE deep
dive
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---
fern/products/sdks/deep-dives/sse-metadata.mdx | 2 ++
fern/products/sdks/generators/python/configuration.mdx | 4 ++--
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/fern/products/sdks/deep-dives/sse-metadata.mdx b/fern/products/sdks/deep-dives/sse-metadata.mdx
index 52a4ce65c9..2cf1789e78 100644
--- a/fern/products/sdks/deep-dives/sse-metadata.mdx
+++ b/fern/products/sdks/deep-dives/sse-metadata.mdx
@@ -55,6 +55,8 @@ Each event exposes the parsed data alongside its protocol fields. Default iterat
+The Python `Stream` is lazy: it issues the request on first iteration and releases the response when the stream is exhausted, when iteration raises, on `close()`, or on exiting a `with` block. `AsyncStream` supports `async with` and is awaitable.
+
`withMetadata()` requires TypeScript SDK generator version 3.73.0+, and `RecvEvent()` requires Go SDK generator version 1.32.0+. In Python, `with_metadata()` requires generator version 5.29.0+ with [`stream_abstraction`](/learn/sdks/generators/python/configuration#stream_abstraction) enabled.
diff --git a/fern/products/sdks/generators/python/configuration.mdx b/fern/products/sdks/generators/python/configuration.mdx
index 02227c8565..69a9c68553 100644
--- a/fern/products/sdks/generators/python/configuration.mdx
+++ b/fern/products/sdks/generators/python/configuration.mdx
@@ -247,14 +247,14 @@ When enabled, skips code formatting (like black) on the generated Python code.
-When enabled, streaming endpoints return a `Stream[T]` (`AsyncStream[T]` for async clients) instead of a generator. Iterating yields the parsed payloads; `with_metadata()` wraps each one in a `StreamEvent` carrying the [server-sent event metadata](/learn/sdks/deep-dives/sse-metadata) fields `id`, `event`, and `retry`.
+When enabled, streaming endpoints return a `Stream[T]` (`AsyncStream[T]` for async clients) instead of a generator. Iterating yields the parsed payloads; `with_metadata()` yields them wrapped with the [server-sent event metadata](/learn/sdks/deep-dives/sse-metadata) fields `id`, `event`, and `retry`.
```python
for event in client.plants.stream(query="fern").with_metadata():
print(event.id, event.data)
```
-The stream stays lazy, issuing the request on first iteration, and releases the underlying response when exhausted, on error, on `close()`, or on exiting a `with` block (`async with` for `AsyncStream`, which is also awaitable). Enabling this option changes the return type of streaming methods, so it remains opt-in until the next major generator version.
+This option changes the return type of streaming methods, so it remains opt-in until the next major generator version.
From ee1c55a8405f5bcc5ed4da9dba6d5ed101fb54b6 Mon Sep 17 00:00:00 2001
From: "devin.logan"
Date: Mon, 24 Aug 2026 17:24:22 +0000
Subject: [PATCH 4/4] docs(sse): document stream response lifecycle for all
languages
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---
fern/products/sdks/deep-dives/sse-metadata.mdx | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/fern/products/sdks/deep-dives/sse-metadata.mdx b/fern/products/sdks/deep-dives/sse-metadata.mdx
index 2cf1789e78..23ae5f6dc7 100644
--- a/fern/products/sdks/deep-dives/sse-metadata.mdx
+++ b/fern/products/sdks/deep-dives/sse-metadata.mdx
@@ -55,7 +55,11 @@ Each event exposes the parsed data alongside its protocol fields. Default iterat
-The Python `Stream` is lazy: it issues the request on first iteration and releases the response when the stream is exhausted, when iteration raises, on `close()`, or on exiting a `with` block. `AsyncStream` supports `async with` and is awaitable.
+Each stream owns the underlying HTTP response, and releases it differently per language:
+
+* **TypeScript**: the body is released when iteration ends and cancelled when you break out of the loop. An `abortSignal` in the request options stops the stream from outside.
+* **Python**: the stream is lazy, issuing the request on first iteration, and releases the response when it's exhausted, when iteration raises, on `close()`, or on exiting a `with` block. `AsyncStream` supports `async with` and is awaitable.
+* **Go**: the stream never closes the body on its own, so `defer stream.Close()` is required.
`withMetadata()` requires TypeScript SDK generator version 3.73.0+, and `RecvEvent()` requires Go SDK generator version 1.32.0+. In Python, `with_metadata()` requires generator version 5.29.0+ with [`stream_abstraction`](/learn/sdks/generators/python/configuration#stream_abstraction) enabled.