Chat Prompt Configuration#
Chat prompts in Langfuse are structured as an ordered list of typed messages. Each message is either a content message (with a role and content string) or a placeholder message (a named slot for dynamically injected message sequences at compile time). The core type definitions and Zod schemas live in packages/shared/src/server/llm/types.ts.
Message Types#
ChatMessageType enum#
The ChatMessageType enum defines all message variants:
| Value | Use |
|---|---|
system, developer, user, assistant-text, assistant-tool-call, tool-result, model-text | Standard LLM roles |
public-api-created | Catch-all for messages ingested via the public API/SDK with arbitrary role strings |
placeholder | Named slot for message injection at compile time |
Each standard role has its own schema (e.g., SystemMessageSchema, UserMessageSchema); all require a matching type literal plus a content string.
ChatMessageSchema union#
ChatMessageSchema is a discriminated union covering the standard roles, plus a fallback branch that accepts {role: string, content: any} and tags the result as PublicAPICreated. PlaceholderMessage is intentionally excluded from this union; it is added separately via ChatMessageWithId.
Prompt-level schemas#
PromptChatMessageSchema is the union used when storing or validating a prompt's message list — it accepts either {role, content} or a PlaceholderMessage. PromptChatMessageListSchema is z.array(PromptChatMessageSchema) and is what PromptContentSchema branches on for chat prompts .
Placeholder Messages#
Schema and naming constraints#
{ type: "placeholder", name: string }
The name field must match /^[a-zA-Z][a-zA-Z0-9_]*$/ — i.e., start with an ASCII letter, followed by zero or more alphanumeric characters or underscores. No spaces, no leading digits, no Unicode beyond ASCII.
Note: this is more restrictive than the
VARIABLE_REGEXused for{{variable}}interpolation, which uses Unicode property escapes (\p{L},\p{N}) and allows non-ASCII letters. See stringChecks.ts.
Compile-time expansion#
extractPlaceholderNames() in compileChatMessages.ts filters an array of prompt messages for entries with type === "placeholder" and returns their names. This drives downstream injection of runtime message sequences into placeholder slots.
Variable Extraction and Collision Detection#
Prompt content uses mustache syntax ({{variable_name}}) for text interpolation. The shared extractVariables() function parses these with MUSTACHE_REGEX (/{{([^{}]*)}}+/g) and filters results through VARIABLE_REGEX.
Variable names and placeholder names must not overlap. Server-side, createPrompt.ts enforces this on every write:
extractChatVariableAndPlaceholderNames()collects variables from each message'scontentfield and placeholder names from the message list.- If any variable name appears in the placeholder list,
createPromptthrows anInvalidRequestErrorlisting the conflicting names.
Frontend Validation#
The UI form schema at web/src/features/prompts/components/NewPromptForm/validation.ts adds two refinements on the chatPrompt array :
- Every message with
type === "placeholder"must passPlaceholderMessageSchema.safeParse(). - Every non-placeholder message must have a non-empty
contentstring.
MCP Integration#
The MCP createChatPrompt tool (PR #13323) added placeholder message support via a two-schema design required by MCP client limitations with oneOf/anyOf in array items:
- Base schema: flat, permissive object with all fields optional (for MCP client display).
- Input schema: enforces the content-vs-placeholder contract using
.superRefine(), re-parsing withPromptChatMessageSchemabefore passing tocreatePromptAction. The variable-placeholder collision check runs at the action layer, same as all other entry points.
Key Source Files#
| File | Purpose |
|---|---|
packages/shared/src/server/llm/types.ts | All message schemas and enums (ChatMessageType, PlaceholderMessageSchema, PromptChatMessageSchema, etc.) |
packages/shared/src/utils/stringChecks.ts | VARIABLE_REGEX, MUSTACHE_REGEX, extractVariables() |
packages/shared/src/server/llm/compileChatMessages.ts | extractPlaceholderNames() |
web/src/features/prompts/server/actions/createPrompt.ts | Authoritative write path; collision detection |
web/src/features/prompts/components/NewPromptForm/validation.ts | Frontend Zod schema for new prompt form |