BrowserStack AI Evals
EvaluationTools

Variable Substitution

Inject runtime values into tool parameter schemas using Mustache placeholders.

Variable Substitution

Tool schemas can contain {{placeholder}} markers that are resolved at compile time. This lets you store a single parameterised tool definition and inject environment-specific or request-specific values when fetching the tool.

How It Works

The compile() method on the tool returned by Tool.get() accepts two maps:

MapPurpose
stringsInline string substitution — values are rendered into surrounding text
objectsTyped value injection — replaces a sole {{placeholder}} with any JSON value (object, array, number, etc.)

The substitution rules differ depending on whether the placeholder is the entire string or embedded within text:

Sole placeholder — the entire string value is "{{key}}" (whitespace-tolerant):

  • Checks objects first; injects the typed value as-is (object, number, boolean, etc.)
  • Falls back to strings if the key is absent from objects
  • Returns '' if the key is in neither map

Inline placeholder{{key}} embedded within other text, e.g. "Search in {{region}}":

  • Rendered with Mustache using the strings map only
  • objects values have no effect on inline placeholders

Arrays and nested objects are traversed recursively, so placeholders anywhere in the parameters schema are resolved.

Examples

String substitution

const result = await tools.get('search_web');

const compiled = result.compile({
  strings: { defaultRegion: 'us-east-1' },
});
// Replaces "{{defaultRegion}}" in any description string with "us-east-1"

Object injection

const compiled = result.compile({
  objects: { extraParams: { timeout: 30, retries: 3 } },
});
// Replaces a sole "{{extraParams}}" value with the full object

Combined

const compiled = result.compile({
  strings: { category: 'electronics' },
  objects: { priceRange: { min: 0, max: 500 } },
});

const response = await openai.chat.completions.create({
  model: 'gpt-4o',
  messages: [{ role: 'user', content: 'Find laptops.' }],
  tools: [compiled as any],
  tool_choice: 'auto',
});

Key conflict: same key in both maps

When the same key appears in both maps, objects wins for a sole placeholder and strings wins for an inline placeholder:

// Sole placeholder → objects wins
result.compile({
  strings: { input: 'Browserstack' },
  objects: { input: { name: 'Browserstack' } },
});
// "{{input}}" → { name: "Browserstack" }

// Inline placeholder → strings wins
result.compile({
  strings: { input: 'Browserstack' },
  objects: { input: { name: 'Browserstack' } },
});
// "Hello {{input}}" → "Hello Browserstack"

Missing key

result.compile({});
// "{{missing}}" → ""
// "Hello {{missing}}" → "Hello "

Compiling a ToolList

When a prompt has tools attached, compile all tools with shared variables in one call:

import { AISDK, Prompt } from '@browserstack/ai-sdk';

const prompt = await Prompt.get('agent-prompt');
const compiledTools = prompt.tools.compile({
  strings: { env: 'production' },
  objects: { config: { timeout: 30 } },
});

String substitution

from browserstack_ai_sdk import Tool

tool = Tool.get("search_products", provider="openai")

compiled = tool.compile(
    strings={"category": "electronics"},
)
# Replaces "{{category}}" in any description string

Object injection

compiled = tool.compile(
    objects={"price_range": {"min": 0, "max": 500}},
)
# Replaces a sole "{{price_range}}" value with the full dict

Combined

import openai

compiled = tool.compile(
    strings={"category": "electronics"},
    objects={"price_range": {"min": 0, "max": 500}},
)

client = openai.OpenAI()
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Find me a good laptop."}],
    tools=[compiled],
    tool_choice="auto",
)

Key conflict: same key in both maps

When the same key appears in both maps, objects wins for a sole placeholder and strings wins for an inline placeholder:

# Sole placeholder → objects wins
tool.compile(
    strings={"input": "Browserstack"},
    objects={"input": {"name": "Browserstack"}},
)
# "{{input}}" → {"name": "Browserstack"}

# Inline placeholder → strings wins
tool.compile(
    strings={"input": "Browserstack"},
    objects={"input": {"name": "Browserstack"}},
)
# "Hello {{input}}" → "Hello Browserstack"

Missing key

tool.compile()
# "{{missing}}" → ""
# "Hello {{missing}}" → "Hello "

Compiling a ToolList

When a prompt has tools attached, compile all tools with shared variables in one call:

from browserstack_ai_sdk import Prompt

prompt = Prompt.get("agent-prompt", type="chat")
compiled_tools = prompt.tools.compile(
    strings={"env": "production"},
    objects={"config": {"timeout": 30}},
)

Tool Schema with Placeholders

A stored tool schema might look like this:

{
  "name": "search_products",
  "description": "Search for {{category}} products in {{region}}.",
  "parameters": {
    "type": "object",
    "properties": {
      "query": { "type": "string" },
      "priceRange": "{{price_range}}",
      "maxResults": { "type": "integer", "default": 10 }
    },
    "required": ["query"]
  }
}

At compile time:

  • "{{category}}" and "{{region}}" (inline) → resolved from strings
  • "{{price_range}}" (sole) → replaced with the full object from objects