ctx.call()
Cross-agent communication with automatic workflow DAG building
The ctx.call() method enables cross-agent communication, allowing reasoners to invoke reasoners and skills on other agents while automatically building workflow DAGs.
Basic Usage
agent.reasoner('orchestrate', async (ctx) => {
// Call another agent's reasoner
const sentiment = await ctx.call('sentiment-agent.analyze', {
text: ctx.input.text
});
return { sentiment };
});Target Format
The target string follows the format: {agent-id}.{reasoner-or-skill-name}
// Call a reasoner
await ctx.call('analysis-agent.deep_analyze', { data });
// Call a skill
await ctx.call('formatter-agent.format_json', { data });
// Call on same agent
await ctx.call('my-agent.other_reasoner', { data });Parameters
Prop
Type
Automatic Context Propagation
When you call another agent, the execution context is automatically propagated:
executionId- Unique ID for the child executionparentExecutionId- Links to the calling executionworkflowId- Shared across the entire workflowrunId- Groups related executionssessionId- User session tracking
The Agentfield control plane uses this context to build workflow DAGs showing the complete execution flow across all agents.
Multi-Agent Orchestration
agent.reasoner('process_ticket', async (ctx) => {
const { ticketId, content } = ctx.input;
// Parallel calls to multiple agents
const [sentiment, category, priority] = await Promise.all([
ctx.call('sentiment-agent.analyze', { text: content }),
ctx.call('classifier-agent.categorize', { text: content }),
ctx.call('priority-agent.assess', { text: content })
]);
// Sequential call based on results
let handler;
if (priority.level === 'critical') {
handler = await ctx.call('escalation-agent.escalate', {
ticketId,
sentiment,
category,
priority
});
} else {
handler = await ctx.call('routing-agent.assign', {
ticketId,
category
});
}
return {
ticketId,
analysis: { sentiment, category, priority },
handler
};
});Agent-Level Call
You can also call from the agent instance directly:
// Outside of a reasoner context
const result = await agent.call('other-agent.function', {
data: 'input'
});Error Handling
agent.reasoner('safe_call', async (ctx) => {
try {
const result = await ctx.call('external-agent.process', ctx.input);
return { success: true, result };
} catch (error) {
// Log error and provide fallback
console.error('External agent failed:', error);
// Try fallback agent
const fallback = await ctx.call('fallback-agent.process', ctx.input);
return { success: true, result: fallback, usedFallback: true };
}
});Workflow DAG Example
When agents call each other, the control plane builds a DAG:
orchestrator.process_request
├── sentiment-agent.analyze
├── classifier-agent.categorize
│ └── enrichment-agent.add_context
└── routing-agent.assign
└── notification-agent.notifyThis DAG is visible in the Agentfield UI and can be exported for auditing.
Examples
Research Pipeline
agent.reasoner('research', async (ctx) => {
const { topic } = ctx.input;
// Step 1: Gather sources
const sources = await ctx.call('search-agent.find_sources', { topic });
// Step 2: Extract information from each source
const extractions = await Promise.all(
sources.map(source =>
ctx.call('extraction-agent.extract', { url: source.url })
)
);
// Step 3: Synthesize findings
const synthesis = await ctx.call('synthesis-agent.combine', {
topic,
extractions
});
// Step 4: Generate report
const report = await ctx.call('report-agent.generate', {
topic,
synthesis
});
return report;
});Conditional Routing
agent.reasoner('smart_router', async (ctx) => {
const { request } = ctx.input;
// Classify the request
const classification = await ctx.call('classifier-agent.classify', {
text: request.content
});
// Route based on classification
switch (classification.type) {
case 'technical':
return await ctx.call('tech-support-agent.handle', request);
case 'billing':
return await ctx.call('billing-agent.handle', request);
case 'sales':
return await ctx.call('sales-agent.handle', request);
default:
return await ctx.call('general-agent.handle', request);
}
});Fan-Out / Fan-In
agent.reasoner('batch_process', async (ctx) => {
const { items } = ctx.input;
// Fan-out: Process all items in parallel
const results = await Promise.all(
items.map((item, index) =>
ctx.call('processor-agent.process', { item, index })
)
);
// Fan-in: Aggregate results
const aggregated = await ctx.call('aggregator-agent.combine', {
results
});
return aggregated;
});Related
- ReasonerContext - Full context reference
- ctx.discover() - Find available agents
- Workflow DAGs - Understanding execution flows