Skip to main content

Code Reviewer

A code review tool that produces three outputs simultaneously: issues, suggestions, and refactored code. All three stream in parallel—users see all panels filling at the same time, with updates interleaving as each LLM generates tokens.

Server Code

import { AgenticSystem, field, action, stream } from 'idyllic';

export default class CodeReviewer extends AgenticSystem {
  @field code = '';
  @field language = 'typescript';
  @field issues = stream<string>('');
  @field suggestions = stream<string>('');
  @field improved = stream<string>('');
  @field status: 'idle' | 'reviewing' = 'idle';

  @action()
  async setCode(code: string, language?: string) {
    this.code = code;
    if (language) this.language = language;
  }

  @action()
  async review() {
    this.status = 'reviewing';
    this.issues.reset();
    this.suggestions.reset();
    this.improved.reset();

    await Promise.all([
      this.findIssues(),
      this.generateSuggestions(),
      this.improveCode(),
    ]);

    this.status = 'idle';
  }

  private async findIssues() {
    for await (const chunk of ai.stream(
      `List issues in this ${this.language} code:\n\n${this.code}`
    )) {
      this.issues.append(chunk);
    }
    this.issues.complete();
  }

  private async generateSuggestions() {
    for await (const chunk of ai.stream(
      `Suggest improvements for this ${this.language} code:\n\n${this.code}`
    )) {
      this.suggestions.append(chunk);
    }
    this.suggestions.complete();
  }

  private async improveCode() {
    for await (const chunk of ai.stream(
      `Refactor this ${this.language} code with best practices:\n\n${this.code}`
    )) {
      this.improved.append(chunk);
    }
    this.improved.complete();
  }
}
The review action runs three streaming methods concurrently with Promise.all. Each method appends to its own stream. The framework multiplexes these updates over the single WebSocket connection. The private methods don’t have @action(), so clients can’t call them directly. Only setCode and review are exposed.

Client Code

import { useSystem } from '@idyllic/react';
import type { CodeReviewer } from '../systems/CodeReviewer';

export default function ReviewerUI() {
  const { code, language, issues, suggestions, improved, status, setCode, review } = useSystem<CodeReviewer>();
  const isReviewing = status === 'reviewing';

  return (
    <div className="flex flex-col h-screen p-4">
      <div className="mb-4">
        <div className="flex gap-2 mb-2">
          <select
            value={language}
            onChange={e => setCode(code, e.target.value)}
            className="px-3 py-2 border rounded"
          >
            <option value="typescript">TypeScript</option>
            <option value="python">Python</option>
            <option value="go">Go</option>
          </select>
          <button
            onClick={review}
            disabled={isReviewing || !code}
            className="px-4 py-2 bg-blue-600 text-white rounded disabled:opacity-50"
          >
            {isReviewing ? 'Reviewing...' : 'Review Code'}
          </button>
        </div>
        <textarea
          value={code}
          onChange={e => setCode(e.target.value)}
          className="w-full h-48 p-3 border rounded font-mono text-sm"
          placeholder="Paste your code here..."
        />
      </div>

      <div className="flex-1 grid grid-cols-3 gap-4">
        <Panel title="Issues" content={issues.current} streaming={isReviewing} />
        <Panel title="Suggestions" content={suggestions.current} streaming={isReviewing} />
        <Panel title="Improved" content={improved.current} streaming={isReviewing} mono />
      </div>
    </div>
  );
}

function Panel({ title, content, streaming, mono }: {
  title: string; content: string; streaming: boolean; mono?: boolean;
}) {
  return (
    <div className="flex flex-col border rounded">
      <h3 className="px-3 py-2 bg-gray-100 font-medium border-b">{title}</h3>
      <div className={`flex-1 p-3 overflow-auto whitespace-pre-wrap ${mono ? 'font-mono text-sm' : ''}`}>
        {content}
        {streaming && <span className="animate-pulse">|</span>}
      </div>
    </div>
  );
}

Running the Example

npx idyllic dev
Paste code with obvious issues. Click Review. All three panels fill simultaneously—Issues typically finishes first, Improved takes longest. Each cursor disappears as its stream completes.

Why Parallel Streaming Matters

Without a framework, building this requires substantial infrastructure: WebSocket multiplexing to route interleaved updates, client-side routing to the correct UI components. With Idyllic: define streaming fields, run concurrent async methods, let the framework handle multiplexing. The complexity of parallel streams never leaks into your code.