Welcome to the new Golem Cloud Docs! 👋
Waiting for External Input with Golem Promises (MoonBit)

Waiting for External Input with Golem Promises (MoonBit)

Overview

A Golem promise lets an agent suspend its execution until an external event completes it. The agent creates a promise, passes the promise ID to an external system (another agent, a webhook, a UI, an HTTP API call), and then awaits the result. The Golem runtime durably suspends the agent — consuming no resources — until the promise is fulfilled.

API

All functions are in the @api package of the Golem MoonBit SDK:

FunctionSignatureDescription
@api.create_promise() -> PromiseIdCreates a new promise and returns its ID
@api.await_promise(PromiseId) -> BytesBlocks until the promise is completed
@api.complete_promise(PromiseId, Bytes) -> BoolCompletes a promise with a byte payload
@api.get_promise(PromiseId) -> PromiseResultGets a handle for polling/getting the result

Usage Pattern

1. Create a Promise and Wait

let promise_id = @api.create_promise()
// Pass promise_id to an external system...

// Agent is durably suspended here until the promise is completed
let data : Bytes = @api.await_promise(promise_id)

2. Complete a Promise from Another Agent

let payload = "approved"
@api.complete_promise(promise_id, Bytes::from_array(payload.to_array().map(fn(c) { c.to_int().to_byte() })))

3. Advanced: Poll without Blocking

let promise_result = @api.get_promise(promise_id)
let pollable = promise_result.subscribe()
// Use pollable with poll infrastructure
match promise_result.get() {
  Some(data) => // promise completed
  None => // not ready yet
}

PromiseId Structure

A PromiseId contains an agent_id and an oplog_idx. To let an external system complete the promise via the Golem REST API, the agent must expose both fields. The external caller then sends:

POST /v1/components/{component_id}/workers/{agent_name}/complete
Content-Type: application/json

{"oplogIdx": <oplog_idx>, "data": [<bytes>]}

Full Example: Human-in-the-Loop Approval

#derive.agent
struct WorkflowAgent {
  name : String
  mut last_result : String
}

fn WorkflowAgent::new(name : String) -> WorkflowAgent {
  { name, last_result: "" }
}

/// Start an approval workflow that waits for external input
pub fn WorkflowAgent::start_approval(self : Self) -> UInt64 {
  let promise_id = @api.create_promise()
  // Return the oplog_idx so the external caller can complete the promise
  promise_id.oplog_idx
}

/// Wait for the approval to arrive and return the result
pub fn WorkflowAgent::wait_for_approval(self : Self, oplog_idx : UInt64) -> String {
  let promise_id = @types.PromiseId::{
    agent_id: @api.get_self_agent_id(),
    oplog_idx,
  }
  let data = @api.await_promise(promise_id)
  let result = String::from_array(data.to_array().map(fn(b) { Char::from_int(b.to_int()) }))
  self.last_result = result
  result
}

Use Cases

  • Human-in-the-loop: Pause a workflow until a human approves or rejects
  • Webhook callbacks: Wait for an external HTTP callback to arrive
  • Inter-agent synchronization: One agent creates a promise, another completes it
  • External event ingestion: Suspend until an IoT sensor, payment gateway, or third-party API sends a signal