Skip to main content

Submit an agent run (Fork V6) end-to-end

Full flow: build AGENT_REQUEST, broadcast, poll lifecycle, render steps + final answer.

Direct (server-side)

import {
OmbraClient, Wallet,
buildAgentRequestTx,
computeAgentRunId, computeConversationId,
MICRO_OMBRA,
} from "@ombrachain/sdk";

const client = new OmbraClient({ endpoint: "https://api.ombra-net.com" });
const wallet = Wallet.fromMnemonic("...");

async function runAgent(prompt: string, tools: string[]) {
const acct = await client.chain.getAccount(wallet.address);
const runId = computeAgentRunId(wallet.address, acct.nonce, prompt);
const convId = computeConversationId(wallet.address);

// 1. Submit AGENT_REQUEST
const tx = buildAgentRequestTx(wallet.address, {
agentRunId: runId,
conversationId: convId,
prompt,
toolsWhitelist: tools,
maxFee: BigInt(MICRO_OMBRA), // 1 OMBRA escrow
maxSteps: 50,
}, acct.nonce, wallet.privateKey);

await client.chain.submitTx(tx);
console.log("submitted:", runId);

// 2. Poll status + steps
const start = Date.now();
let lastStepIdx = -1;
while (Date.now() - start < 180_000) {
await new Promise((r) => setTimeout(r, 2_000));
const res = await fetch(`https://api.ombra-net.com/api/agent/v6/run/${runId}`);
if (!res.ok) continue;
const run = await res.json();

// Pull new steps
if ((run.stepCount ?? 0) > lastStepIdx + 1) {
const stepsRes = await fetch(`https://api.ombra-net.com/api/agent/v6/run/${runId}/steps`);
const { steps } = await stepsRes.json();
for (const s of steps) {
if (s.stepIndex > lastStepIdx) {
console.log(`step ${s.stepIndex}: ${s.outputTokens} tokens`);
for (const tc of s.toolCalls ?? []) {
console.log(`${tc.name} (${tc.durationMs}ms) ${tc.ok ? "✓" : "✗"}`);
}
lastStepIdx = s.stepIndex;
}
}
}

if (["completed", "failed", "timeout", "insufficient_funds", "cancelled"].includes(run.status)) {
console.log("=== finished ===");
console.log("status:", run.status);
console.log("tokens:", run.totalTokensOut);
console.log("miner reward:", run.minerReward, "micro");
console.log("refund:", run.userRefund, "micro");
console.log("answer:", run.finalAnswerInline);
return run;
}
}
throw new Error("agent timeout (180s)");
}

await runAgent(
"What's my OMBRA balance and how many NFTs do I own?",
["chain_get_balance", "chain_list_nfts"],
);

Browser via window.ombra

For dApps, the Ombra Wallet extension signs without exposing keys:

async function runAgentViaExtension(prompt: string, tools: string[]) {
const result = await window.ombra.request({
method: "ombra_submitAgentRequest",
params: {
prompt,
toolsWhitelist: tools,
maxFee: "1000000", // micro-OMBRA as string
maxSteps: 50,
},
}) as { agentRunId: string; conversationId: string; txHash: string };

console.log("approved + broadcast:", result.txHash);
// poll as above with result.agentRunId
}

The extension shows a popup with:

  • Prompt preview
  • Escrow amount (in OMBRA)
  • Tools whitelist
  • Max steps

User must approve before the tx is signed.

Rendering steps in a UI

Step data includes:

  • stepIndex — order
  • outputTokens — for cost display
  • toolCalls — array of { name, durationMs, ok, argsHash, resultHash }
  • outputHash — sha256 of step text (verify against fetched content)

Example React snippet:

{run.steps.map((s) => (
<div key={s.stepIndex} className="step">
<div className="step-header">
Step {s.stepIndex} · {s.outputTokens} tokens
</div>
{s.toolCalls?.map((tc, i) => (
<div key={i} className="tool-call">
🔧 {tc.name} {tc.ok ? "✓" : "✗"} ({tc.durationMs}ms)
</div>
))}
</div>
))}

When agents fail

If status === "failed" — the miner aborted (LLM error, tool execution error). Look at last step for clues.

If status === "insufficient_funds" — the run consumed all maxFee in network fees + token rewards before producing a final answer. Increase maxFee and resubmit.

If status === "timeout" — no miner picked up the run within the network's claim window (typically 5 min). Causes:

  • No miners online with all whitelisted tools
  • maxFee too low (miners ignore unprofitable runs)
  • All capable miners are busy (max concurrent runs reached)

Mitigation: increase maxFee, reduce toolsWhitelist to commonly-available tools, or retry later.

Cost estimation

Before submitting:

estimatedMinerCost = expectedTokensOut × 1 // micro-OMBRA
estimatedNetworkFee = expectedSteps × 100 // micro-OMBRA
totalCost ≈ estimatedMinerCost + estimatedNetworkFee

Always escrow maxFee >= totalCost × 2 for safety. Excess is refunded.

For a typical chat agent with 1-3 tool calls and ~2000 output tokens:

  • minerCost = 2000
  • networkFee = 3 × 100 = 300
  • Recommended maxFee = 10_000 (0.01 OMBRA)