fabric/invoke
Serve an agent or graph run as a bounded request and response.
No transport is assumed: an HTTP handler, MCP handler or job can use
the same service. agent and graph bind execution; request holds
caller-owned input. Configuration is opaque and waits default to 25 s.
A key is scoped by service, runtime family and principal. Retries with
the same input reopen that run even when their correlation changes;
a changed input is key_reused. The first request’s correlation stays
with the run. Use a stable authenticated principal in a shared service.
Without a key each request starts a fresh run; a deadline or the
supplied cancellation selector cancels work still in flight. Keyed
work outlives a disconnect, bounded by the agent or graph’s limits.
Approval and reconciliation return immediately with the run id: the
application owns following them up, including unkeyed requests.
let service = invoke.agent("desk", runs, desk)
let request = invoke.request(context, "Help with order 42")
|> invoke.with_principal(subject)
|> invoke.with_key(Some(request_key))
|> invoke.with_cancelled(disconnected)
let response = invoke.call(service, request)
case invoke.answer(response) {
Some(answer) -> respond(answer)
None -> pending(invoke.id(response), invoke.describe_response(response))
}
An unavailable admission returns OutcomeUnknown with the attempted run id.
Retry with the same principal and key, or recover that run explicitly;
do not interpret an unconfirmed start as refusal to create a run.
A cancellation failure is reported explicitly; it never claims the
run stopped. Read or recover such a run by id. An unknown effect needs
reconciliation, not a retry of the effect. Cancelled and expired runs
retain unresolved effect evidence in OutcomeUnknown, including effects
owned by a child. A completion committed before cancellation retains its
native answer.
Serving through Relay
Copy the module relay_serve of consumers/relay_tools into the
application; that consumer compiles and tests it. relay_serve.serve
checks the service with invoke.check and serves a Relay tool call
through it. The call’s idempotency key, correlation and cancellation reach
the request, and the response’s run id travels in the result metadata
under io.github.gleam-dream/run-id. An answer completes the call; a
response without one is a tool error that carries the response details.
See the README and the design layer for composition and failure handling.
Reading a Relay run id
Copy the module relay_run of consumers/relay_tools into the
application; that consumer compiles and tests it. relay_run.run_of reads
the run id from a client tool result’s metadata and returns None when
the entry is absent or is not a valid run id. See the README and the
design layer for composition and failure handling.
Types
A finite wait must fit the BEAM timer range. Invocation deliberately requires a deadline; continuing keyed work has its own runtime bounds.
pub type ConfigError {
InvalidWait(value: Int, minimum: Int, maximum: Int)
}
Constructors
-
InvalidWait(value: Int, minimum: Int, maximum: Int)
Stable next-action classification. Detailed machine codes may grow.
pub type Kind {
Answered
Working
AwaitingApproval
AwaitingInput
OutcomeUnknown
Unattended
Ended
Refused
}
Constructors
-
Answered -
Working -
AwaitingApproval -
AwaitingInput -
OutcomeUnknown -
Unattended -
Ended -
Refused
Caller-owned input and identity. Context and cancellation are never stored.
pub opaque type Request(context, input)
A response always names the attempted run, including start failures.
facts is a portable JSON object for rendering structured failures;
native successful answers are available through answer.
pub opaque type Response(answer)
Values
pub fn agent(
name: String,
runs: store.Store,
agent: agent.Agent(c, a),
) -> Service(c, String, a)
Bind an agent; its prompt is the request input and its context is live.
pub fn agent_with_history(
name: String,
runs: store.Store,
agent: agent.Agent(c, a),
) -> Service(c, input.Input, a)
Bind an agent to validated original history and its current prompt.
Keyed retries compare the complete original input and reopen the same
run; waiting, cancellation and typed answers follow agent unchanged.
pub fn answer(response: Response(a)) -> option.Option(a)
pub fn call(
service: Service(c, i, a),
request: Request(c, i),
) -> Response(a)
Start or reopen, then wait once. Invalid configuration starts nothing.
pub fn check(
service: Service(c, i, a),
) -> Result(Nil, ConfigError)
Validate configuration at application startup, before accepting calls.
pub fn describe_config_error(error: ConfigError) -> String
pub fn describe_response(response: Response(a)) -> String
pub fn details(response: Response(a)) -> value.Value
A portable object with error, run_id and any approval or uncertain
effect evidence. Successful answers should be rendered from answer.
pub fn graph(
name: String,
runtime: graph.Runtime(c, s, a),
) -> Service(Nil, s, a)
Bind a graph. Its runtime owns context; pass Nil as request context
and the native initial state as input. Retries compare the original
state, even after the graph has changed it.
pub fn keyed_id(
service: Service(c, i, a),
principal: String,
key: String,
) -> run.RunId
A collision-resistant, unambiguous identity for this service, principal and key. JSON frames the parts before hashing; separators inside any part cannot alias another request. This differs from the old MCP bridge derivation; previously written runs remain accessible by their old id.
pub fn request(
context: context,
input: input,
) -> Request(context, input)
Build a request for one trusted anonymous caller. Shared services must set the authenticated principal before accepting an idempotency key.
pub fn with_cancelled(
request: Request(c, i),
cancelled: process.Selector(Nil),
) -> Request(c, i)
The caller supplies its disconnect or monitor selector. Consumed only for an unkeyed request; keyed requests outlive the caller.
pub fn with_correlation(
request: Request(c, i),
correlation: correlation.Correlation,
) -> Request(c, i)
pub fn with_key(
request: Request(c, i),
key: option.Option(String),
) -> Request(c, i)
pub fn with_principal(
request: Request(c, i),
principal: String,
) -> Request(c, i)
Scopes execution identity; this does not authenticate the caller.
pub fn with_wait(
service: Service(c, i, a),
wait: duration.Duration,
) -> Service(c, i, a)