Streaming

Stream generated text as it arrives with DeepSeekWeb.stream(). Handle stream chunks, retries, cancellation, timeouts, and validated structured output.

DeepSeekWeb.stream() generates a response incrementally and returns a promise that resolves to an async iterable. Instead of waiting for the complete answer, your application can process each chunk as it arrives.

Getting started

Create a DeepSeekWeb client with your model and credentials, then call stream() with a prompt. Both the dsSessionId session cookie and authorization value are required. DeepSeek does not provide a guest mode.

src/stream.ts
import 'dotenv/config'import { DeepSeekWeb } from '@orcushq/deepseek' const model = new DeepSeekWeb({  model: 'deepseek-v3',  dsSessionId: process.env.DEEPSEEK_SESSION_ID ?? '',  authorization: process.env.DEEPSEEK_AUTHORIZATION ?? '',}) const stream = await model.stream(  'Write a haiku about servers.',) for await (const chunk of stream) {  if (chunk.content) {    process.stdout.write(chunk.content)  }   if (chunk.done) {    console.log('\nStreaming complete.')  }}

Set DEEPSEEK_SESSION_ID and DEEPSEEK_AUTHORIZATION in your .env file. The example uses dotenv/config to load these values. The SDK validates credentials when preparing the request and raises an authentication error if either value is missing.

Understanding stream chunks

Each DeepSeekStreamChunk contains the following fields:

  • `content` - Newly generated answer text in the current chunk. It is an empty string when the chunk contains no new answer text.
  • `accumulated` - The complete answer text emitted so far during the current successful attempt.
  • `thinking` - Newly emitted thinking content in the current chunk, when available.
  • `accumulatedThinking` - Thinking content accumulated so far during the current attempt.
  • `done` - Set to true on the final chunk of a successful stream.
typescript
const stream = await model.stream(  'Explain how an API works.',) for await (const chunk of stream) {  if (chunk.content) {    process.stdout.write(chunk.content)  }   console.log({    accumulated: chunk.accumulated,    done: chunk.done,  })}

Chunk metadata

Stream chunks do not expose `model`, `requestedModel`, `modelFellBack`, `fallbackReason`, or `authenticationMode`. To inspect the model resolution before making a request, use `model.resolveModelFor()`. Do not treat the resolved model ID as proof of which backend model actually served the response.

Retries

Streaming retries are enabled by default. Configure the retry policy in the client configuration or per-call options, or use retry: false to disable retries for that stream. The default policy allows three attempts with a 2-second initial delay, a backoff factor of 2, and a maximum delay of 30 seconds. In the current implementation, stream() is the operation that forwards the constructor-level retry policy to its turn-level retry logic.

When a retry starts, the SDK resets the failed attempt’s accumulated response and starts a fresh completion attempt. Non-retryable typed errors are propagated without another attempt. Rate-limit responses can provide a Retry-After delay that the SDK respects within the configured maximum delay.

typescript
const stream = await model.stream(  'Explain retries in distributed systems.',  {    retry: false,  },) for await (const chunk of stream) {  if (chunk.content) {    process.stdout.write(chunk.content)  }}

Retries can repeat visible text

If a stream fails after emitting chunks, your application may already have displayed part of the answer. A retry starts a new attempt, so previously displayed text cannot be retracted and repeated text is possible. The SDK does not guarantee deduplication or consistency between answers from separate attempts.

Cancellation and timeouts

Pass an AbortSignal to cancel a stream. Use timeoutMs to configure the request timeout in milliseconds. A timeout of 0 disables the configured timeout.

typescript
const controller = new AbortController() const timeout = setTimeout(() => {  controller.abort()}, 5000) try {  const stream = await model.stream(    'Write a long essay about distributed systems.',    {      signal: controller.signal,    },  )   for await (const chunk of stream) {    if (chunk.content) {      process.stdout.write(chunk.content)    }  }} finally {  clearTimeout(timeout)}

When the caller aborts the request, the SDK raises DeepSeekAbortError. You can also set timeoutMs in the client configuration or pass it as an invocation option to override the timeout for a particular call.

Streaming structured output

Use withStructuredOutput() with a Zod schema when you want streamed output to be parsed as JSON and validated. The structured stream exposes content, accumulated, done, and partial.

typescript
import { z } from 'zod' const person = z.object({  name: z.string(),  age: z.number(),}) const structured = model.withStructuredOutput(person) for await (const chunk of structured.stream(  'Return a JSON object for a person named Vikas who is 21 years old.',)) {  if (chunk.partial !== undefined) {    console.log(chunk.partial)  }}
  • `content` - Newly generated text in the current chunk.
  • `accumulated` - The accumulated output text.
  • `done` - Indicates the final chunk of a successful stream.
  • `partial` - The parsed and validated value when the accumulated output is valid; otherwise, undefined.

Structured partials are best effort

The SDK validates the accumulated output against the complete Zod schema. `partial` remains `undefined` while the output is incomplete or invalid. If the final output cannot be parsed or fails schema validation, the stream raises `DeepSeekStructuredOutputError`. The schema is communicated through prompt instructions; this is not native backend JSON Schema enforcement.

Important notes

  • Streaming returns an async iterable of chunks, not the DeepSeekResponse object returned by invoke().
  • The client updates its carried conversation state only when stream iteration completes successfully.
  • If you stop consuming the stream early, the client does not commit that turn as completed.
  • Use invoke() when you need the complete response object, including response metadata and citations.