Principle:Helicone Helicone Schema Mapping
| Knowledge Sources | |
|---|---|
| Domains | LLM Observability, Schema Mapping, Response Normalization |
| Last Updated | 2026-02-14 00:00 GMT |
Overview
Schema Mapping is the declarative, bidirectional field mapping system used by v2 mappers to transform between provider-specific (external) and Helicone-internal (LLMRequestBody) data formats using dot-notation paths.
Description
While the v1 mappers in Helicone use imperative code to extract and assign fields between provider formats and the internal LlmSchema, the v2 mapper system introduces a declarative approach. Instead of writing custom transformation functions for each provider, developers define a set of path mappings -- pairs of dot-notation strings that specify which field in the external format corresponds to which field in the internal LLMRequestBody type.
For example, the mapping ("model", "model") copies the model field directly, while ("max_tokens", "max_tokens") does the same for token limits. When fields need transformation (e.g., converting Anthropic's stop_sequences: string[] to the internal stop: string[]), a mapWithTransform call provides bidirectional transform functions.
The system consists of two core components:
- MapperBuilder -- a fluent builder that collects path mappings and produces a
PathMapperinstance - PathMapper -- the runtime engine that traverses objects using parsed dot-notation paths to copy and transform values in either direction
Usage
Use Schema Mapping when creating new v2 provider mappers or when you need bidirectional conversion between a provider's request format and Helicone's internal LLMRequestBody. It is particularly valuable for providers whose request schemas closely mirror the internal schema (minimal transforms needed) and for cases where bidirectional mapping is required (e.g., prompt playground sending requests back in provider format).
Theoretical Basis
Schema Mapping is built on several design principles:
Declarative Mapping
Rather than imperative field-by-field assignment, the system uses path declarations that describe what maps to what, not how to do it. This makes mappings self-documenting and easy to audit:
new MapperBuilder<AnthropicBody>("anthropic")
.map("model", "model")
.map("max_tokens", "max_tokens")
.mapWithTransform("stop_sequences", "stop", toIntFn, toExtFn)
.build()
Bidirectional Transforms
Every mapping is inherently bidirectional. The PathMapper can convert external to internal (toInternal) or internal to external (toExternal), using the same mapping definitions. Transform functions come in pairs (toInternal, toExternal) ensuring round-trip fidelity.
Dot-Notation Path Traversal
The PathMapper parses paths like "output.message.content" or "choices[0].message.role" into structured segments, then traverses nested objects accordingly. The path parser handles:
- Simple property access:
"model" - Nested property access:
"output.message.content" - Array index access:
"choices[0].message" - Empty bracket notation:
"items[]"for whole-array operations
Type-Safe Builder
The MapperBuilder uses TypeScript generic type parameters and utility types (PathsOf<T>, TypeAtPath<T, P>, ValidInternalPaths) to provide compile-time validation of path strings. When typed correctly, invalid paths produce TypeScript errors, catching mismatches before runtime.
Auto-Initialization
When setting values by path, the PathMapper automatically creates intermediate objects and arrays as needed. If the path "output.message.content" requires output and message to exist, they are created as empty objects. If the next segment is an array index, an empty array is created instead.