docs: add examples for structured output and task retry

This commit is contained in:
JackChen 2026-04-03 14:23:22 +08:00
parent 043deaf562
commit 27c0103736
3 changed files with 207 additions and 0 deletions

View File

@ -125,6 +125,8 @@ npx tsx examples/01-single-agent.ts
| [07 — Fan-Out / Aggregate](examples/07-fan-out-aggregate.ts) | `runParallel()` MapReduce — 3 analysts in parallel, then synthesize | | [07 — Fan-Out / Aggregate](examples/07-fan-out-aggregate.ts) | `runParallel()` MapReduce — 3 analysts in parallel, then synthesize |
| [08 — Gemma 4 Local](examples/08-gemma4-local.ts) | Pure-local Gemma 4 agent team with tool-calling — zero API cost | | [08 — Gemma 4 Local](examples/08-gemma4-local.ts) | Pure-local Gemma 4 agent team with tool-calling — zero API cost |
| [09 — Gemma 4 Auto-Orchestration](examples/09-gemma4-auto-orchestration.ts) | `runTeam()` with Gemma 4 as coordinator — auto task decomposition, fully local | | [09 — Gemma 4 Auto-Orchestration](examples/09-gemma4-auto-orchestration.ts) | `runTeam()` with Gemma 4 as coordinator — auto task decomposition, fully local |
| [10 — Structured Output](examples/10-structured-output.ts) | `outputSchema` (Zod) on AgentConfig — validated JSON via `result.structured` |
| [11 — Task Retry](examples/11-task-retry.ts) | `maxRetries` / `retryDelayMs` / `retryBackoff` with `task_retry` progress events |
## Architecture ## Architecture

View File

@ -0,0 +1,73 @@
/**
* Example 10 Structured Output
*
* Demonstrates `outputSchema` on AgentConfig. The agent's response is
* automatically parsed as JSON and validated against a Zod schema.
* On validation failure, the framework retries once with error feedback.
*
* The validated result is available via `result.structured`.
*
* Run:
* npx tsx examples/10-structured-output.ts
*
* Prerequisites:
* ANTHROPIC_API_KEY env var must be set.
*/
import { z } from 'zod'
import { OpenMultiAgent } from '../src/index.js'
import type { AgentConfig } from '../src/types.js'
// ---------------------------------------------------------------------------
// Define a Zod schema for the expected output
// ---------------------------------------------------------------------------
const ReviewAnalysis = z.object({
summary: z.string().describe('One-sentence summary of the review'),
sentiment: z.enum(['positive', 'negative', 'neutral']),
confidence: z.number().min(0).max(1).describe('How confident the analysis is'),
keyTopics: z.array(z.string()).describe('Main topics mentioned in the review'),
})
type ReviewAnalysis = z.infer<typeof ReviewAnalysis>
// ---------------------------------------------------------------------------
// Agent with outputSchema
// ---------------------------------------------------------------------------
const analyst: AgentConfig = {
name: 'analyst',
model: 'claude-sonnet-4-6',
systemPrompt: 'You are a product review analyst. Analyze the given review and extract structured insights.',
outputSchema: ReviewAnalysis,
}
// ---------------------------------------------------------------------------
// Run
// ---------------------------------------------------------------------------
const orchestrator = new OpenMultiAgent({ defaultModel: 'claude-sonnet-4-6' })
const reviews = [
'This keyboard is amazing! The mechanical switches feel incredible and the RGB lighting is stunning. Build quality is top-notch. Only downside is the price.',
'Terrible experience. The product arrived broken, customer support was unhelpful, and the return process took 3 weeks.',
'It works fine. Nothing special, nothing bad. Does what it says on the box.',
]
console.log('Analyzing product reviews with structured output...\n')
for (const review of reviews) {
const result = await orchestrator.runAgent(analyst, `Analyze this review: "${review}"`)
if (result.structured) {
const data = result.structured as ReviewAnalysis
console.log(`Sentiment: ${data.sentiment} (confidence: ${data.confidence})`)
console.log(`Summary: ${data.summary}`)
console.log(`Topics: ${data.keyTopics.join(', ')}`)
} else {
console.log(`Validation failed. Raw output: ${result.output.slice(0, 100)}`)
}
console.log(`Tokens: ${result.tokenUsage.input_tokens} in / ${result.tokenUsage.output_tokens} out`)
console.log('---')
}

132
examples/11-task-retry.ts Normal file
View File

