(Advanced) Custom Consensus

By default, Somnia Agents uses Majority consensus — the request finalizes when a threshold of validators return byte-identical results. This works well for deterministic agents (math, API lookups with exact values, etc.) but breaks down when each validator is expected to return a different value.

Threshold consensus solves this. Instead of requiring matching results, it finalizes as soon as the threshold number of validators respond successfully — regardless of whether their results agree. Your callback receives all individual results, and you aggregate them however you like.

Consensus Types

Type

Finalization Condition

responses[] in Callback

Majority (0)

threshold validators return the same result

Responds with all responses; at least threshold will match on the same .result value

Threshold (1)

threshold validators return any successful result

All responses (check .status to filter successful ones)

Using Threshold Consensus

Call createAdvancedRequest instead of createRequest:

platform.createAdvancedRequest{value: deposit}(
    agentId,
    address(this),
    this.handleResponse.selector,
    payload,
    5,                       // subcommitteeSize
    3,                       // threshold — finalize after 3 of 5 respond
    ConsensusType.Threshold, // don't require matching results
    1 minutes                // timeout
);

The threshold parameter controls how many successful responses are needed before finalization. A typical choice is 3 of 5 — this tolerates up to 2 validator failures while still collecting enough data points for meaningful aggregation.

Example: Price Oracle (Median)

Each validator fetches a price independently. Results may differ slightly. Your contract takes the median to filter outliers.

Taking the median of independent price observations naturally filters outliers and manipulation — with 3 of 5 results, the median remains accurate even if one validator returns a garbage value.

Example: Random Oracle (XOR)

Each validator returns a random uint256. Your contract XORs all values together to produce a combined random number. This is secure as long as at least one responding validator provides a truly random value — even if the others are compromised or predictable, the XOR output remains unpredictable.

When to Use Which

Use Case
Consensus
Why

Deterministic computation (math, hashing)

Majority

All validators should return the exact same result

API lookups with exact values

Majority

Same endpoint, same response

Deterministic LLM inference

Majority

Fixed seed + temperature 0 produces identical outputs across validators

Price feeds / continuous values

Threshold

Slight differences expected; median filters outliers

Random number generation

Threshold

Values must differ; XOR combines them securely

Weather data / sensor readings

Threshold

Approximate values; average or median for accuracy

Non-deterministic LLM inference

Threshold

Natural variance in outputs; application decides how to reconcile

Threshold Tips

  • A threshold of 3 out of 5 is a good default — it tolerates up to 2 failures while still collecting enough data for aggregation.

  • Higher thresholds (e.g., 4 of 5) give more data points but are more likely to time out if a validator fails.

  • Avoid setting threshold = subcommitteeSize — a single validator failure would prevent finalization entirely.

  • The responses[] array in your callback contains all validator responses — check each responses[i].status to filter for successful ones.

  • getAdvancedRequestDeposit(subSize) returns the operations-reserve floor (minPerAgentDeposit × subSize). That's the minimum msg.value the contract will accept, and it only covers gas/callback/upkeep — the agent pot is msg.value − floor. Deposit more than the floor to actually pay runners for execution work. See Gas Fees for the full fund-flow model.

  • Unused funds are rebated to the requester after finalisation.

Next Steps

Last updated