Docs

Examples

Backoffice Agent

A real-case internal workflow with guarded writes, approvals, idempotency, and audit.

A backoffice agent helps internal users perform operational workflows. It can read product state, propose actions, and call guarded side-effect tools, but normal admin permissions and audit requirements still apply.

Scenario

An operations user asks the agent to refund an order, create a ticket, and notify finance. Refunds over a threshold require approval, every write needs an idempotency key, and every action must be auditable.

Flow

Step Pattern
authorize operator Agent App Flow
compose operational tools Permissioned Tools
guard writes Guarded Side Effects
request approval Human Input / Tool Approvals
persist audit Runtime State and Persistence

Example

import { AgentBuilder } from "@anvia/core";

const BACKOFFICE_INSTRUCTIONS = [
  "Use tools for operational actions.",
  "Explain which actions were performed and which were denied.",
  "Do not perform destructive actions without approval.",
  "Never rely on prompt text for permissions.",
].join("\n");

export async function runBackofficeAction(input: BackofficeInput) {
  const operator = await input.auth.requireUser();
  await input.authz.require(operator, "backoffice:use_agent");

  const agent = new AgentBuilder("backoffice", input.model)
    .instructions(BACKOFFICE_INSTRUCTIONS)
    .tools(createBackofficeTools({
      operator,
      services: input.services,
      auditLog: input.auditLog,
      authz: input.authz,
      idempotencyKey: input.idempotencyKey,
    }))
    .defaultMaxTurns(5)
    .build();

  const response = await agent
    .prompt(input.message)
    .withTrace({
      name: "backoffice-agent",
      userId: operator.id,
      metadata: {
        tenantId: operator.tenantId,
        operatorId: operator.id,
        requestId: input.requestId,
      },
    })
    .approvals(input.approvals)
    .send();

  await input.runRecords.record({
    requestId: input.requestId,
    operatorId: operator.id,
    traceId: response.trace?.traceId,
    output: response.output,
  });

  return { output: response.output };
}

Guarded write tools record audit data inside execution:

await auditLog.record({
  actorId: operator.id,
  action: "refund.issue",
  targetId: orderId,
  idempotencyKey,
  metadata: { amountCents, refundId },
});

Production Checks

  • Admin permission checks live in services/tools, not prompt text.
  • Approval decisions are persisted with reviewer identity.
  • Retried runs reuse idempotency keys.
  • Tool outputs omit private payment and internal finance data.
  • Run records link trace id, operator id, request id, and audit ids.

Failure Modes

  • Agent tools bypass normal admin permissions.
  • Audit logs depend on the model’s final answer.
  • Retried runs duplicate writes.
  • Approval state is not persisted.
  • Rejection messages leak internal policy or payment details.

Next Patterns