bitpro가 원문에서 글자만 모은 내용이에요. 표·그림·수식은 빠지거나 깨질 수 있어요. 전체 54쪽 중 50쪽
agents/base-agents/llm-parse-website) — Extract structured data from websites
# Quickstart
This section covers how to invoke Somnia Agents—calling their methods and receiving results.
## How Agent Invocation Works
Agent invocations are **asynchronous**. When you invoke an agent:
1. Your request is sent to the Somnia network
2. Multiple validator nodes execute the agent independently
3. Validators reach consensus on the result
4. The result is returned (and optionally delivered to a callback)
{% @mermaid/diagram content="sequenceDiagram
participant You
participant Platform as Platform Contract
participant Network as Validator Network
```
You->>Platform: Invoke agent + fee
Platform->>Network: Distribute to validators
Network->>Network: Execute & reach consensus
Network->>Platform: Return result
Platform->>You: Deliver result (callback or response)" %}
```
This decentralized execution ensures that results are trustworthy and auditable.
## Network & Tokens
Somnia Agents are live on both **Somnia Mainnet** and **Somnia Testnet**. Pick the network that matches your deployment target:
| Property | Mainnet | Testnet |
| ----------------------- | -------------------------------------------- | -------------------------------------------- |
| Network Name | Somnia Mainnet | Somnia Testnet |
| Chain ID | `5031` | `50312` |
| RPC URL | `https://api.infra.mainnet.somnia.network` | `https://api.infra.testnet.somnia.network` |
| Currency | SOMI | STT |
| `SomniaAgents` Contract | `0x5E5205CF39E766118C01636bED000A54D93163E6` | `0x037Bb9C718F3f7fe5eCBDB0b600D607b52706776` |
Get testnet STT from the [Somnia Faucet](https://testnet.somnia.network). For mainnet, acquire SOMI through the usual channels.
## Explore Agents
The easiest way to get started is the Agent Explorer web app:
| Network | URL |
| ------- | ---------------------------------------------------------------------------------- |
| Testnet | [**https://agents.testnet.somnia.network**](https://agents.testnet.somnia.network) |
| Mainnet | [**https://agents.somnia.network**](https://agents.somnia.network) |
Here you can:
* Browse all available agents
* View agent methods and their parameters
* Invoke agents directly from the browser
* View execution receipts
* Generate code snippets for Solidity and JavaScript
## Invocation Methods
There are two ways to invoke agents:
| Method | Use Case | Guide |
| ------------ | ----------------------------------------------- | --------------------------------------------------------------- |
| **Web App** | Exploration, testing, one-off calls | This page |
| **Solidity** | Smart contract integration, on-chain automation | [Invoking from Solidity](/agents/invoking-agents/from-solidity) |
All agent invocations go through the Solidity platform contract — including calls made from the web app.
## Next Steps
* [Invoking from Solidity](/agents/invoking-agents/from-solidity) — Integrate agents into smart contracts
* [Receipts](broken://pages/mMhGrKhRzYkIc9MyZqDZ) — Understand execution receipts
* [Gas Fees](/agents/invoking-agents/gas-fees) — Learn about invocation costs
# Invoking from Solidity
This guide shows how to invoke Somnia Agents from smart contracts. Your contracts can call agents and receive responses via callbacks.
## Generate Code from the Web App
The easiest way to get started is to use the code generator:
1. Visit <https://agents.somnia.network>
2. Select an agent from the list
3. Click on a method to expand it
4. Select the "Solidity" tab to see generated code for that method
5. Copy the generated code into your project
The generator creates a complete contract with:
* Platform interface definitions
* Agent method encoding
* Callback handling
* Proper error handling
> **Tip:** The "TypeScript" tab generates code for invoking agents from JavaScript/TypeScript — it sends transactions to the platform contract and listens for response events.
## How It Works
{% @mermaid/diagram content="sequenceDiagram
participant Contract as Your Contract
participant Platform as SomniaAgents Contract
participant Committee
participant Validators as Validator Network
```
Contract->>Platform: createRequest{value: deposit}(agentId, callback, selector, payload)
Platform-->>Validators: RequestCreated(..., perAgentBudget, subcommittee)
Validators->>Platform: submitResponse (result, receipt, success, executionCost)
Platform-->>Validators: gas refund (operations reserve)
Platform->>Platform: Reach consensus
Platform->>Contract: handleResponse(requestId, responses[], status, details)
Platform->>Committee: deposit(subcommittee, [median × subSize])
Platform->>Contract: Send rebate (unused budget)
Platform-->>Contract: RequestFinalized event" %}
```
1. Your contract calls `createRequest()` with the agent ID, encoded payload, and a deposit.
2. The platform splits the deposit into an **operations reserve** (`minPerAgentDeposit × subSize`, funds gas refunds / callback / upkeep) and an **agent reward pot** (the rest). `perAgentBudget = rewardPot / subSize` is emitted in `RequestCreated` so runners know their cap.
3. Elected validators execute the agent and submit responses; each submission is gas-refunded from the operations reserve.
4. Once consensus is reached, the platform calls your callback, then pays every elected subcommittee member the **median** of the reported `executionCost` values via the committee.
5. Any unused funds are rebated to the requester.
See [Gas Fees](/agents/invoking-agents/gas-fees) for a full fund-flow diagram and details on sizing `msg.value`.
## Platform Interface
```solidity
enum ConsensusType { Majority, Threshold }
enum ResponseStatus {
None, // 0 - Default zero value (uninitialized storage)
Pending, // 1 - Awaiting responses
Success, // 2 - Consensus reached normally
Failed, // 3 - Validators reported failure
TimedOut // 4 - Request timed out
}
struct Response {
address validator;
bytes result;
ResponseStatus status;
uint256 receipt;
uint256 timestamp;
uint256 executionCost;
}
struct Request {
uint256 id;
address requester;
address callbackAddress;
bytes4 callbackSelector;
address[] subcommittee;
Response[] responses;
uint256 responseCount;
uint256 failureCount;
uint256 threshold;
uint256 createdAt;
uint256 deadline;
ResponseStatus status;
ConsensusType consensusType;
uint256 remainingBudget; // escrow remaining at any point in the lifecycle
uint256 perAgentBudget; // max each elected member can claim (set at creation)
}
interface IAgentRequester {
// Events
event RequestCreated(uint256 indexed requestId, uint256 indexed agentId, uint256 perAgentBudget, bytes payload, address[] subcommittee);
event RequestFinalized(uint256 indexed requestId, ResponseStatus status);
event SubcommitteePaid(uint256 indexed requestId, uint256 totalPaid, uint256 perMember);
event CommitteeDepositFailed(uint256 indexed requestId, uint256 attemptedAmount);
// Request Creation (payable - sends budget upfront)
function createRequest(
uint256 agentId,
address callbackAddress,
bytes4 callbackSelector,
bytes calldata payload
) external payable returns (uint256 requestId);
function createAdvancedRequest(
uint256 agentId,
address callbackAddress,
bytes4 callbackSelector,
bytes calldata payload,
uint256 subcommitteeSize,
uint256 threshold,
ConsensusType consensusType,
uint256 timeout
) external payable returns (uint256 requestId);
// Query Functions
function getRequest(uint256 requestId) external view returns (Request memory);
function hasRequest(uint256 requestId) external view returns (bool);
// Deposit helpers — query the exact msg.value required
function getRequestDeposit() external view returns (uint256);
function getAdvancedRequestDeposit(uint256 subcommitteeSize) external view returns (uint256);
}
interface IAgentRequesterHandler {
function handleResponse(
uint256 requestId,
Response[] memory responses,
ResponseStatus status,
Request memory details
) external;
}
```
**`SomniaAgents` / `AgentRequester` Addresses:**
| Network | Address |
| -------------------------- | -------------------------------------------- |
| Mainnet (chain ID `5031`) | `0x5E5205CF39E766118C01636bED000A54D93163E6` |
| Testnet (chain ID `50312`) | `0x037Bb9C718F3f7fe5eCBDB0b600D607b52706776` |
The examples below use the testnet address; swap in the mainnet address for production.
## Basic Example
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
enum ConsensusType { Majority, Threshold }
enum ResponseStatus {
None, // 0 - Default zero value (uninitialized storage)
Pending, // 1 - Awaiting responses
Success, // 2 - Consensus reached normally
Failed, // 3 - Validators reported failure
TimedOut // 4 - Request timed out
}
struct Response {
address validator;
bytes result;
ResponseStatus status;
uint256 receipt;
uint256 timestamp;
uint256 executionCost;
}
struct Request {
uint256 id;
address requester;
address callbackAddress;
bytes4 callbackSelector;
address[] subcommittee;
Response[] responses;
uint256 responseCount;
uint256 failureCount;
uint256 threshold;
uint256 createdAt;
uint256 deadline;
ResponseStatus status;
ConsensusType consensusType;
uint256 remainingBudget; // escrow remaining at any point in the lifecycle
uint256 perAgentBudget; // max each elected member can claim (set at creation)
}
interface IAgentRequester {
function createRequest(
uint256 agentId,
address callbackAddress,
bytes4 callbackSelector,
bytes calldata payload
) external payable returns (uint256 requestId);
function getRequestDeposit() external view returns (uint256);
}
interface IJsonApiAgent {
function fetchUint(string calldata url, string calldata selector, uint8 decimals)
external returns (uint256);
}
contract PriceOracle {
IAgentRequester public platform =
IAgentRequester(0x037Bb9C718F3f7fe5eCBDB0b600D607b52706776);
uint256 public constant JSON_API_AGENT_ID = 12345678901234567890; // Replace with actual agent ID from the web app
uint256 public constant SUBCOMMITTEE_SIZE = 3; // matches the platform default
uint256 public constant JSON_FETCH_COST_PER_AGENT = 0.03 ether; // see Gas Fees → Current Per-Agent Prices
uint256 public latestPrice;
mapping(uint256 => bool) public pendingRequests;
event PriceRequested(uint256 indexed requestId);
event PriceReceived(uint256 indexed requestId, uint256 price);
function requestBitcoinPrice() external payable returns (uint256 requestId) {
// Encode the agent function call
bytes memory payload = abi.encodeWithSelector(
IJsonApiAgent.fetchUint.selector,
"https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd",
"bitcoin.usd",
uint8(8)
);
// Safe deposit: contract floor + per-agent execution reward.
// Floor only would satisfy the contract but runners would skip the
// request because perAgentBudget < scheduledExecutionCost.
uint256 reserve = platform.getRequestDeposit(); // = minPerAgentDeposit × subSize
uint256 reward = JSON_FETCH_COST_PER_AGENT * SUBCOMMITTEE_SIZE;
uint256 deposit = reserve + reward;
requestId = platform.createRequest{value: deposit}(
JSON_API_AGENT_ID,
address(this),
this.handleResponse.selector,
payload
);
pendingRequests[requestId] = true;
emit PriceRequested(requestId);
}
// Callback function - called by the platform when consensus is reached
function handleResponse(
uint256 requestId,
Response[] memory responses,
ResponseStatus status,
Request memory details
) external {
require(msg.sender == address(platform), "Only platform can call");
require(pendingRequests[requestId], "Unknown request");
delete pendingRequests[requestId];
if (status == ResponseStatus.Success && responses.length > 0) {
latestPrice = abi.decode(responses[0].result, (uint256));
emit PriceReceived(requestId, latestPrice);
}
}
// Allow receiving rebates
receive() external payable {}
}
```
## Callback Function Signature
Your callback function must match this signature:
```solidity
function handleResponse(
uint256 requestId,
Response[] memory responses,
ResponseStatus status,
Request memory details
) external;
```
* `requestId`: The ID returned from `createRequest()`
* `responses`: Array of `Response` structs from validators (each contains `.result` bytes, `.status`, `.validator`, etc.)
* `status`: The overall request status — one of `Success` (2), `Failed` (3), or `TimedOut` (4)
* `details`: The full `Request` struct with metadata (subcommittee, threshold, deadline, etc.)
You can name the function anything, but the parameter types must match. The selector you pass to `createRequest` must match your function.
### Response Status
| Status | Value | Meaning |
| ---------- | ----- | ------------------------------------------------------- |
| `None` | 0 | Default zero value (uninitialized storage) |
| `Pending` | 1 | Awaiting responses |
| `Success` | 2 | Validators reached consensus |
| `Failed` | 3 | Validators reported failure (success became impossible) |
| `TimedOut` | 4 | Request timed out before consensus was reached |
## Decoding Responses
The `responses` array contains `Response` structs from validators. Each response has a `.result` field with ABI-encoded bytes and a `.status` field. The callback receives **all** responses submitted up to finalization. For `Majority` consensus, at least `threshold` responses will have identical `.result` bytes (the consensus value). For `Threshold` consensus, results may differ.
```solidity
// Decode from the first successful response
if (status == ResponseStatus.Success && responses.length > 0) {
// Single uint256
uint256 value = abi.decode(responses[0].result, (uint256));
// Single string
string memory text = abi.decode(responses[0].result, (string));
// Multiple values
(uint256 value, string memory message) = abi.decode(responses[0].result, (uint256, string));
}
// Iterate all responses (useful for Threshold consensus)
for (uint256 i = 0; i < responses.length; i++) {
if (responses[i].status == ResponseStatus.Success) {
uint256 value = abi.decode(responses[i].result, (uint256));
// Process each validator's result...
}
}
```
## Multiple Callbacks
Use different callbacks for different response types:
```solidity
contract MultiAgentConsumer {
IAgentRequester public platform =
IAgentRequester(0x037Bb9C718F3f7fe5eCBDB0b600D607b52706776);
// Request with uint256 response
function requestPrice() external payable {
bytes memory payload = abi.encodeWithSelector(...);
platform.createRequest{value: msg.value}(
PRICE_AGENT_ID,
address(this),
this.handlePriceResponse.selector,
payload
);
}
// Request with string response
function requestText() external payable {
bytes memory payload = abi.encodeWithSelector(...);
platform.createRequest{value: msg.value}(
TEXT_AGENT_ID,
address(this),
this.handleTextResponse.selector,
payload
);
}
function handlePriceResponse(
uint256 requestId,
Response[] memory responses,
ResponseStatus status,
Request memory details
) external {
require(msg.sender == address(platform), "Only platform");
if (status == ResponseStatus.Success && responses.length > 0) {
uint256 price = abi.decode(responses[0].result, (uint256));
// Process price...
}
}
function handleTextResponse(
uint256 requestId,
Response[] memory responses,
ResponseStatus status,
Request memory details
) external {
require(msg.sender == address(platform), "Only platform");
if (status == ResponseStatus.Success && responses.length > 0) {
string memory text = abi.decode(responses[0].result, (string));
// Process text...
}
}
receive() external payable {}
}
```
## Error Handling
Handle all response statuses gracefully:
```solidity
function handleResponse(
uint256 requestId,
Response[] memory responses,
ResponseStatus status,
Request memory details
) external {
require(msg.sender == address(platform), "Only platform");
if (status == ResponseStatus.Failed) {
emit AgentFailed(requestId);
// Validators reported execution failure
return;
}
if (status == ResponseStatus.TimedOut) {
emit AgentTimedOut(requestId);
// Request timed out - maybe retry
return;
}
// Success
if (responses.length == 0) {
emit EmptyResponse(requestId);
return;
}
// Decode and process response...
}
```
## Security Considerations
1. **Always verify the caller**: Check that `msg.sender` is the platform contract
2. **Track pending requests**: Use a mapping to validate incoming callbacks
3. **Handle all statuses**: Check `status` — requests can succeed, fail, or time out
4. **Validate responses length**: Check `responses.length` before decoding
5. **Accept rebates**: Implement `receive()` so your contract can receive rebated funds
## Next Steps
* [Gas Fees](/agents/invoking-agents/gas-fees) — Understand costs
# Receipts
Every agent invocation produces an **execution receipt** — a per-validator log of what happened during execution. Receipts provide transparency and auditability for agent operations.
{% hint style="info" %}
**Note:** Receipts are currently stored on centralized infrastructure (a public Google Cloud Storage bucket). We plan to migrate to decentralized storage in the future to make receipts tamper-proof and permanently available.
{% endhint %}
## Understanding Receipts
### Consensus vs. Receipts
It's important to understand the distinction:
* **Result**: The final output of the agent is what validators reach **consensus** on. All nodes must agree on this value for it to be accepted.
* **Receipt**: The execution steps are **subjective** and may vary slightly between nodes. Receipts are for transparency and debugging, not consensus.
This means:
* You can trust the **result** completely — it's been verified by multiple validators.
* Each receipt shows **what one node did** to compute that result.
* Different nodes may have different receipts (timing, network paths) but still agree on the final result.
### One request → one receipt per subcommittee member
A single agent request is processed by every member of its subcommittee (default size **3**, configurable via `createAdvancedRequest`). Each member produces its own receipt, so a default request yields **3 receipts**. The receipt service exposes them as a manifest keyed by `(contractAddress, requestId)`.
## Viewing Receipts in the UI
### From the Web App
1. Visit the Agent Explorer for the network you used — [https://agents.somnia.network](https://agents.somnia.network/) (mainnet) or [https://agents.testnet.somnia.network](https://agents.testnet.somnia.network/) (testnet).
2. Invoke an agent.
3. After execution completes, click **View Receipt**.
4. Explore each step of the execution.
The UI displays receipts in a readable format, showing:
* Per-validator execution timelines
* External calls made (URLs, responses)
* Data transformations
* Timing information
### From Monitoring
Browse recent invocations or search by request ID at:
```
https://agents.somnia.network/monitoring
```
Useful when you don't have the receipt URL handy or want to scan recent activity.
### From Receipt URL
If you already know the request ID, navigate directly to:
```
https://agents.somnia.network/receipts/<requestId>
```
Replace `<requestId>` with the numeric request ID returned by `createRequest`.
## Fetching Receipts Programmatically
Fetching is a **two-step flow**:
1. Hit the receipts service with the platform `contractAddress` and `requestId` — you get back a manifest of public Google Cloud Storage URLs.
2. Fetch each URL directly to read the per-validator receipt JSON.
| Network | Receipts service base URL | Platform contract |
| ------- | --------------------------------------------- | -------------------------------------------- |
| Mainnet | `https://receipts.mainnet.agents.somnia.host` | `0x5E5205CF39E766118C01636bED000A54D93163E6` |
| Testnet | `https://receipts.testnet.agents.somnia.host` | `0x037Bb9C718F3f7fe5eCBDB0b600D607b52706776` |
```javascript
const baseUrl = 'https://receipts.프로젝트로 돌아가기