Functions
build-headers
fn (body-text: Str, opts: CallbackOptions): Map
Internal: assemble the headers dictionary for a callback POST. Adds the signature header when a secret is configured.
callback-host
fn (url: Str): Str
Internal: best-effort host extraction for already-lowercased HTTPS callback URLs.
from-body
fn (body: Map?): Any
Build a CallbackOptions from a webhook body. Returns null when
the caller didn't supply a callback URL. Recognized keys (both
kebab-case and snake_case):
callback_url/callback-urlcallback_secret_env/callback-secret-envcallback_signing_header/callback-signing-header
Convenience for transports that accept callback_url in the
inbound payload directly. Non-HTTPS URLs are ignored; callers that
need local development callbacks should use streams or construct
their own stricter transport-local policy.
is-private-callback-host
fn (host: Str): Bool
Internal: reject obvious localhost, link-local, and RFC1918 callback hosts.
is-url-allowed
fn (url: Str?): Bool
Return true when a callback URL is safe for the shared helper to call. The default policy is intentionally narrow: callbacks must be HTTPS and must not target obvious local/private hosts, so untrusted webhook bodies cannot direct the worker at internal services.
ns
Alias of ::ai::agent::callbacks/
Outbound callback support for queued / asynchronous agent replies.
The standard agent webhook contract has three reply modes:
response— the agent computed an answer synchronously and returns it in the HTTP response.queued— the agent kicked off async work (memory recall, LLM call) and returns a placeholder. The transport client is expected to listen on the Hot run stream for the eventual answer, or...callback— same asqueued, but the agent commits to POSTing the final answer to acallback_urlprovided by the caller. This is the right shape for Slack / Telegram / Discord integrations that don't speak Hot's run stream natively.
This module is the agent-side helper for mode 3.
Surface
CallbackOptions—{url, signing-secret-env?, signing-header?, timeout-ms?, headers?}.post-callback(payload, opts)— POSTpayload(JSON-encoded) to an HTTPSopts.url, attaching an HMAC signature header when a signing secret is configured. Returns{ok, status, error?, attempt-ms}.from-body(body)— extract aCallbackOptionsfrom the webhook body'scallback_url/callback_secret_envfields, returningnullwhen no callback was requested.
Transports that want callback parity should:
- Pull a
CallbackOptionsfrom the inbound body viafrom-body. - Reply synchronously with
mode: "queued"andcallback: true. - Once the async work finishes, call
post-callback(answer, opts).
post-callback
fn (payload: Any, opts: CallbackOptions): CallbackResult
POST payload to opts.url as JSON, optionally signing the body
with HMAC-SHA256. Returns a CallbackResult capturing status and
elapsed time so the agent can log / retry.
payload may be any value — it's wrapped through
::hot::json/to-json before transmission.
resolve-secret
fn (literal: Str?, env-name: Str?): Str?
Internal: resolve a literal-or-env signing secret. Returns null when neither is set.
Types
CallbackOptions
CallbackOptions type {
url: Str,
signing-secret-env: Str?,
signing-secret: Str?,
signing-header: Str?,
headers: Map?,
timeout-ms: Int?
}
Configuration for a callback POST.
url— destination URL.signing-secret-env— env var holding the HMAC secret used to sign the JSON body.signing-secret— literal secret (rare; prefer env).signing-header— header name for the signature. Defaults tox-hot-signature. The value is"sha256=<hex>".headers— extra headers to send.timeout-ms— reserved (HTTP timeout — currently advisory).
CallbackResult
CallbackResult type {
ok: Bool,
status: Int,
error: Str?,
attempt-ms: Int
}
Outcome of a callback POST.
ok— true when the upstream returned a 2xx status.status— HTTP status code (or0when the call never reached the server).error— human-readable error string on failure.attempt-ms— wall-clock time spent on the attempt.