Skip to main content

Your First Agent

Let’s build a simple travel assistant agent that can recommend destinations and plan itineraries. This guide will walk you through the core concepts of PromptSmith.
1

Import the Builder

Start by importing the createPromptBuilder function from PromptSmith:
import { createPromptBuilder } from "promptsmith-ts/builder";
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
Make sure you’ve already installed the required packages. See the Installation guide if you haven’t.
2

Create the Agent

Use the builder’s fluent API to configure your agent:
const agent = createPromptBuilder()
  .withIdentity("You are a helpful travel assistant")
  .withCapabilities([
    "Recommend destinations based on user preferences",
    "Plan detailed itineraries",
    "Provide travel tips and advice",
  ])
  .withTone("Enthusiastic, knowledgeable, and helpful");
What’s happening here?
  • withIdentity() - Defines who or what the agent is
  • withCapabilities() - Lists what the agent can do
  • withTone() - Sets the communication style
3

Generate a Response

Use the agent with Vercel AI SDK:
const { text } = await generateText({
  model: openai("gpt-4"),
  ...agent.toAiSdk(), // Spreads { system, tools }
  prompt: "I want to visit Japan for 2 weeks. What should I see?",
});

console.log(text);
The .toAiSdk() method exports the complete configuration for Vercel AI SDK, including the system prompt and any tools.

Complete Example

Here’s the complete code from the steps above:
travel-assistant.ts
import { createPromptBuilder } from "promptsmith-ts/builder";
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";

async function main() {
  // Create a basic travel assistant
  const agent = createPromptBuilder()
    .withIdentity("You are a helpful travel assistant")
    .withCapabilities([
      "Recommend destinations based on user preferences",
      "Plan detailed itineraries",
      "Provide travel tips and advice",
    ])
    .withTone("Enthusiastic, knowledgeable, and helpful");

  // Generate response
  const { text } = await generateText({
    model: openai("gpt-4"),
    ...agent.toAiSdk(),
    prompt: "I want to visit Japan for 2 weeks. What should I see?",
  });

  console.log(text);
}

main().catch(console.error);
node travel-assistant.ts

Adding Tools

Now let’s enhance our agent with a tool to fetch real-time weather data:
1

Define the Tool

Import Zod and create a tool definition with a schema:
import { z } from "zod";

// Mock weather API (replace with real API in production)
async function fetchWeather(location: string, units: string) {
  return {
    location,
    temperature: units === "celsius" ? "22°C" : "72°F",
    conditions: "Partly cloudy",
    humidity: "65%",
  };
}
2

Register the Tool

Add the tool to your agent with .withTool():
const weatherAgent = createPromptBuilder()
  .withIdentity("You are a weather information assistant")
  .withCapabilities([
    "Provide current weather conditions",
    "Answer weather-related questions",
  ])
  .withTool({
    name: "get_weather",
    description: "Get current weather for a location",
    schema: z.object({
      location: z.string().describe("City name or coordinates"),
      units: z.enum(["celsius", "fahrenheit"]).default("celsius"),
    }),
    execute: async ({ location, units }) => {
      return await fetchWeather(location, units);
    },
  })
  .withConstraint("must", "Always use the weather tool for current conditions")
  .withTone("Friendly and informative");
The Zod schema provides full type inference for the execute function parameters. TypeScript knows that location is a string and units is “celsius” or “fahrenheit”.
3

Use the Agent

The tool is automatically included when you export to AI SDK:
const { text } = await generateText({
  model: openai("gpt-4"),
  ...weatherAgent.toAiSdk(), // Includes both system prompt and tools
  prompt: "What's the weather like in Tokyo?",
});

Complete Tool Example

weather-agent.ts
import { createPromptBuilder } from "promptsmith-ts/builder";
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";

// Mock weather API
async function fetchWeather(location: string, units: string) {
  return {
    location,
    temperature: units === "celsius" ? "22°C" : "72°F",
    conditions: "Partly cloudy",
    humidity: "65%",
  };
}

