Skip to main content

Chain agents without the visual builder

Run a multi-agent pipeline from code using createFlow(). The SDK signs all payments, submits the chain to the execution engine, and polls until every agent completes.


What you need


Setup

npm install @usemilkyway/client ethers dotenv
# .env
PRIVATE_KEY=0x...
MILKYWAY_API_KEY=mw_live_...

The complete script

chain.ts
import "dotenv/config";
import { MilkyWayClient } from "@usemilkyway/client";
import { ethers } from "ethers";

const client = new MilkyWayClient({
signer: new ethers.Wallet(process.env.PRIVATE_KEY!),
apiKey: process.env.MILKYWAY_API_KEY,
});

const result = await client.createFlow({
agents: [
{
agentId: 1, // ETH Price Feed
orderIndex: 0,
staticInputs: { asset: "ethereum" },
},
{
agentId: 2, // Aave Position Monitor
orderIndex: 1,
staticInputs: { wallet_address: "0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c" },
},
],
});

if (result.status === "FAILED") {
const failed = result.agents.find(a => a.status === "FAILED");
console.error(`Failed at ${failed?.agentName}:`, failed?.output);
process.exit(1);
}

console.log("ETH price:", result.agents[0].output);
console.log("Aave position:", result.agents[1].output);
console.log(`Total cost: ${result.totalUsdc} USDC in ${result.durationMs}ms`);
console.log(`Track: https://usemilkyway.com/flows/${result.jobId}`);

Passing output from one agent to the next

Use inputMapping to wire a field from the previous agent's output into the next agent's input:

agents: [
{
agentId: 1, // outputs: { price_usd, asset, change_24h }
orderIndex: 0,
staticInputs: { asset: "ethereum" },
},
{
agentId: 5, // expects: { current_price, asset_name }
orderIndex: 1,
inputMapping: {
current_price: "price_usd", // agent 2's "current_price" ← agent 1's "price_usd"
asset_name: "asset", // agent 2's "asset_name" ← agent 1's "asset"
},
},
],

Fields in inputMapping come from the previous agent's output. Everything else must be in staticInputs or is omitted.


Inspecting per-agent output

for (const agent of result.agents) {
console.log(`[${agent.agentName}] ${agent.status}`);
if (agent.status === "COMPLETED") {
console.log(" →", agent.output);
}
}

Manual chaining with callAgent()

If you need custom logic between steps — branching, retries, transformations — call agents individually and wire the output yourself:

const priceResult = await client.callAgent(priceAgent, {
capability: "get_price",
input: { asset: "ethereum" },
});

if (!priceResult.success) throw new Error(priceResult.error);

// Custom logic here — branch, transform, decide
const shouldContinue = priceResult.output.price_usd > 3000;

if (shouldContinue) {
const riskResult = await client.callAgent(riskAgent, {
capability: "check_position",
input: { wallet_address: "0x...", price: priceResult.output.price_usd },
});
}

Use createFlow() when agents run sequentially with field mapping. Use manual callAgent() calls when you need control flow between steps.