Build action and workflow Agents
Build tool-using operators, process automation, approval flows, and browser Agents with explicit effects, waits, and durable progress.
Before you begin
List every world-changing operation and classify its effect as read-only, idempotent, reconcilable, or non-idempotent. Bind exact Resources and Credentials through the deployment, not the message. Decide which operations Policy may allow automatically and which require a human. Use durable mode when progress must survive across waits, retries, or separate invocations.
Steps
- Offer the model narrow Tools with validated schemas and truthful effect ceilings. Deterministic code may invoke the same Resources directly.
- Supply a stable deduplication key for idempotent writes. Let the runtime reconcile ambiguous outcomes; never turn an unknown result into success.
- Use
awaitfor external authority and return explicit serializable state from each durable step. - Commit business truth only after the effect or approval has a proven outcome. A browser is just another governed Resource with interactive operations and evidence.
import { agent } from "@constal/sdk";
type State = {
request: { ticketId: string; summary: string };
phase: "approval" | "apply" | "done" | "rejected";
result?: unknown;
};
export default agent<State>({
id: "change-workflow", version: "1.0.0", model: "model", mode: "durable",
init: (request: State["request"]) => ({ request, phase: "approval" }),
async step(state, ctx) {
if (state.phase === "approval") {
const decision = await ctx.await<{ approved: boolean }>("change-approval", {
schema: { type: "object", required: ["approved"], additionalProperties: false,
properties: { approved: { type: "boolean" } } },
});
return { state: { ...state, phase: decision.approved ? "apply" : "rejected" }, done: !decision.approved };
}
if (state.phase === "apply") {
const result = await ctx.invoke(ctx.resources.ticketing!, "ticket.update", state.request, {
dedupeKey: `ticket-change:${state.request.ticketId}`,
});
await ctx.commit({ kind: "change-applied", ticketId: state.request.ticketId, result });
return { state: { ...state, phase: "done", result }, done: true };
}
return { state, done: true };
},
output: (state) => ({ phase: state.phase, result: state.result }),
});Tool-using operators may stay in script mode when work is bounded and immediate. Choose durable mode for onboarding, claims, procurement, remediation, or any workflow whose state matters between events. Computer-use Agents follow the same rules: screenshots are untrusted observations, clicks are effects, and completion requires verifiable evidence.
Verify
Exercise approval, rejection, timeout, duplicate delivery, provider failure, and ambiguous effect outcomes. Inspect the Run journal for the wait, decision, exact Resource operation, recovery evidence, and final commit. Ensure a replay cannot apply the same change twice and a denied principal cannot substitute another tenant’s Resource or Credential.
Next steps
Read Resources and Tools, Resource effects and recovery, Policies and approvals, and Run controls.