ZTS Docs
AI

Agents

ToolLoopAgent, built-in tools, and tRPC-as-tools for the in-app chat agent.

The in-app chat uses a ToolLoopAgent from the Vercel AI SDK — not the MCP server. Agents can call built-in demo tools and, on the web chat route, authenticated tRPC procedures exposed as tools.

Core agent (@zts/ai)

createZtsAgent() in packages/ai/src/create-zts-agent.ts wraps ToolLoopAgent:

import { createZtsAgent } from "@zts/ai";
 
const agent = createZtsAgent({
  model,                    // from createLanguageModel
  toolContext: { preferences, userEmail, userName },
  instructions: "...",      // optional — defaults to ZTS_AGENT_INSTRUCTIONS
  tools: mergedToolSet,     // optional — defaults to createZtsAgentTools
});
OptionDefault
Agent id"zts-assistant"
Stop conditionstepCountIs(20) — up to 20 tool-loop steps
InstructionsHelp users build and ship with Zero To Shipped

Default instructions encourage concise answers and tool use when accuracy requires it.

Built-in tools

createZtsAgentTools() in packages/ai/src/tools/index.ts:

ToolPurpose
getCurrentTimeCurrent ISO timestamp + server timezone
getUserContextSigned-in user name/email + configured provider names
calculateSafe evaluation of basic arithmetic expressions

These are demos — replace or extend them for your product.

Adding a built-in tool

import { tool } from "ai";
import { z } from "zod";
 
export const createZtsAgentTools = (context: ZtsAgentToolContext): ToolSet => ({
  // ...existing tools
  searchDocs: tool({
    description: "Search product documentation",
    inputSchema: z.object({ query: z.string() }),
    execute: async ({ query }) => {
      // your logic
      return { results: [] };
    },
  }),
});

Pass custom tools via createZtsAgent({ tools: { ...createZtsAgentTools(ctx), ...myTools } }).

tRPC-as-tools (web chat only)

apps/web/src/server/trpc-agent-tools.ts uses trpc-to-mcp's extractToolsFromProcedures(appRouter) to turn authenticated tRPC procedures into agent tools.

In apps/web/src/app/api/chat/route.ts, tools are merged:

const agent = createZtsAgent({
  model,
  toolContext: { preferences, userEmail, userName },
  tools: {
    ...createZtsAgentTools({ preferences, userEmail, userName }),
    ...createTrpcAgentTools(ctx),  // session-scoped tRPC context
  },
});

This lets the in-app agent call the same business logic as the web app (e.g. update preferences, fetch profile) without duplicating HTTP clients.

Scope: These are session-scoped tRPC tools — different from MCP tools, which use API keys and only expose apiExposure() procedures.

Language model + intelligence

Before creating the agent, the chat route:

  1. resolveUserAiProvider — pick provider + key from preferences
  2. createLanguageModel@ai-sdk/* model instance
  3. resolveIntelligenceForModel — clamp thinking level to what the model supports

See Providers for catalog and intelligence details.

Customizing agent behavior

Instructions

Override default system prompt:

createZtsAgent({
  model,
  toolContext,
  instructions: "You are a billing assistant for Acme Corp. Be brief.",
});

Or edit ZTS_AGENT_INSTRUCTIONS in create-zts-agent.ts for a global default.

Step limit

Adjust stopWhen in create-zts-agent.ts if 20 steps is too many or too few for your tool graph.

Separate agents

For multiple agent personas (support vs. codegen), create factory functions that return different ToolLoopAgent instances with distinct instructions and tools sets, then route to them from separate API routes.

MCP tools vs in-app agent tools

MCP (/api/mcp)In-app ToolLoopAgent
HostCursor, external agentsWeb chat UI
AuthAPI key / MCP OAuthSession cookie
Tool sourceapiExposure() procedures onlyBuilt-in tools + optional full tRPC router
TransportMCP protocolPOST /api/chat streaming
DocsMCPThis page

Testing

apps/web/src/app/api/chat/route.test.ts covers the chat route. Vitest aliases @zts/ai to packages/ai/src/index.ts via apps/web/vitest.config.ts.

  • Chat — API route and UI wiring
  • Providers — model resolution
  • MCP — external agent tools (separate surface)

On this page