Anvia
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

Path

  1. Read Runtime Boundaries to confirm ownership is clear.
  2. Read Errors 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.

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.

Runtime Wrapper Shape

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

import {
  MaxTurnsError,
  PromptCancelledError,
  type Agent,
  type Message,
} from "@anvia/core";

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

export async function runSupportAgent(
  agent: Agent,
  options: RunSupportAgentOptions,
) {
  try {
    const response = await agent
      .prompt(options.input)
      .withHistory(options.history)
      .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.