> ## Documentation Index
> Fetch the complete documentation index at: https://docs.idyllic.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Multiple Streams

> Stream multiple fields simultaneously to the client

# Multiple Streams

Real applications often need to stream multiple pieces of content simultaneously. A code reviewer might display issues, suggestions, and improved code in separate panels. A research assistant might summarize multiple sources before synthesizing them. Idyllic supports these patterns through multiple `stream<T>` fields, each operating independently.

## Defining Multiple Stream Fields

Declare multiple `stream<T>` fields. Each maintains its own value, status, and update history:

```typescript theme={null}
export default class CodeReviewer extends AgenticSystem {
  @field issues = stream<string>('');
  @field suggestions = stream<string>('');
  @field improvedCode = stream<string>('');
  @field status: 'idle' | 'reviewing' = 'idle';

  @action()
  async review(code: string) {
    this.status = 'reviewing';
    await this.analyzeCode(code);
    this.status = 'idle';
  }
}
```

Every `append()` call broadcasts to all connected clients. The framework handles multiplexing automatically.

## Sequential Streaming

Complete one stream before starting the next. Works when later streams depend on earlier content:

```typescript theme={null}
@action()
async review(code: string) {
  this.status = 'reviewing';

  // First: stream issues
  for await (const chunk of this.findIssues(code)) {
    this.issues.append(chunk);
  }
  this.issues.complete();

  // Second: stream suggestions based on issues
  for await (const chunk of ai.stream(`Suggest fixes for:\n${this.issues.current}`)) {
    this.suggestions.append(chunk);
  }
  this.suggestions.complete();

  // Third: stream improved code
  for await (const chunk of ai.stream(`Improve:\n${code}`)) {
    this.improvedCode.append(chunk);
  }
  this.improvedCode.complete();

  this.status = 'idle';
}
```

Each section finishes before the next begins, creating predictable reading flow.

## Parallel Streaming

When streams are independent, update them simultaneously with `Promise.all`:

```typescript theme={null}
export default class ResearchSynthesizer extends AgenticSystem {
  @field summaries: Array<{ source: string; content: StreamableValue<string> }> = [];
  @field synthesis = stream<string>('');
  @field status: 'idle' | 'summarizing' | 'synthesizing' = 'idle';

  @action()
  async synthesize(sources: string[]) {
    this.status = 'summarizing';

    // Create streams for each source
    this.summaries = sources.map(source => ({
      source,
      content: stream<string>(''),
    }));

    // Stream all in parallel
    await Promise.all(
      sources.map(async (source, i) => {
        for await (const chunk of ai.stream(`Summarize: ${source}`)) {
          this.summaries[i].content.append(chunk);
        }
        this.summaries[i].content.complete();
      })
    );

    // Then synthesize
    this.status = 'synthesizing';
    const allContent = this.summaries.map(s => s.content.current).join('\n\n');

    for await (const chunk of ai.stream(`Synthesize:\n${allContent}`)) {
      this.synthesis.append(chunk);
    }
    this.synthesis.complete();

    this.status = 'idle';
  }
}
```

Clients see multiple cards streaming simultaneously. Fast sources don't block slow ones.

## Client-Side Rendering

Iterate over streams, showing status for each:

```tsx theme={null}
function ResearchView() {
  const { summaries, synthesis, status } = useSystem<ResearchSynthesizer>();

  return (
    <div>
      <StatusBadge status={status} />

      <div className="summaries">
        {summaries.map((summary, i) => (
          <SummaryCard key={i} source={summary.source}>
            {summary.content.current}
            {summary.content.status === 'streaming' && <Cursor />}
          </SummaryCard>
        ))}
      </div>

      {synthesis.current && (
        <div className="synthesis">
          {synthesis.current}
          {synthesis.status === 'streaming' && <Cursor />}
        </div>
      )}
    </div>
  );
}
```

***

## FAQ

### How many streams can run in parallel?

No hard limit. Practical constraints are LLM rate limits and client rendering performance. Ten simultaneous streams work fine.

### What if one parallel stream fails?

With `Promise.all`, one failure rejects the group. Use `Promise.allSettled` for independent error handling:

```typescript theme={null}
await Promise.allSettled(
  sources.map(async (source, i) => {
    try {
      await this.streamSource(source, i);
    } catch (e) {
      this.summaries[i].content.fail(e);
    }
  })
);
```

### How do I show overall progress?

Track completion count in state:

```typescript theme={null}
@field completedCount = 0;

// After each stream completes
this.summaries[i].content.complete();
this.completedCount++;
```

Client can show "3 of 5 sources analyzed."
