Files
open-multi-agent/examples/patterns/task-retry.ts
T
JackChen ffec13e915 refactor: reorganize examples by category (#125)
Examples grew to 19 flat files mixing basics, provider demos, orchestration
patterns, and integrations, with two files colliding on the number 16.
Reorganized into category folders so the structure scales as new providers
and patterns get added.

Layout:
  examples/basics/         core execution modes (4 files)
  examples/providers/      one example per supported model provider (8 files)
  examples/patterns/       reusable orchestration patterns (6 files)
  examples/integrations/   MCP, observability, AI SDK (3 entries)
  examples/production/     placeholder for end-to-end use cases

Notable changes:
- Dropped numeric prefixes; folder + filename now signal category and intent.
- Rewrote former smoke-test scripts (copilot, gemini) into proper three-agent
  team examples matching the deepseek/grok/minimax/groq template. Adapter
  unit tests in tests/ already cover correctness, so this only improves
  documentation quality.
- Added examples/README.md as the categorized index plus maintenance rules
  for new submissions.
- Added examples/production/README.md with acceptance criteria for the new
  production category.
- Updated all internal npx tsx paths and import paths (../src/ to ../../src/).
- Updated README.md and README_zh.md links.
- Fixed stale cd paths inside examples/integrations/with-vercel-ai-sdk/README.md.
2026-04-19 17:01:58 +08:00

133 lines
4.7 KiB
TypeScript

/**
* 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/patterns/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)}`)
}