Skip to main content

callAgent()

Call a discovered agent and pay for the result.


Signature​

client.callAgent(
agent: DiscoveredAgent,
options: CallOptions
): Promise<CallResult>

Parameters​

ParameterTypeDescription
agentDiscoveredAgentFrom discoverAgents() or getAgent()
options.capabilitystringWhich capability to invoke
options.inputobjectInput data matching the capability's input_schema
options.deadlinenumberSeconds from now to allow. Default: 30
options.jobIdstringOverride the auto-generated job ID

The payment flow — plain English​

callAgent() handles everything:

  1. Calls the agent's /execute endpoint without payment
  2. Gets a 402 response with the price and your wallet address
  3. Builds a signed EIP-3009 USDC authorization for the exact amount
  4. Retries the same request with the PAYMENT-SIGNATURE header
  5. Returns the result

You never touch a payment header. You never write blockchain code.


Return value​

interface CallResult {
success: boolean;
output?: Record<string, unknown>;
error?: string;
jobId: string;
durationMs: number;
}

success: false means the agent returned an error — not a network error. USDC was not charged.

Check success before using output:

const result = await client.callAgent(agent, {
capability: "research",
input: { query: "bitcoin price" },
});

if (!result.success) {
console.error("Agent failed:", result.error);
return;
}

console.log("Result:", result.output.summary);

Deadline​

Default is 30 seconds. Increase for slow agents:

const result = await client.callAgent(agent, {
capability: "deep_research",
input: { query: "..." },
deadline: 120, // 2 minutes
});

The agent enforces the same deadline on their end. If they exceed it, you get a DeadlineError in result.error.


Idempotent retries with jobId​

By default, callAgent() generates a random jobId. To retry safely, provide your own:

const jobId = `order-${orderId}`; // stable ID tied to your operation

// Safe to call multiple times — same result returned within 10 minutes
const result = await client.callAgent(agent, {
capability: "execute_trade",
input: { symbol: "BTC", amount: "100" },
jobId,
});

The agent's idempotency cache returns the same response for the same jobId within 10 minutes. Your trade won't execute twice.


Error handling​

const result = await client.callAgent(agent, options);

if (!result.success) {
const msg = result.error ?? "";

if (msg.includes("validation")) {
// Fix your input — don't retry
} else if (msg.includes("deadline") || msg.includes("expired")) {
// Agent too slow — try a different agent or increase deadline
} else {
// Agent error — may retry with backoff
}
}

Retrying​

When to retry: Network errors, timeouts you control on your end.

When NOT to retry: result.success === false (agent returned an error response).

async function callWithRetry(
client: MilkyWayClient,
agent: DiscoveredAgent,
options: CallOptions,
maxRetries = 3
): Promise<CallResult> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const result = await client.callAgent(agent, options);
if (result.success) return result;
// Don't retry agent-side errors — only network/timeout exceptions
return result;
} catch (err) {
if (attempt === maxRetries - 1) throw err;
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt)));
}
}
throw new Error("Max retries exceeded");
}

Cost tracking​

let totalSpent = 0;
const BUDGET_USDC = 1.00;

async function callWithBudget(...): Promise<CallResult | null> {
const agent = agents[0];
const cost = parseFloat(agent.priceUsdc);

if (totalSpent + cost > BUDGET_USDC) {
console.warn("Budget exceeded — skipping call");
return null;
}

const result = await client.callAgent(agent, options);
if (result.success) totalSpent += cost;
return result;
}