Implementation:Helicone Helicone MapperBuilder PathMapper
| Knowledge Sources | |
|---|---|
| Domains | LLM Observability, Schema Mapping, Response Normalization |
| Last Updated | 2026-02-14 00:00 GMT |
Overview
Concrete declarative bidirectional field mapping system for v2 mappers, provided by the llm-mapper/path-mapper module. Consists of the MapperBuilder fluent builder and the PathMapper runtime engine.
Description
MapperBuilder provides a fluent API for defining path mappings between an external provider format and the internal LLMRequestBody type. Each call to .map() or .mapWithTransform() registers a path pair. The .build() method produces a PathMapper instance that can convert objects in either direction using toInternal() and toExternal(). The PathMapper traverses objects using parsed dot-notation paths, auto-creating intermediate objects/arrays as needed, and applies optional transform functions for non-trivial conversions.
Usage
Use when building a new v2 provider mapper. Define all field correspondences with the builder, then call .build() to get a reusable PathMapper that converts request bodies in both directions.
Code Reference
Source Location
- Repository: Helicone
- Files:
packages/llm-mapper/path-mapper/builder.ts-- MapperBuilder class and type utilitiespackages/llm-mapper/path-mapper/core.ts-- PathMapper class with traversal logic
Signature (MapperBuilder)
export class MapperBuilder<ExternalType = any, InternalType = LLMRequestBody> {
constructor(name: string);
map<
ExternalPath extends string & PathsOf<ExternalType>,
InternalPath extends string & ValidInternalPaths
>(externalPath: ExternalPath, internalPath: InternalPath): this;
mapWithTransform<
ExternalPath extends string & PathsOf<ExternalType>,
InternalPath extends string & ValidInternalPaths,
T = any,
E = TypeAtPath<ExternalType, ExternalPath>
>(
externalPath: ExternalPath,
internalPath: InternalPath,
toInternal: (value: E, internal?: InternalType) => T,
toExternal: (value: T, external?: ExternalType) => E,
description?: string
): this;
build(): PathMapper<ExternalType, InternalType>;
}
Signature (PathMapper)
export class PathMapper<ExternalType, InternalType = LLMRequestBody> {
constructor(name: string, mappings: PathMapping[]);
// Convert internal to external format (convenience alias)
map(internal: InternalType): ExternalType;
// Convert external format to internal Helicone format
toInternal(external: ExternalType): InternalType;
// Convert internal Helicone format to external format
toExternal(internal: InternalType): ExternalType;
// Accessors
get mapperName(): string;
get pathPairs(): PathMapping[];
}
Import
import { MapperBuilder } from "@helicone-package/llm-mapper/path-mapper/builder";
import { PathMapper } from "@helicone-package/llm-mapper/path-mapper/core";
I/O Contract
Inputs (MapperBuilder.map)
| Name | Type | Required | Description |
|---|---|---|---|
| externalPath | string & PathsOf<ExternalType> |
Yes | Dot-notation path into the external (provider) object (e.g. "model", "stop_sequences", "output.message.content")
|
| internalPath | string & ValidInternalPaths |
Yes | Dot-notation path into the internal LLMRequestBody object (e.g. "model", "stop", "messages")
|
Inputs (MapperBuilder.mapWithTransform)
| Name | Type | Required | Description |
|---|---|---|---|
| externalPath | string & PathsOf<ExternalType> |
Yes | Dot-notation path into the external object |
| internalPath | string & ValidInternalPaths |
Yes | Dot-notation path into the internal object |
| toInternal | (value: E, internal?: InternalType) => T |
Yes | Transform function converting external value to internal format |
| toExternal | (value: T, external?: ExternalType) => E |
Yes | Transform function converting internal value back to external format |
| description | string |
No | Documentation string for this mapping |
Inputs (PathMapper.toInternal / toExternal)
| Name | Type | Required | Description |
|---|---|---|---|
| external / internal | ExternalType / InternalType |
Yes | The source object to transform |
Outputs
| Name | Type | Description |
|---|---|---|
| MapperBuilder.build() | PathMapper<ExternalType, InternalType> |
A configured PathMapper instance ready for bidirectional conversions |
| PathMapper.toInternal() | InternalType |
The converted internal (LLMRequestBody) object |
| PathMapper.toExternal() | ExternalType |
The converted external (provider-specific) object |
Type Utilities
The builder module exports several TypeScript utility types used for path validation:
| Type | Description |
|---|---|
PathsOf<T> |
Recursively generates all valid dot-notation path strings for type T, including array index notation |
TypeAtPath<T, P> |
Resolves the TypeScript type at a given path P within type T |
RecursiveKeyOf<TObj> |
Generates all recursive key paths for an object type |
ValidInternalPaths |
Union of all valid paths within LLMRequestBody, used to constrain internal path arguments
|
PathMapping |
Interface for a single mapping definition with optional transform and description |
Path Parsing
The PathMapper parses dot-notation path strings into structured segments:
// "users[0].name" parses to:
[
{ type: "property", name: "users" },
{ type: "array", name: "0", index: "0" },
{ type: "property", name: "name" }
]
The parser handles:
- Dots outside brackets as segment separators
- Bracket notation for array indices:
"items[0]" - Empty brackets for whole-array operations:
"items[]" - Nested bracket/dot combinations:
"choices[0].message.content"
Usage Examples
Basic Usage
import { MapperBuilder } from "@helicone-package/llm-mapper/path-mapper/builder";
// Define a mapper for a hypothetical provider
interface MyProviderBody {
model: string;
max_tokens: number;
stop_sequences: string[];
messages: Array<{ role: string; content: string }>;
}
const mapper = new MapperBuilder<MyProviderBody>("my-provider")
.map("model", "model")
.map("max_tokens", "max_tokens")
.mapWithTransform(
"stop_sequences",
"stop",
(ext) => ext, // toInternal: string[] -> string[]
(int) => int as string[], // toExternal: string[] -> string[]
"Stop sequences mapping"
)
.build();
// Convert external to internal
const internal = mapper.toInternal({
model: "my-model",
max_tokens: 1024,
stop_sequences: ["END"],
messages: [{ role: "user", content: "Hello" }],
});
// internal.model === "my-model"
// internal.max_tokens === 1024
// internal.stop === ["END"]
// Convert internal back to external
const external = mapper.toExternal(internal);
// external.model === "my-model"
// external.stop_sequences === ["END"]
With Complex Transforms
const mapper = new MapperBuilder<AnthropicBody>("anthropic")
.map("model", "model")
.map("max_tokens", "max_tokens")
.map("temperature", "temperature")
.mapWithTransform(
"messages",
"messages",
(anthropicMsgs) => anthropicMsgs.map(convertAnthropicToInternal),
(internalMsgs) => internalMsgs.map(convertInternalToAnthropic),
"Message format conversion"
)
.build();