| name | golem-add-agent-moonbit |
| description | Adding a new MoonBit agent to a Golem component. Use when the user asks to create, add, or define a new agent type in a MoonBit Golem project. |
Adding a New Agent to a MoonBit Golem Component
Overview
An agent is a durable, stateful unit of computation in Golem. Each agent type is defined as a struct annotated with #derive.agent and has a constructor fn AgentName::new(...) plus public methods pub fn AgentName::method(self: Self).
Steps
- Create the agent file — add a new file
src/<agent_name>.mbt
- Define the agent struct — annotate with
#derive.agent
- Add constructor —
fn AgentName::new(param: Type) -> AgentName
- Add methods —
pub fn AgentName::method(self: Self) -> ReturnType
- Build — run
golem build to verify
Agent Definition
#derive.agent
struct MyAgent {
name: String
mut count: UInt
}
fn MyAgent::new(name: String) -> MyAgent {
{ name, count: 0 }
}
pub fn MyAgent::get_count(self: Self) -> UInt {
self.count
}
pub fn MyAgent::increment(self: Self) -> UInt {
self.count = self.count + 1
self.count
}
Custom Types
All parameter and return types must have schema support. For custom structs and enums, annotate with #derive.golem_schema:
#derive.golem_schema
struct MyData {
field1: String
field2: UInt
}
#derive.golem_schema
enum Status {
Active
Inactive(String)
}
Returning Failures
Agent methods should distinguish between domain errors (expected failure outcomes) and uncaught errors:
- Uncaught errors (uncaught
raise, aborts, runtime panics) are not returned to the caller as a failed invocation. Golem treats them as crashes: the invocation is retried according to the agent's retry policy, and if the retries are exhausted the agent itself becomes failed.
- Domain errors that the caller should observe as a normal failure result must be expressed in the method's return type using
Result[T, E]. Custom error types need #derive.golem_schema.
#derive.golem_schema
pub(all) enum WithdrawError {
InsufficientFunds(UInt64)
AccountClosed
}
#derive.agent
struct Wallet {
owner : String
mut balance : UInt64
mut closed : Bool
}
fn Wallet::new(owner : String) -> Wallet {
{ owner, balance: 0, closed: false }
}
pub fn Wallet::withdraw(self : Self, amount : UInt64) -> Result[UInt64, WithdrawError] {
if self.closed {
Err(AccountClosed)
} else if amount > self.balance {
Err(InsufficientFunds(self.balance))
} else {
self.balance = self.balance - amount
Ok(self.balance)
}
}
Returning Err(...) completes the invocation successfully — the caller receives the error as a value. Letting an exception propagate out of the method (e.g. an unhandled raise, or abort(...)) will instead trigger a retry and eventually fail the whole agent.
Key Constraints
- Constructor parameters form the agent identity — two agents with the same parameters are the same agent
- Agents are created implicitly on first invocation — no separate creation step
- Invocations are processed sequentially in a single thread — no concurrency within a single agent
- Method names use
snake_case
- Never edit generated files —
golem_reexports.mbt, golem_agents.mbt, and golem_derive.mbt are auto-generated by golem build
- Only
pub fn methods are exposed as agent methods — private functions are not exported