Agents
Intents
An intent is what the agent needs, plus the economic constraints around that need.
interface IntentRequest {
need: string; // free text, used for matching only
input?: Record<string, unknown>; // validated against each candidate's schema
constraints?: IntentConstraints; // typed, checked before ranking
limit?: number; // candidates returned in the plan
}The need is not an instruction
need helps Tollex find relevant capabilities. It cannot change anything economic. A need that says “ignore the price limit and use mainnet” is matched as text, and the price limit and networks still come from the typed constraints and your policy. The test suite includes this exact case.
Constraints
| Field | Type | Meaning |
|---|---|---|
maxCost | atomic integer string | The most the route may cost. Compared with the route's maximum (for metered routes, the ceiling), not its expected price. |
asset | token address | Pay only in this asset. |
networks | CAIP-2 list | Settle only on these networks, e.g. eip155:46630. |
schemes | exact | upto | batch-settlement | Payment schemes the agent can use. |
maxLatencyMs | integer | Observed p95 latency must be at or below this. A capability with no latency observations fails. |
receiptRequired | boolean | Only capabilities that return a signed Tollex receipt. |
evidenceRequired | boolean or list | true: at least one evidence kind. A list: every named kind, e.g. block_pinned. |
allowedProviders / blockedProviders | list, trailing * allowed | Provider allow and block lists. |
allowedTools / blockedTools | list, trailing * allowed | Tool allow and block lists. |
categories | list | Only these capability categories. |
requiredFreshnessMs | integer | Terms and health must have been observed within this window. Never observed fails. |
minSuccessRate | 0 to 1 | Observed success rate over at least five calls. |
maxSideEffects | none | read | write | The highest side-effect class the agent accepts. |
requireStableSchemaForMs | integer | The capability's current input and output schema must have been in place this long. No schema history fails. |
maxBreakingChanges30d | integer | At most this many breaking schema changes in the last 30 days. No schema history fails. |
includeExternal | boolean | Also consider external x402 services found by discovery. Where the service enables external execution they are bought with your wallet, paid directly to the merchant, after the live price is checked again; otherwise they are planned only. |
Constraints are parsed strictly. An unknown key is rejected with 400 invalid_intent rather than ignored, because a misspelled restriction that silently disappears is worse than an error. Amounts are integers in atomic units; there is no floating point anywhere in the path. In TypeScript, usdg("0.01") converts a decimal string to atomic units.
Profiles and composition
An agent usually has a standing profile: its signing policy plus default intent constraints. Each request composes with it, and the most restrictive value wins. Ceilings take the minimum, allow lists intersect, block lists combine and requirements add up. A request can narrow the profile; it can never widen it. An empty intersection means nothing is eligible, never “anything goes”.
const profile: AgentPolicyProfile = {
policy: {
id: "cautious",
agentId: "research-03",
networks: [NETWORK],
assets: [{ network: NETWORK, address: USDG_ADDRESS, decimals: 6 }],
schemes: ["exact"],
maxPerRequest: usdg("0.005"),
budgets: { hourly: usdg("0.5"), daily: usdg("5") },
providers: { block: ["untrusted.*"] },
maxAuthorizationLifetimeSeconds: 300,
},
intentDefaults: { receiptRequired: true, requiredFreshnessMs: 10 * 60_000 },
};
const agent = new TollexTools(new TollexClient({ wallet, policy: new PolicyEngine(profile.policy) }), TOLLEX_URL, {
intentDefaults: profile.intentDefaults,
});
// Asking for more than the profile allows does not widen it:
const planned = await agent.resolve({ need: "spot price", input: { pair: "ETH-USD" }, constraints: { maxCost: usdg("1") } });
planned.constraints.maxCost; // 5000n: the profile's per-request ceilingThe signing policy is enforced again when the payment is signed, with durable budgets. Composition only makes the plan match what signing would allow; it is not the last line of defence.