async function main() {
  const weatherAgent = createPromptBuilder()
    .withIdentity("You are a weather information assistant")
    .withCapabilities([
      "Provide current weather conditions",
      "Answer weather-related questions",
    ])
    .withTool({
      name: "get_weather",
      description: "Get current weather for a location",
      schema: z.object({
        location: z.string().describe("City name or coordinates"),
        units: z.enum(["celsius", "fahrenheit"]).default("celsius"),
      }),
      execute: async ({ location, units }) => {
        return await fetchWeather(location, units);
      },
    })
    .withConstraint("must", "Always use the weather tool for current conditions")
    .withConstraint("must_not", "Provide weather information without checking the tool")
    .withTone("Friendly and informative");

  const { text } = await generateText({
    model: openai("gpt-4"),
    ...weatherAgent.toAiSdk(),
    prompt: "What's the weather like in Tokyo?",
  });

  console.log(text);
}

main().catch(console.error);

Key Concepts

Identity

Defines who or what the agent is. This appears first in the system prompt and frames all subsequent instructions.
.withIdentity("You are a helpful assistant")

Capabilities

Lists what the agent can do. Each capability should describe a specific skill or action.
.withCapabilities(["Search", "Summarize"])

Tools

External functions the agent can invoke. Defined with Zod schemas for type safety.
.withTool({
  name: "search",
  schema: z.object({...}),
  execute: async (args) => {...}
})

Constraints

Rules that govern the agent’s behavior with different severity levels (must, must_not, should, should_not).
.withConstraint("must", "Verify identity")

Tone

Sets the communication style and personality of the agent.
.withTone("Professional and friendly")

Guardrails

Built-in security measures to protect against prompt injection and malicious use.
.withGuardrails()

Adding Security

For production agents, always enable security guardrails:
const secureAgent = createPromptBuilder()
  .withIdentity("You are a customer service assistant")
  .withCapabilities(["Answer questions", "Process returns"])
  .withGuardrails() // Enable anti-prompt-injection security
  .withForbiddenTopics([
    "Medical diagnosis or treatment advice",
    "Legal advice or interpretation of laws",
    "Financial investment recommendations",
  ])
  .withConstraint("must", "Always verify user authentication before accessing personal data")
  .withConstraint("must_not", "Never store or log sensitive information");
Always enable guardrails for production agents that handle user input. Use .withGuardrails() to protect against prompt injection attacks.

Using with Mastra

PromptSmith also works seamlessly with Mastra:
import { Agent } from "@mastra/core/agent";
import { createPromptBuilder } from "promptsmith-ts/builder";
import { z } from "zod";

const promptBuilder = createPromptBuilder()
  .withIdentity("Weather information assistant")
  .withCapabilities(["Provide current weather conditions"])
  .withTool({
    name: "get-weather",
    description: "Get current weather for a location",
    schema: z.object({
      location: z.string(),
      units: z.enum(["celsius", "fahrenheit"]).default("celsius"),
    }),
    execute: async ({ location, units }) => {
      return await fetchWeather(location, units);
    },
  })
  .withTone("Friendly and informative");

// Single method exports both instructions and tools
const { instructions, tools } = promptBuilder.toMastra();

const weatherAgent = new Agent({
  name: "weather-assistant",
  instructions,
  model: "anthropic/claude-3-5-sonnet",
  tools, // Already in Mastra format
});
The .toMastra() method automatically converts PromptSmith tools to Mastra’s format, eliminating tool duplication.

Debugging Your Agent

Use the .debug() method to inspect your agent’s configuration:
const agent = createPromptBuilder()
  .withIdentity("Travel assistant")
  .withCapabilities(["Book flights", "Find hotels"])
  .withTool({
    name: "search_flights",
    description: "Search available flights",
    schema: z.object({
      from: z.string(),
      to: z.string(),
      date: z.string(),
    }),
  })
  .withConstraint("must", "Always verify dates")
  .withGuardrails()
  .debug(); // Prints comprehensive debug info
The debug output shows:
  • Configuration summary with counts
  • Detailed section breakdowns
  • Validation warnings and suggestions
  • Token usage estimates
  • Format comparison (markdown vs TOON savings)

Next Steps

Now that you understand the basics, explore more advanced features:

API Reference

Complete documentation of all builder methods

Templates

Pre-built templates for common use cases

Testing

Test your agents before deploying to production

Advanced Patterns

Composition, extension, and reusable patterns

Examples

Real-world examples and use cases

Token Optimization

Reduce costs with TOON format

Example Repository

Explore more examples in the PromptSmith GitHub repository:
  • Basic agents
  • Agents with tools
  • Mastra integration
  • Validation patterns
  • Conditional logic
  • Production patterns
Start with the basic agent example and progressively explore more complex patterns.

Build docs developers (and LLMs) love