Parallel
Run multiple agents concurrently and get typed results as a named record.
parallel() runs a named map of agents concurrently and returns all results as a typed record. Use it when agents are independent — reviewing content, analyzing from different angles, or gathering data from multiple sources.
import { parallel } from '@crux/ai'
import { agent } from '@crux/core/agent'
const result = await parallel({
agents: {
factCheck: factCheckerAgent,
style: styleReviewerAgent,
seo: seoAnalyzerAgent,
},
context: { content: articleDraft },
model: claude35,
})
result.results.factCheck.output // typed from factCheckerAgent's output schema
result.results.style.output // typed from styleReviewerAgent's output schema
result.results.seo.output // typed from seoAnalyzerAgent's output schema
result.durationMs // total wall-clock time (= slowest agent)How it works
- All agents start executing at the same time (
Promise.all) - Each agent receives the same
context - When all finish, results are returned as a
Record<name, AgentResult<typed>>— each result is typed from the agent's output schema - Each result is an
AgentResultwith.agentId,.output,.durationMs
Total time is the duration of the slowest agent, not the sum.
Using results
Results are returned as a named record, so you access each agent's output by name with full type safety:
const { results, durationMs } = await parallel({
agents: { factCheck: factCheckerAgent, style: styleReviewerAgent },
context: { content: draft },
model,
})
const approved = results.factCheck.output.score > 0.8
&& results.style.output.score > 0.7
const feedback = [
...results.factCheck.output.issues,
...results.style.output.suggestions,
]Error handling
By default, parallel() uses fail-fast semantics — if any agent throws, the entire composition fails immediately.
For best-effort execution, use onError: 'continue':
const result = await parallel({
agents: { a: agentA, b: agentB },
context: { content: draft },
model,
onError: 'continue',
})
// result.results contains successful agents' results
// result.settled contains discriminated results for all agents:
if (result.settled.a.status === 'success') {
// result.settled.a.value is AgentResult
}
if (result.settled.b.status === 'error') {
// result.settled.b.error is Error
}In continue mode, result.settled contains a discriminated union for each agent:
{ status: 'success', value: AgentResult }— agent succeeded{ status: 'error', error: Error }— agent failed
Fallback integration
Per-agent model fallbacks work naturally. Each agent's model can be wrapped with fallback():
import { fallback } from '@crux/core'
const reviewer = agent({
id: 'reviewer',
prompt: reviewPrompt,
model: fallback(claude35, gpt4), // try Claude first, fall back to GPT-4
})The composition's onError only triggers after all model fallbacks are exhausted.
Devtools
In the devtools timeline, parallel compositions appear as:
comp → parallel 3 agents
comp ← reviewer 1.2s
comp ← factCheck 0.9s
comp ← seo 1.8s
comp ← parallel 3/3 ok 1.8s