Skip to main content
Endpoint connection input templates use a template syntax based on Nunjucks (compatible with Jinja2) to inject test case data into request bodies. This page covers the structured input placeholder syntax, JSON escaping behavior, the placeholder toolbar in the dashboard, and how missing fields are handled.

Structured Input Placeholders

For CONVERSATION-type endpoint connections, the input template must reference at least one field from the test case’s structured input using property access syntax:
{{ input.field_name }}
For example, if your test case input has fields user_message and customer_id, you reference them as {{ input.user_message }} and {{ input.customer_id }}.
Bare {{ input }} and {{ context }} are not valid and will be rejected by validation. Always use property access syntax: {{ input.field_name }} or {{ context.field_name }}.

Context Fields

Test cases can include structured context alongside the input. Access context fields with the same property access syntax:
{{ context.field_name }}
For example, {{ context.topic }}, {{ context.system_prompt }}, or {{ context.language }}.

Complete Placeholder Reference

PlaceholderDescription
{{ input.<field> }}Access a field from the test case input (required). Example: {{ input.user_message }}
{{ context.<field> }}Access a field from the test case context. Example: {{ context.topic }}
{{ session_id }}The external session ID (if available)
{{ galtea_session_id }}Galtea’s internal session identifier
{{ test_case_id }}The current test case ID
{{ test_id }}The current test ID
{{ inference_result_id }}The inference result ID for this turn (also sent as the X-Galtea-Inference-Id header for trace collection)
{{ language_code }}ISO 639-1 language code from the test case (e.g. "es"). Empty string when the test case has no language set.
{{ language_name }}Full English name of the test case language (e.g. "Spanish"). Empty string when the test case has no language set.
past_turnsConversation history loop collection. Use with {% for turn in past_turns %}. See Conversation History.
Any metadata keyFields extracted via Output Mapping and stored in session metadata (e.g., {{ tenant_id }})

Examples

Single Input Field

The simplest template sends a single user message to an OpenAI-compatible endpoint:
{
  "model": "gpt-4",
  "messages": [
    {"role": "user", "content": "{{ input.user_message }}"}
  ]
}

Multiple Input Fields

When your test cases have several input fields, reference each one by name:
{
  "model": "gpt-4",
  "messages": [
    {"role": "system", "content": "You are a customer support agent."},
    {"role": "user", "content": "Customer ID: {{ input.customer_id }}. Question: {{ input.question }}"}
  ],
  "metadata": {
    "department": "{{ input.department }}"
  }
}

Using Context Fields

Context fields provide test case-specific information alongside the input. A common use case is passing a system prompt or topic:
{
  "model": "gpt-4",
  "messages": [
    {"role": "system", "content": "{{ context.system_prompt }}"},
    {"role": "user", "content": "{{ input.user_message }}"}
  ]
}

Built-in Language Variables

Every test case stores its language. Use the built-in {{ language_code }} and {{ language_name }} variables to pass language information to your endpoint without defining language in the input schema:
{
  "message": "{{ input.user_message }}",
  "language": "{{ language_code }}"
}
Or use the full language name:
{
  "model": "gpt-4",
  "messages": [
    {"role": "system", "content": "Always respond in {{ language_name }}."},
    {"role": "user", "content": "{{ input.user_message }}"}
  ]
}
Both resolve to empty strings for language-agnostic test cases (those with no language set).
If your input schema already has a language field, it still works via {{ input.language }}. The built-in {{ language_code }} and {{ language_name }} variables are an additional convenience that avoids defining language in the schema.

Conversation History

Use {% for turn in past_turns %} to include previous conversation turns:
{
  "model": "gpt-4",
  "messages": [
    {"role": "system", "content": "{{ context.system_prompt }}"},
    {% for turn in past_turns %}
    {"role": "user", "content": "{{ turn.input }}"},
    {"role": "assistant", "content": "{{ turn.output }}"},
    {% endfor %}
    {"role": "user", "content": "{{ input.user_message }}"}
  ]
}
Each turn exposes two properties:
  • {{ turn.input }} - the previous user input
  • {{ turn.output }} - the previous assistant response
When a loop is the last item in a JSON array, use {% if not loop.last %},{% endif %} after each iteration to prevent a trailing comma. When there’s content after the loop (like the final user message above), this pattern is not required.

Anthropic Claude Format

{
  "model": "claude-3-opus-20240229",
  "max_tokens": 1024,
  "messages": [
    {% for turn in past_turns %}
    {"role": "user", "content": "{{ turn.input }}"},
    {"role": "assistant", "content": "{{ turn.output }}"},
    {% endfor %}
    {"role": "user", "content": "{{ input.user_message }}"}
  ]
}

JSON Escaping

String values in the template context are automatically JSON-escaped before rendering. This means that test case inputs containing ", \, or newline characters produce valid JSON bodies without any extra work on your part. You still need to provide the surrounding double quotes in your template for string fields (e.g., "{{ input.field_name }}"), since the escaping only applies to the content, not the JSON structure. For example, if a test case input field contains:
She said "hello" and pressed Enter
The template engine escapes it to:
She said \"hello\" and pressed Enter
This ensures that the rendered request body is always valid JSON, even when inputs contain special characters.

Placeholder Toolbar

When editing an input template in the Galtea dashboard, a placeholder toolbar appears above the editor. It shows clickable pills grouped by category:
CategoryPlaceholders
Basic{{ input.user_message }}, {{ context.value }}
Historypast_turns loop, {{ turn.input }}, {{ turn.output }}
Session{{ session_id }}, {{ galtea_session_id }}
Inference{{ inference_result_id }}
Test{{ test_case_id }}, {{ test_id }}
Language{{ language_code }}, {{ language_name }}
Clicking a pill inserts the corresponding syntax at the cursor position in the editor.
The placeholder toolbar auto-generates pills from the available placeholders. If your test cases use custom input field names (e.g., query instead of user_message), you can type {{ input.query }} directly in the editor. The toolbar shows common defaults, but any field name from your test case input schema is valid.

Missing Fields

When a template references a field that does not exist in the test case, Nunjucks renders the undefined placeholder as an empty string. This can produce invalid JSON. For example, if {{ input.customer_id }} is referenced but the test case input does not have a customer_id field:
{
  "customer_id": "{{ input.customer_id }}",
  "message": "{{ input.user_message }}"
}
Renders to:
{
  "customer_id": "",
  "message": "What is the capital of France?"
}
When a missing field produces structurally invalid JSON (e.g., a numeric field rendering as empty), the endpoint typically rejects the malformed request (e.g., returns a 400 error), causing the inference result status to be marked as FAILED.
Ensure that all placeholders in your template correspond to fields that exist in your test case input and context schemas. Undefined fields silently render as empty strings.

Templates & Mapping

Full reference for Input Templates, Output Mapping, custom headers, and retry configuration.

Endpoint Connection Overview

What endpoint connections are and how to create one.

Test Cases

Understand the structure of test case inputs and context.

Direct Inferences Tutorial

Run evaluations from the dashboard using your endpoint connection.