Learning Paths

Prepare for Production

Review practical checks before shipping Anvia workflows.

Use this path when an Anvia workflow is moving from a prototype into product code.

Goal

By the end, you should have reviewed:

  • provider configuration
  • tool permissions
  • history persistence
  • turn limits
  • structured output validation
  • retries and error handling
  • logging and traces

Checklist

AreaCheck
ProvidersCreate clients and models once, configure keys through your normal secret system
ToolsEnforce auth and permissions inside tool code
HistoryPersist Message[] and append response.messages
Turn limitsKeep limits low enough to prevent unbounded tool loops
Structured outputValidate output before using it in product workflows
RetrievalFilter by tenant, user, or document ownership when needed
ObservabilityLog run metadata, usage, tool calls, errors, and trace ids
ErrorsClassify setup, provider, validation, tool, and runtime-limit failures
TestingCover tools, deterministic pipeline steps, retrieval filters, and Studio routes before broad provider tests

Path

  1. Read How Anvia Works to confirm ownership is clear.
  2. Read Errors and Cancellation to plan failure handling.
  3. Read Human in the Loop for guarded actions.
  4. Read Messages and History for persistence shape.
  5. Read Output Validation for typed workflows.
  6. Read Observers for runtime visibility.
  7. Read Testing for verification boundaries.

Practical Rule

Keep product-critical decisions in your application code. Use Anvia to coordinate prompts, tools, context, retrieval, output shape, and observability around those decisions.

Deployment Shape

Create provider clients, models, and long-lived agents at application startup when possible. Keep per-request data in the prompt request:

Startup-ownedRequest-owned
provider clients and model instancesuser input and message history
reusable agents, tools, and pipelinestrace metadata and session ids
durable stores and connection registriesrequest-specific turn limits and hooks

If a workflow runs in a queue or background worker, pass the same explicit inputs you would pass in an HTTP route: current message, stored history, product metadata, and any request-local authorization context.

Usage and Rate Limits

Use response.usage and trace metadata to build product-level controls:

await usageEvents.record({
  userId: options.userId,
  inputTokens: response.usage.inputTokens,
  outputTokens: response.usage.outputTokens,
  totalTokens: response.usage.totalTokens,
  traceId: response.trace?.traceId,
});

Keep retry policy in application code. Provider failures, rate limits, and tool failures need different product decisions, so do not hide them behind a generic retry loop.

Runtime Wrapper Shape

Put agent calls behind a small application-owned wrapper so logging, history, trace metadata, and error handling are consistent.

import {
  type AgentBuilder,
  MaxTurnsError,
  Message,
  PromptCancelledError,
  type Message as MessageType,
} from "@anvia/core";

type Agent = ReturnType<AgentBuilder["build"]>;

type RunSupportAgentOptions = {
  userId: string;
  conversationId: string;
  input: string;
  history: MessageType[];
};

export async function runSupportAgent(
  agent: Agent,
  options: RunSupportAgentOptions,
) {
  try {
    const response = await agent
      .prompt([...options.history, Message.user(options.input)])
      .withTrace({
        name: "support-agent",
        userId: options.userId,
        sessionId: options.conversationId,
      })
      .maxTurns(3)
      .send();

    await conversations.saveMessages(options.conversationId, [
      ...options.history,
      ...response.messages,
    ]);

    await usageEvents.record({
      userId: options.userId,
      totalTokens: response.usage.totalTokens,
      traceId: response.trace?.traceId,
    });

    return response.output;
  } catch (error) {
    if (error instanceof MaxTurnsError) {
      await incidents.record("support-agent-max-turns", error);
      return "The support workflow could not finish safely.";
    }

    if (error instanceof PromptCancelledError) {
      return "The support request was cancelled.";
    }

    await incidents.record("support-agent-failed", error);
    throw error;
  }
}

Keep the wrapper small. It should coordinate application policy around the agent, not hide all SDK concepts from the rest of the codebase.