Pattern: Structured Analysis
Use structured output to build type-safe analysis tools with real-time partial results.
SvelteKit Implementation
svelte
<script lang="ts">
import { StructuredStream } from "@aibind/sveltekit";
import { z } from "zod/v4";
const ReviewSchema = z.object({
sentiment: z.enum(["positive", "negative", "neutral", "mixed"]),
confidence: z.number().min(0).max(1),
topics: z.array(
z.object({
name: z.string(),
sentiment: z.enum(["positive", "negative", "neutral"]),
}),
),
summary: z.string(),
actionItems: z.array(z.string()).optional(),
});
const review = new StructuredStream({
schema: ReviewSchema,
model: "smart",
system: "Analyze the given review. Be thorough and objective.",
});
let input = $state("");
</script>
<textarea bind:value={input} placeholder="Paste a review..." rows="6" />
<button
onclick={() => review.send(`Analyze: ${input}`)}
disabled={review.loading}
>
{review.loading ? "Analyzing..." : "Analyze"}
</button>
{#if review.partial}
<div class="results">
{#if review.partial.sentiment}
<div
class="badge"
class:positive={review.partial.sentiment === "positive"}
class:negative={review.partial.sentiment === "negative"}
>
{review.partial.sentiment}
{#if review.partial.confidence != null}
({(review.partial.confidence * 100).toFixed(0)}%)
{/if}
</div>
{/if}
{#if review.partial.topics?.length}
<h3>Topics</h3>
<ul>
{#each review.partial.topics as topic}
<li>{topic.name} — {topic.sentiment}</li>
{/each}
</ul>
{/if}
{#if review.partial.summary}
<h3>Summary</h3>
<p>{review.partial.summary}</p>
{/if}
{#if review.partial.actionItems?.length}
<h3>Action Items</h3>
<ul>
{#each review.partial.actionItems as item}
<li>{item}</li>
{/each}
</ul>
{/if}
</div>
{/if}Key Patterns
Schema Design
- Use
z.enum()for categorical values — they resolve first and can be shown immediately - Put arrays last — they fill in progressively
- Optional fields with
.optional()appear only when the AI decides to include them
Partial Rendering
The partial property is DeepPartial<T> — every field is potentially undefined. Always use optional chaining:
ts
review.partial?.topics?.length; // Safe
review.partial.topics.length; // May crash during streamingError Recovery
If the AI generates invalid JSON that doesn't match your schema, error is set with validation details:
svelte
{#if review.error}
<p class="error">{review.error.message}</p>
<button onclick={() => review.retry()}>Retry</button>
{/if}