Skip to content

Prompt Templates

A template engine for building dynamic prompts with variable substitution, built-in functions, caching, and validation.

Basic Usage

import "github.com/joakimcarlsson/ai/prompt"

result, err := prompt.Process("Hello, {{.name}}!", map[string]any{
    "name": "World",
})
// "Hello, World!"

Reusable Templates

tmpl, err := prompt.New("You are {{.role}}. Help with {{.task}}.")
if err != nil {
    log.Fatal(err)
}

result, err := tmpl.Process(map[string]any{
    "role": "a coding assistant",
    "task": "debugging",
})
// "You are a coding assistant. Help with debugging."

Caching

Thread-safe template caching avoids re-parsing the same template repeatedly.

cache := prompt.NewCache()

tmpl, err := prompt.New("You are {{.role}}.",
    prompt.WithCache(cache),
    prompt.WithName("system"),  // cache key
)

When using a cache without WithName, the template source is hashed automatically as the cache key.

Validation

Require specific variables to be present in the data map:

_, err := prompt.Process("Hello, {{.name}}!", map[string]any{},
    prompt.WithRequired("name"),
)
// error: missing required variables: name

Strict Mode

Error on any missing variable instead of using zero values:

tmpl, err := prompt.New("{{.name}} is {{.age}} years old.",
    prompt.WithStrictMode(),
)

_, err = tmpl.Process(map[string]any{"name": "Alice"})
// error: template execution fails because .age is missing

Built-in Functions

String

Function Description Example
upper Uppercase {{upper .name}}
lower Lowercase {{lower .name}}
title Title case {{title .name}}
trim Trim whitespace {{trim .text}}
trimPrefix Remove prefix {{trimPrefix "Mr. " .name}}
trimSuffix Remove suffix {{trimSuffix "." .text}}
replace Replace all {{replace "old" "new" .text}}
contains Check substring {{if contains .text "error"}}...{{end}}
hasPrefix Check prefix {{if hasPrefix .name "Dr."}}...{{end}}
hasSuffix Check suffix {{if hasSuffix .file ".go"}}...{{end}}

Collections

Function Description Example
join Join slice {{join ", " .items}}
split Split string {{split "," .csv}}
first First element {{first .items}}
last Last element {{last .items}}
list Create slice {{list "a" "b" "c"}}

Comparison

Function Description Example
eq Equal {{if eq .role "admin"}}...{{end}}
ne / neq Not equal {{if ne .status "done"}}...{{end}}
lt Less than {{if lt .count 10}}...{{end}}
le Less or equal {{if le .count 10}}...{{end}}
gt Greater than {{if gt .count 0}}...{{end}}
ge Greater or equal {{if ge .count 1}}...{{end}}

Defaults

Function Description Example
default Default value {{default "anonymous" .name}}
coalesce First non-empty {{coalesce .nickname .name "unknown"}}
empty Check if empty {{if empty .list}}...{{end}}
ternary Conditional {{ternary .admin "admin" "user"}}

Formatting

Function Description Example
indent Indent text {{indent 4 .code}}
nindent Newline + indent {{nindent 4 .code}}
quote Double quote {{quote .name}}
squote Single quote {{squote .name}}

Custom Functions

Add your own template functions:

import "text/template"

result, err := prompt.Process("{{shout .name}}", data,
    prompt.WithFuncs(template.FuncMap{
        "shout": func(s string) string {
            return strings.ToUpper(s) + "!!!"
        },
    }),
)

Options

Option Description
prompt.WithCache(c) Enable template caching
prompt.WithName(name) Set template name (used as cache key)
prompt.WithRequired(vars...) Require specific variables
prompt.WithStrictMode() Error on missing variables
prompt.WithFuncs(funcs) Add custom template functions

With Agent Instruction Templates

The prompt package powers the agent's instruction templates feature:

myAgent := agent.New(llmClient,
    agent.WithSystemPrompt("You are {{.role}}. The user's name is {{.userName}}."),
    agent.WithState(map[string]any{
        "role":     "a helpful assistant",
        "userName": "Alice",
    }),
)