@ -0,0 +1,132 @@
/**
* Example 11 Task Retry with Exponential Backoff
*
* Demonstrates `maxRetries`, `retryDelayMs`, and `retryBackoff` on task config.
* When a task fails, the framework automatically retries with exponential
* backoff. The `onProgress` callback receives `task_retry` events so you can
* log retry attempts in real time.
*
* Scenario: a two-step pipeline where the first task (data fetch) is configured
* to retry on failure, and the second task (analysis) depends on it.
*
* Run:
* npx tsx examples/11-task-retry.ts
*
* Prerequisites:
* ANTHROPIC_API_KEY env var must be set.
*/
import { OpenMultiAgent } from '../src/index.js'
import type { AgentConfig, OrchestratorEvent } from '../src/types.js'
// ---------------------------------------------------------------------------
// Agents
// ---------------------------------------------------------------------------
const fetcher: AgentConfig = {
name: 'fetcher',
model: 'claude-sonnet-4-6',
systemPrompt: `You are a data-fetching agent. When given a topic, produce a short
JSON summary with 3-5 key facts. Output ONLY valid JSON, no markdown fences.
Example: {"topic":"...", "facts":["fact1","fact2","fact3"]}`,
maxTurns: 2,
}
const analyst: AgentConfig = {
name: 'analyst',
model: 'claude-sonnet-4-6',
systemPrompt: `You are a data analyst. Read the fetched data from shared memory
and produce a brief analysis (3-4 sentences) highlighting trends or insights.`,
maxTurns: 2,
}
// ---------------------------------------------------------------------------
// Progress handler — watch for task_retry events
// ---------------------------------------------------------------------------
function handleProgress(event: OrchestratorEvent): void {
const ts = new Date().toISOString().slice(11, 23)
switch (event.type) {
case 'task_start':
console.log(`[${ts}] TASK START "${event.task}" (agent: ${event.agent})`)
break
case 'task_complete':
console.log(`[${ts}] TASK DONE "${event.task}"`)
break
case 'task_retry': {
const d = event.data as { attempt: number; maxAttempts: number; error: string; nextDelayMs: number }
console.log(`[${ts}] TASK RETRY "${event.task}" — attempt ${d.attempt}/${d.maxAttempts}, next in ${d.nextDelayMs}ms`)
console.log(` error: ${d.error.slice(0, 120)}`)
break
}
case 'error':
console.log(`[${ts}] ERROR "${event.task}" agent=${event.agent}`)
break
}
}
// ---------------------------------------------------------------------------
// Orchestrator + team
// ---------------------------------------------------------------------------
const orchestrator = new OpenMultiAgent({
defaultModel: 'claude-sonnet-4-6',
onProgress: handleProgress,
})
const team = orchestrator.createTeam('retry-demo', {
name: 'retry-demo',
agents: [fetcher, analyst],
sharedMemory: true,
})
// ---------------------------------------------------------------------------
// Tasks — fetcher has retry config, analyst depends on it
// ---------------------------------------------------------------------------
const tasks = [
{
title: 'Fetch data',
description: 'Fetch key facts about the adoption of TypeScript in open-source projects as of 2024. Output a JSON object with a "topic" and "facts" array.',
assignee: 'fetcher',
// Retry config: up to 2 retries, 500ms base delay, 2x backoff (500ms, 1000ms)
maxRetries: 2,
retryDelayMs: 500,
retryBackoff: 2,
},
{
title: 'Analyze data',
description: 'Read the fetched data from shared memory and produce a 3-4 sentence analysis of TypeScript adoption trends.',
assignee: 'analyst',
dependsOn: ['Fetch data'],
// No retry — if analysis fails, just report the error
},
]
// ---------------------------------------------------------------------------
// Run
// ---------------------------------------------------------------------------
console.log('Task Retry Example')
console.log('='.repeat(60))
console.log('Pipeline: fetch (with retry) → analyze')
console.log(`Retry config: maxRetries=2, delay=500ms, backoff=2x`)
console.log('='.repeat(60))
console.log()
const result = await orchestrator.runTasks(team, tasks)
// ---------------------------------------------------------------------------
// Summary
// ---------------------------------------------------------------------------
console.log('\n' + '='.repeat(60))
console.log(`Overall success: ${result.success}`)
console.log(`Tokens — input: ${result.totalTokenUsage.input_tokens}, output: ${result.totalTokenUsage.output_tokens}`)
for (const [name, r] of result.agentResults) {
const icon = r.success ? 'OK ' : 'FAIL'
console.log(` [${icon}] ${name}`)
console.log(` ${r.output.slice(0, 200)}`)
}