PRC-Agent Contracts

A PRC-Agent is an autonomous, on-chain agent with a stable identity, a declared set of capabilities, and a single execute(task) entry point. This page documents the reference implementation and two example agents. For the standard itself, see PRC-Agent; for the broader design, see AI Agents.

ContractPurpose
PRCAgentSelf-contained reference implementation with identity, capabilities, and task execution.
TradingAgentExample agent that executes buy/sell trading tasks and logs positions.
DataLabelingAgentExample agent that labels data points and maintains a labeled dataset.

The two example agents are deployable from the playground (AI Agents category). Each has an in-editor tutorial.


The common shape

Every PRC-Agent shares the same core state and entry point:

class State:
    agent_id: str      # ctx.contract_address -- the agent's identity
    owner: str         # who deployed it
    capabilities: list # what it's allowed to do
    active: bool       # can it accept tasks?

@call
def execute(self, ctx, task: dict) -> dict:
    ...

Agents identify themselves by their own contract address, declare capabilities at construction, and expose lifecycle control (revoke) to the owner. All task handling flows through execute(task), where the task dict shape is agent-specific.


PRCAgent (reference implementation)

The reference PRCAgent supports a fixed capability vocabulary: inference, training, data_access, cross_contract. Capabilities passed at construction are filtered to this set.

Methods

MethodKindDescription
__init__(agent_uri, capabilities)constructorRegisters the agent, filtering capabilities to the valid set. Emits AgentRegistered.
register(agent_uri, capabilities)callOwner re-registers/updates the agent. Emits AgentUpdated. Returns the agent id.
bind_capability(capability)callOwner adds a capability. Emits CapabilityBound.
execute(task)callRuns a task whose type must be one of the agent's capabilities. Logs it (last 100). Emits TaskExecuted. Returns {"status": "completed", "task_id", "agent_id"}.
revoke()callOwner deactivates the agent. Emits AgentRevoked.
get_agent()queryFull profile: id, owner, uri, capabilities, active, task_count.
get_capabilities()queryThe capability list.
get_execution_log()queryRecent execution log entries.

A task like {"type": "inference", "input": [1, 2, 3]} is accepted only if the agent declared the inference capability; otherwise it raises.


TradingAgent (example)

TradingAgent accepts buy/sell tasks and keeps an auditable position log.

  • Capabilities: ["inference", "data_access"]
  • Task shape: {"action": "buy"|"sell", "asset": str, "amount": float}
MethodKindDescription
__init__(strategy="momentum")constructorRegisters the agent. Emits AgentRegistered.
execute(task)callValidates the action, records a position (capped at 1000), increments total_trades. Emits TradeExecuted. Returns {"trade_id", "status": "executed"}.
revoke()callOwner deactivates the agent.
get_agent()queryAgent profile with total_trades.
get_capabilities()queryThe capability list.
get_positions(limit=50)queryThe most recent positions, each with trade_id, action, asset, amount, block.

An invalid action or a missing asset reverts. Because the log is on-chain, anyone can audit the agent's full trading history.


DataLabelingAgent (example)

DataLabelingAgent labels data points, either from an explicit label (supervised) or heuristically.

  • Capabilities: ["inference", "training"]
  • Task shape: {"data_id": str, "features": list, "label": str}

When label is empty, the agent assigns "positive" if avg(features) > 0, else "negative" (or "unknown" if no features).

MethodKindDescription
__init__(model_uri="")constructorRegisters the agent. Emits AgentRegistered.
execute(task)callStores a label (explicit or heuristic) with a features hash, labeler, and block. Emits DataLabeled. Returns {"data_id", "label", "status": "labeled"}.
revoke()callOwner deactivates the agent.
get_agent()queryAgent profile with label_count.
get_capabilities()queryThe capability list.
get_label(data_id)queryThe stored label record for a data point.
get_label_count()queryTotal labels stored.

Re-labeling the same data_id overwrites the previous label — useful for corrections.


Verifiability

Every execute transaction runs inside the deterministic PandaVM and produces a receipt. Because identical inputs against identical state yield identical outputs, any node can re-execute a past task and confirm the result. This is what makes an on-chain agent auditable rather than a black box.


Try it