One of the key benefits of using Agention is that pipelines are typed end to end. Every agent, and every custom node you write, implements the same interface:
interface GraphNode<TInput, TOutput> {
name?: string;
nodeType?: GraphNodeType;
execute(input: TInput): Promise<TOutput>;
}
Agents already implement GraphNode, so they drop straight into a pipeline with nothing extra to configure.
Chaining Agents
AgentGraph.sequential() chains nodes together, passing each one's output to the next:
import { AgentGraph } from "@agentionai/agents";
import { ClaudeAgent } from "@agentionai/agents/claude";
const researcher = new ClaudeAgent({
id: "researcher",
name: "Researcher",
description: "Research the topic and list key facts.",
apiKey: process.env.ANTHROPIC_API_KEY,
model: "claude-sonnet-4-5",
});
const writer = new ClaudeAgent({
id: "writer",
name: "Writer",
description: "Write a blog post from the research provided.",
apiKey: process.env.ANTHROPIC_API_KEY,
model: "claude-sonnet-4-5",
});
const chain = AgentGraph.sequential(researcher, writer);
const result = await chain.execute("Artificial intelligence in healthcare");
Custom Nodes Keep Their Types
Because the interface is generic, a plain function can join a pipeline right next to an LLM agent, and TypeScript still checks that the shapes line up:
import { GraphNode } from "@agentionai/agents";
const dataFetcher: GraphNode<string, object> = {
name: "data-fetcher",
nodeType: "custom",
async execute(url: string): Promise<object> {
const response = await fetch(url);
return response.json();
},
};
const pipeline = AgentGraph.pipeline(dataFetcher, analyzer);
If dataFetcher's output type doesn't match what analyzer expects as input, that's a compile error, not a runtime surprise.
Composing Without Losing Types
Executors are nodes themselves, so you can nest them: run a parallel research phase, then feed all of it into a sequential synthesis phase.
const researchPhase = AgentGraph.parallel({}, webSearcher, documentAnalyzer, expertConsult);
const synthesisPhase = AgentGraph.sequential(summarizer, factChecker);
const pipeline = AgentGraph.pipeline(researchPhase, synthesisPhase);
Observability Comes Free
Because every stage is a typed node, wrapping the whole pipeline in a metrics collector is one line:
import { createMetricsCollector } from "@agentionai/agents";
const metrics = createMetricsCollector();
const pipeline = AgentGraph.pipeline(researcher, writer).withMetrics(metrics);
await pipeline.execute("Input");
console.log(metrics.getAggregateMetrics());
Conclusion
Type safety here isn't a layer bolted on top. It's the same GraphNode interface all the way down, from a single agent to a tree of parallel and sequential stages. Your IDE can autocomplete and your compiler can catch mismatches, even several stages deep.