@sembl/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/schema/json-schema.ts","../src/schema/resolve-enum-sources.ts","../src/schema/registry.ts","../src/decorators.ts","../src/errors/coerce-error.ts","../src/errors/enum-resolution-error.ts","../src/coerce/prompt-builder.ts","../src/coerce/repair.ts","../src/coerce/provenance.ts","../src/coerce/validator.ts","../src/tracing/tracer.ts","../src/coerce/coerce.ts","../src/coerce/config.ts","../src/coerce/coercible.ts","../src/tracing/console-sink.ts"],"sourcesContent":["import type {\n RuntimeSchema,\n FieldDescriptor,\n FieldConstraints,\n FieldType,\n SchemaBundle,\n} from \"./types.js\";\nimport type { ResolvedEnums } from \"./enum-source.js\";\n\ntype JsonSchema = Record<string, unknown>;\n\n/**\n * Which flavour of JSON Schema to emit.\n *\n * - `\"openai-strict\"` — the subset OpenAI structured outputs accepts.\n * - `\"standard\"` — ordinary JSON Schema, for validators and other providers.\n */\nexport type JsonSchemaDialect = \"openai-strict\" | \"standard\";\n\n/**\n * Options for JSON Schema generation.\n */\nexport interface JsonSchemaOptions {\n /** Legal values for dynamic enum sources, from `resolveEnumSources` */\n resolvedEnums?: ResolvedEnums;\n /** Target dialect. Defaults to `\"openai-strict\"`. */\n dialect?: JsonSchemaDialect;\n}\n\n/**\n * Keys of FieldConstraints that map 1:1 onto JSON Schema keywords.\n *\n * These are emitted in the `\"standard\"` dialect only, and deliberately dropped\n * under `\"openai-strict\"`. OpenAI's structured outputs validate the schema up\n * front and reject the whole request on an unsupported keyword — errors read\n * like `'minLength' is not permitted` — so emitting one turns a soft\n * constraint into a hard 400. Reports on which of these the strict validator\n * accepts currently conflict: multiple 2026 tool integrations still strip all\n * of them, while OpenAI has announced incremental support for string lengths,\n * patterns, numeric ranges and array bounds. The primary documentation was\n * unreachable when this was written, so the conservative branch wins.\n *\n * Nothing is actually lost: the prompt states every constraint and the\n * validator enforces every constraint, so dropping them here costs only\n * schema-level enforcement. To loosen this, confirm against the current\n * structured-outputs docs (the \"Supported properties\" / unsupported-keyword\n * list) which keywords the strict validator accepts for the models in use,\n * then move those into the strict branch.\n */\nconst CONSTRAINT_KEYWORDS = [\n \"maxLength\",\n \"minLength\",\n \"minimum\",\n \"maximum\",\n \"minItems\",\n \"maxItems\",\n \"pattern\",\n] as const satisfies readonly (keyof FieldConstraints)[];\n\n/** The subset of CONSTRAINT_KEYWORDS that bounds an array rather than a value. */\nconst ARRAY_KEYWORDS: readonly string[] = [\"minItems\", \"maxItems\"];\n\n/**\n * Translate FieldConstraints into JSON Schema keywords for the given dialect.\n */\nfunction constraintsToJsonSchema(\n constraints: FieldConstraints | undefined,\n dialect: JsonSchemaDialect,\n): JsonSchema {\n if (!constraints || dialect === \"openai-strict\") {\n return {};\n }\n\n const out: JsonSchema = {};\n for (const keyword of CONSTRAINT_KEYWORDS) {\n const value = constraints[keyword];\n if (value !== undefined) {\n out[keyword] = value;\n }\n }\n return out;\n}\n\n/**\n * Convert a FieldType to a JSON Schema type definition.\n *\n * `visiting` holds the schema ids on the current inlining path so a bundle\n * that references itself terminates instead of recursing forever.\n */\nfunction fieldTypeToJsonSchema(\n fieldType: FieldType,\n bundle: SchemaBundle | undefined,\n options: JsonSchemaOptions,\n visiting: Set<string>,\n): JsonSchema {\n switch (fieldType.kind) {\n case \"string\":\n return { type: \"string\" };\n case \"number\":\n return { type: \"number\" };\n case \"boolean\":\n return { type: \"boolean\" };\n case \"array\":\n return {\n type: \"array\",\n items: fieldTypeToJsonSchema(fieldType.items, bundle, options, visiting),\n };\n case \"enum\":\n return { type: \"string\", enum: fieldType.values };\n case \"dynamicEnum\": {\n const values = options.resolvedEnums?.[fieldType.sourceId];\n // An unresolved source can only be expressed as a free-form string.\n return values && values.length > 0\n ? { type: \"string\", enum: [...values] }\n : { type: \"string\" };\n }\n case \"object\": {\n // If we have a bundle and can find the nested schema, inline it\n const nested = bundle?.schemas[fieldType.nestedSchemaId];\n if (nested && !visiting.has(nested.id)) {\n return buildObjectSchema(nested, bundle, options, visiting);\n }\n return { type: \"object\", additionalProperties: false };\n }\n }\n}\n\n/**\n * Convert a FieldDescriptor to a JSON Schema property definition.\n */\nfunction fieldToJsonSchema(\n field: FieldDescriptor,\n bundle: SchemaBundle | undefined,\n options: JsonSchemaOptions,\n visiting: Set<string>,\n): JsonSchema {\n const base = fieldTypeToJsonSchema(field.type, bundle, options, visiting);\n const dialect = options.dialect ?? \"openai-strict\";\n const constraints = constraintsToJsonSchema(field.constraints, dialect);\n\n if (base.type !== \"array\") {\n return { ...base, ...constraints, description: field.description };\n }\n\n // On an array field only minItems/maxItems bound the array; the string and\n // number bounds describe each element, so they move onto `items`.\n const arrayLevel: JsonSchema = {};\n const itemLevel: JsonSchema = {};\n for (const [keyword, value] of Object.entries(constraints)) {\n (ARRAY_KEYWORDS.includes(keyword) ? arrayLevel : itemLevel)[keyword] = value;\n }\n\n return {\n ...base,\n ...arrayLevel,\n items: { ...(base.items as JsonSchema), ...itemLevel },\n description: field.description,\n };\n}\n\n/**\n * Build the object schema for a RuntimeSchema, tracking the inlining path.\n */\nfunction buildObjectSchema(\n schema: RuntimeSchema,\n bundle: SchemaBundle | undefined,\n options: JsonSchemaOptions,\n visiting: Set<string>,\n): JsonSchema {\n const properties: Record<string, JsonSchema> = {};\n const required: string[] = [];\n\n const dialect = options.dialect ?? \"openai-strict\";\n\n visiting.add(schema.id);\n for (const field of schema.fields) {\n const fieldSchema = fieldToJsonSchema(field, bundle, options, visiting);\n\n if (dialect === \"openai-strict\") {\n // Strict mode admits no absent property, so an optional field is\n // expressed as a nullable one and every name goes in `required`.\n properties[field.name] = field.required\n ? fieldSchema\n : { anyOf: [fieldSchema, { type: \"null\" }] };\n required.push(field.name);\n } else {\n properties[field.name] = fieldSchema;\n if (field.required) {\n required.push(field.name);\n }\n }\n }\n visiting.delete(schema.id);\n\n return {\n type: \"object\",\n description: schema.description,\n properties,\n required,\n additionalProperties: false,\n };\n}\n\n/**\n * Convert a RuntimeSchema to a JSON Schema object.\n *\n * Under `\"openai-strict\"`, every property is listed in `required` and an\n * optional field becomes `anyOf: [T, null]`, as structured outputs demand.\n * Under `\"standard\"`, only genuinely required fields are listed and optional\n * ones are simply absent — which is what keeps an unmentioned field\n * distinguishable from one the model explicitly nulled.\n *\n * Both dialects inline nested schemas (no `$ref`) and set\n * `additionalProperties: false`. Dynamic enum fields become a string `enum`\n * when their source resolved, and a plain string otherwise. FieldConstraints\n * are emitted only in `\"standard\"` — see {@link CONSTRAINT_KEYWORDS}.\n */\nexport function runtimeSchemaToJsonSchema(\n schema: RuntimeSchema,\n bundle?: SchemaBundle,\n options: JsonSchemaOptions = {},\n): JsonSchema {\n return buildObjectSchema(schema, bundle, options, new Set());\n}\n\n/**\n * Wrap a RuntimeSchema as a top-level JSON Schema suitable for\n * OpenAI's response_format.json_schema.schema parameter.\n */\nexport function toOpenAIJsonSchema(\n schema: RuntimeSchema,\n bundle?: SchemaBundle,\n options: Omit<JsonSchemaOptions, \"dialect\"> = {},\n): JsonSchema {\n return {\n name: schema.id,\n strict: true,\n schema: runtimeSchemaToJsonSchema(schema, bundle, {\n ...options,\n dialect: \"openai-strict\",\n }),\n };\n}\n","import type { FieldType, RuntimeSchema, SchemaBundle } from \"./types.js\";\nimport type { EnumResolver, ResolvedEnums } from \"./enum-source.js\";\n\n/**\n * An enum source that could not be turned into a usable set of legal values.\n */\nexport interface EnumSourceFailure {\n /** The source id that failed */\n sourceId: string;\n /** Why it failed: the resolver threw, or it produced no values */\n reason: \"threw\" | \"empty\";\n /** The thrown value, when `reason` is \"threw\" */\n cause?: unknown;\n /**\n * Whether a required field depends on this source. A field counts as\n * required only if every object on the path to it is also required — an\n * unreachable field cannot make a coercion fail.\n */\n required: boolean;\n /** Field paths that reference this source, for error messages */\n paths: string[];\n}\n\n/**\n * The outcome of resolving every enum source a schema reaches.\n */\nexport interface EnumResolution {\n /** Legal values for each source that resolved successfully */\n enums: ResolvedEnums;\n /** Sources that threw or produced nothing */\n failures: EnumSourceFailure[];\n}\n\n/** How a single enum source is reached from the root schema. */\nexport interface EnumSourceUsage {\n /** Whether the source is reachable through an unbroken chain of required fields */\n required: boolean;\n /** Field paths that reference this source */\n paths: string[];\n}\n\n/**\n * Walk a FieldType, recording every dynamic enum source it reaches.\n *\n * `visiting` is the stack of schema ids on the current path rather than a set\n * of everything seen, so a schema referenced twice in different branches is\n * still walked twice while a schema that references itself terminates.\n */\nfunction collectFromType(\n type: FieldType,\n path: string,\n required: boolean,\n bundle: SchemaBundle | undefined,\n visiting: Set<string>,\n usages: Map<string, EnumSourceUsage>,\n): void {\n switch (type.kind) {\n case \"dynamicEnum\": {\n const existing = usages.get(type.sourceId);\n if (existing) {\n // A source is required-critical if *any* of its uses is required.\n existing.required ||= required;\n existing.paths.push(path);\n } else {\n usages.set(type.sourceId, { required, paths: [path] });\n }\n break;\n }\n case \"array\":\n collectFromType(type.items, `${path}[]`, required, bundle, visiting, usages);\n break;\n case \"object\": {\n const nested = bundle?.schemas[type.nestedSchemaId];\n if (nested && !visiting.has(nested.id)) {\n collectFromSchema(nested, path, required, bundle, visiting, usages);\n }\n break;\n }\n default:\n break;\n }\n}\n\n/**\n * Walk a schema's fields, recording every dynamic enum source they reach.\n */\nfunction collectFromSchema(\n schema: RuntimeSchema,\n parentPath: string,\n parentRequired: boolean,\n bundle: SchemaBundle | undefined,\n visiting: Set<string>,\n usages: Map<string, EnumSourceUsage>,\n): void {\n visiting.add(schema.id);\n for (const field of schema.fields) {\n const path = parentPath ? `${parentPath}.${field.name}` : field.name;\n collectFromType(\n field.type,\n path,\n parentRequired && field.required,\n bundle,\n visiting,\n usages,\n );\n }\n visiting.delete(schema.id);\n}\n\n/**\n * Collect the distinct dynamic enum source ids a schema reaches, directly or\n * through its bundle, along with whether each is reachable through a chain of\n * required fields.\n */\nexport function collectEnumSources(\n schema: RuntimeSchema,\n bundle?: SchemaBundle,\n): Map<string, EnumSourceUsage> {\n const usages = new Map<string, EnumSourceUsage>();\n collectFromSchema(schema, \"\", true, bundle, new Set(), usages);\n return usages;\n}\n\n/**\n * Resolve every dynamic enum source a schema reaches, calling `resolver` once\n * per distinct source id and awaiting all of them concurrently.\n *\n * Resolution never throws on the caller's behalf. A source whose resolver\n * throws, or which yields no values, is reported in `failures` and left out of\n * `enums` — downstream that means the field widens to a free-form string.\n * Widening a *required* field is a silent correctness hole, so callers are\n * expected to treat a failure with `required: true` as fatal; `coerce` and\n * `partialCoerce` do exactly that.\n */\nexport async function resolveEnumSources(\n schema: RuntimeSchema,\n resolver: EnumResolver,\n bundle?: SchemaBundle,\n): Promise<EnumResolution> {\n const usages = collectEnumSources(schema, bundle);\n\n const enums: Record<string, readonly string[]> = {};\n const failures: EnumSourceFailure[] = [];\n\n await Promise.all(\n [...usages].map(async ([sourceId, usage]) => {\n try {\n const values = await resolver(sourceId);\n if (!values || values.length === 0) {\n failures.push({ sourceId, reason: \"empty\", ...usage });\n return;\n }\n enums[sourceId] = values;\n } catch (cause) {\n failures.push({ sourceId, reason: \"threw\", cause, ...usage });\n }\n }),\n );\n\n // Map iteration order is insertion order, but Promise.all settles in\n // completion order — sort so failures are reported deterministically.\n failures.sort((a, b) => a.sourceId.localeCompare(b.sourceId));\n\n return { enums, failures };\n}\n","import type { RuntimeSchema, SchemaBundle } from \"./types.js\";\n\n/**\n * Registry for looking up compiled RuntimeSchemas by ID.\n */\nexport class SchemaRegistry {\n private schemas = new Map<string, RuntimeSchema>();\n\n /**\n * Register a single schema.\n */\n register(schema: RuntimeSchema): void {\n this.schemas.set(schema.id, schema);\n }\n\n /**\n * Register all schemas from a bundle.\n */\n registerBundle(bundle: SchemaBundle): void {\n for (const schema of Object.values(bundle.schemas)) {\n this.register(schema);\n }\n }\n\n /**\n * Look up a schema by ID.\n */\n get(id: string): RuntimeSchema | undefined {\n return this.schemas.get(id);\n }\n\n /**\n * Get a schema by ID, throwing if not found.\n */\n require(id: string): RuntimeSchema {\n const schema = this.schemas.get(id);\n if (!schema) {\n throw new Error(`Schema \"${id}\" not found in registry`);\n }\n return schema;\n }\n\n /**\n * Get a SchemaBundle of all registered schemas.\n */\n toBundle(): SchemaBundle {\n const schemas: Record<string, RuntimeSchema> = {};\n for (const [id, schema] of this.schemas) {\n schemas[id] = schema;\n }\n return { schemas };\n }\n\n /**\n * Get all registered schema IDs.\n */\n ids(): string[] {\n return [...this.schemas.keys()];\n }\n}\n","import type { FieldConstraints } from \"./schema/types.js\";\n\n/**\n * Class decorator marking a schema class with a semantic description.\n * No-op at runtime — parsed by the compiler from source AST.\n */\nexport function Schema(description: string): ClassDecorator {\n return function (target) {\n return target;\n };\n}\n\n/**\n * Property decorator providing a field-level semantic description.\n * No-op at runtime — parsed by the compiler from source AST.\n */\nexport function Describe(description: string): PropertyDecorator {\n return function (_target, _propertyKey) {};\n}\n\n/**\n * Property decorator bounding a field's legal values — lengths, numeric\n * ranges, array sizes, a pattern.\n *\n * Takes an object literal of compile-time constants; the compiler reads it\n * from source, so computed expressions are not supported.\n *\n * ```ts\n * @Describe(\"Display name for the listing.\")\n * @Constrain({ maxLength: 40 })\n * name!: string;\n * ```\n *\n * No-op at runtime — parsed by the compiler from source AST.\n */\nexport function Constrain(constraints: FieldConstraints): PropertyDecorator {\n return function (_target, _propertyKey) {};\n}\n\n/**\n * Property decorator declaring that a field's legal values come from a named\n * source resolved at coercion time rather than from the source tree — a CMS\n * taxonomy, a database enum table.\n *\n * Applies to a string field or to the element type of a string array. The\n * caller supplies an `EnumResolver` that maps `sourceId` to the legal values.\n *\n * ```ts\n * @Describe(\"Amenities the property offers.\")\n * @ValuesFrom(\"amenities\")\n * amenities!: string[];\n * ```\n *\n * No-op at runtime — parsed by the compiler from source AST.\n */\nexport function ValuesFrom(sourceId: string): PropertyDecorator {\n return function (_target, _propertyKey) {};\n}\n","/**\n * Describes a single validation issue on a field.\n */\nexport interface FieldValidationIssue {\n /** Dot-separated path to the field, e.g. \"address.city\" */\n path: string;\n /** What went wrong */\n message: string;\n /** The value that was received, if any */\n received?: unknown;\n}\n\n/**\n * Error thrown when coercion validation fails.\n */\nexport class CoerceError extends Error {\n public readonly issues: FieldValidationIssue[];\n\n constructor(issues: FieldValidationIssue[]) {\n const summary = issues.map((i) => ` ${i.path}: ${i.message}`).join(\"\\n\");\n super(`Coercion validation failed:\\n${summary}`);\n this.name = \"CoerceError\";\n this.issues = issues;\n }\n}\n","import type { EnumSourceFailure } from \"../schema/resolve-enum-sources.js\";\n\n/**\n * Error thrown when an enum source backing a required field could not be\n * resolved.\n *\n * Falling back to a free-form string here would let the model invent values\n * that pass coercion and fail downstream, so a required field with a dead\n * taxonomy is a hard failure rather than a widening.\n */\nexport class EnumResolutionError extends Error {\n public readonly failures: EnumSourceFailure[];\n\n constructor(failures: EnumSourceFailure[]) {\n const summary = failures\n .map((f) => {\n const why =\n f.reason === \"empty\"\n ? \"resolved to no values\"\n : `threw: ${f.cause instanceof Error ? f.cause.message : String(f.cause)}`;\n return ` ${f.sourceId} (${f.paths.join(\", \")}): ${why}`;\n })\n .join(\"\\n\");\n super(`Enum source resolution failed for required fields:\\n${summary}`);\n this.name = \"EnumResolutionError\";\n this.failures = failures;\n }\n}\n","import type {\n RuntimeSchema,\n FieldDescriptor,\n FieldConstraints,\n SchemaBundle,\n} from \"../schema/types.js\";\nimport type { ResolvedEnums } from \"../schema/enum-source.js\";\n\n/**\n * Options for prompt generation.\n */\nexport interface PromptOptions {\n /** Legal values for dynamic enum sources, from `resolveEnumSources` */\n resolvedEnums?: ResolvedEnums;\n}\n\n/**\n * Render FieldConstraints as instruction phrases a model will act on.\n * Returns an empty array when the field is unconstrained.\n */\nfunction describeConstraints(constraints: FieldConstraints | undefined): string[] {\n if (!constraints) {\n return [];\n }\n\n const phrases: string[] = [];\n const { minLength, maxLength, minimum, maximum, minItems, maxItems, pattern } =\n constraints;\n\n if (minLength !== undefined && maxLength !== undefined) {\n phrases.push(`between ${minLength} and ${maxLength} characters`);\n } else if (maxLength !== undefined) {\n phrases.push(`at most ${maxLength} characters`);\n } else if (minLength !== undefined) {\n phrases.push(`at least ${minLength} characters`);\n }\n\n if (minimum !== undefined && maximum !== undefined) {\n phrases.push(`between ${minimum} and ${maximum}`);\n } else if (minimum !== undefined) {\n phrases.push(`at least ${minimum}`);\n } else if (maximum !== undefined) {\n phrases.push(`at most ${maximum}`);\n }\n\n if (minItems !== undefined && maxItems !== undefined) {\n phrases.push(`between ${minItems} and ${maxItems} entries`);\n } else if (maxItems !== undefined) {\n phrases.push(`at most ${maxItems} entries`);\n } else if (minItems !== undefined) {\n phrases.push(`at least ${minItems} entries`);\n }\n\n if (pattern !== undefined) {\n phrases.push(`matching the pattern /${pattern}/`);\n }\n\n return phrases;\n}\n\n/**\n * Describe a dynamic enum field's allowed values.\n *\n * Deliberately a pointer rather than the values themselves. A CMS taxonomy can\n * run to several hundred slugs, and every one of them is already in the JSON\n * Schema the model receives on the same request — repeating them here would\n * roughly double the input tokens of every call to restate what the schema\n * already enforces. Naming the source and the count still tells the model the\n * field is closed-vocabulary and that guessing is wrong, which is the part the\n * schema alone does not communicate. This also matches how static `enum`\n * fields are already handled: the prompt carries semantics, the schema carries\n * the legal values.\n */\nfunction describeDynamicEnum(\n sourceId: string,\n resolvedEnums: ResolvedEnums | undefined,\n): string | undefined {\n const values = resolvedEnums?.[sourceId];\n if (!values || values.length === 0) {\n // Unresolved source — the field is a free-form string, nothing to say.\n return undefined;\n }\n return `exactly one of the ${values.length} allowed \"${sourceId}\" values enumerated in the JSON schema for this field (never invent a value)`;\n}\n\n/**\n * Build a semantic context block for a field, including nested schema context.\n *\n * `visiting` holds the schema ids on the current path so a bundle that\n * references itself terminates instead of recursing forever.\n */\nfunction buildFieldContext(\n field: FieldDescriptor,\n parentPath: string,\n bundle: SchemaBundle | undefined,\n depth: number,\n options: PromptOptions,\n visiting: Set<string>,\n): string[] {\n const lines: string[] = [];\n const indent = \" \".repeat(depth);\n const fieldPath = parentPath ? `${parentPath}.${field.name}` : field.name;\n\n lines.push(\n `${indent}- ${fieldPath} (${field.required ? \"required\" : \"optional\"}): ${field.description}`,\n );\n\n const rules = describeConstraints(field.constraints);\n\n const dynamicSourceId =\n field.type.kind === \"dynamicEnum\"\n ? field.type.sourceId\n : field.type.kind === \"array\" && field.type.items.kind === \"dynamicEnum\"\n ? field.type.items.sourceId\n : undefined;\n if (dynamicSourceId) {\n const allowed = describeDynamicEnum(dynamicSourceId, options.resolvedEnums);\n if (allowed) {\n rules.push(allowed);\n }\n }\n\n if (rules.length > 0) {\n lines.push(`${indent} Limits: ${rules.join(\"; \")}.`);\n }\n\n // If this is a nested object type, include nested schema context\n if (field.type.kind === \"object\" && bundle) {\n const nested = bundle.schemas[field.type.nestedSchemaId];\n if (nested && !visiting.has(nested.id)) {\n visiting.add(nested.id);\n lines.push(`${indent} [${nested.id}: ${nested.description}]`);\n for (const nestedField of nested.fields) {\n lines.push(\n ...buildFieldContext(\n nestedField,\n fieldPath,\n bundle,\n depth + 1,\n options,\n visiting,\n ),\n );\n }\n visiting.delete(nested.id);\n }\n }\n\n // If this is an array of objects, include item schema context\n if (field.type.kind === \"array\" && field.type.items.kind === \"object\" && bundle) {\n const nested = bundle.schemas[field.type.items.nestedSchemaId];\n if (nested && !visiting.has(nested.id)) {\n visiting.add(nested.id);\n lines.push(`${indent} [Array of ${nested.id}: ${nested.description}]`);\n for (const nestedField of nested.fields) {\n lines.push(\n ...buildFieldContext(\n nestedField,\n `${fieldPath}[]`,\n bundle,\n depth + 1,\n options,\n visiting,\n ),\n );\n }\n visiting.delete(nested.id);\n }\n }\n\n return lines;\n}\n\n/**\n * Build a system prompt that provides semantic context for the target schema.\n * This assembles the semantic hierarchy so the LLM understands the meaning\n * of each field in context.\n */\nexport function buildPrompt(\n schema: RuntimeSchema,\n bundle?: SchemaBundle,\n options: PromptOptions = {},\n): string {\n const lines: string[] = [\n \"You are a semantic coercion engine. Your task is to extract structured data from the user's input.\",\n \"\",\n `Target schema: ${schema.id}`,\n `Description: ${schema.description}`,\n \"\",\n \"Fields:\",\n ];\n\n const visiting = new Set<string>([schema.id]);\n for (const field of schema.fields) {\n lines.push(...buildFieldContext(field, \"\", bundle, 0, options, visiting));\n }\n\n lines.push(\"\");\n lines.push(\"Instructions:\");\n lines.push(\"- Extract values from the user's input that match the schema fields.\");\n lines.push(\"- Use null for optional fields that cannot be determined from the input.\");\n lines.push(\"- Required fields must always have a valid, non-null value.\");\n lines.push(\"- Interpret the user's input semantically — infer meaning, don't just pattern match.\");\n lines.push(\"- Respect every stated limit exactly; truncate or drop lower-priority content to stay within it.\");\n lines.push(\"- Return only the structured JSON output matching the schema.\");\n\n return lines.join(\"\\n\");\n}\n","import type { FieldValidationIssue } from \"../errors/coerce-error.js\";\n\n/** Longest rendering of a rejected value before it is elided. */\nconst MAX_RECEIVED_LENGTH = 200;\n\nfunction renderReceived(received: unknown): string {\n if (received === undefined) {\n return \"(missing)\";\n }\n const text = JSON.stringify(received) ?? String(received);\n return text.length > MAX_RECEIVED_LENGTH\n ? `${text.slice(0, MAX_RECEIVED_LENGTH)}… (truncated)`\n : text;\n}\n\n/**\n * Build the input for a repair attempt: the original input, the output that\n * was rejected, and what was wrong with it.\n *\n * The `Provider` interface is single-turn, so the correction has to travel as\n * user text rather than as a real assistant turn. In practice that reads to\n * the model the same way, and it keeps repair working on every provider\n * without widening the provider contract. Exported so a caller who wants\n * different wording can build their own and call the provider directly.\n */\nexport function buildRepairInput(\n originalInput: string,\n rejected: Record<string, unknown>,\n issues: FieldValidationIssue[],\n): string {\n const lines = [\n originalInput,\n \"\",\n \"---\",\n \"\",\n \"A previous attempt at this extraction produced:\",\n \"\",\n JSON.stringify(rejected, null, 2),\n \"\",\n \"It was rejected because:\",\n \"\",\n ];\n\n for (const issue of issues) {\n lines.push(`- ${issue.path}: ${issue.message} (received: ${renderReceived(issue.received)})`);\n }\n\n lines.push(\n \"\",\n \"Return a corrected object addressing every point above. Keep the values \" +\n \"that were already right — only the listed fields are wrong. If the \" +\n \"input genuinely does not support a value, leave the field out rather \" +\n \"than inventing one.\",\n );\n\n return lines.join(\"\\n\");\n}\n","import type {\n FieldDescriptor,\n RuntimeSchema,\n SchemaBundle,\n} from \"../schema/types.js\";\n\n/**\n * How well the input supported a value.\n *\n * A three-level scale rather than a number: models are poorly calibrated at\n * producing a 0–1 score, and a review UI only ever needs to decide whether to\n * flag a field for a human anyway.\n */\nexport type FieldConfidence = \"high\" | \"medium\" | \"low\";\n\n/** Where a coerced field's value came from. */\nexport interface FieldProvenance {\n /** How well the input supported this value. */\n confidence: FieldConfidence;\n /**\n * The span of input the value was read from, quoted. Absent when the value\n * was inferred rather than read — which is itself the signal worth showing.\n */\n evidence?: string;\n}\n\n/** A coercion result paired with per-field provenance. */\nexport interface ProvenanceResult<T> {\n /** The coerced data, in the shape of the target schema. */\n data: T;\n /** Provenance for each top-level field the model returned, keyed by name. */\n provenance: Record<string, FieldProvenance>;\n}\n\n/** Suffix marking the wrapper schema built around a target schema. */\nconst WRAPPER_SUFFIX = \"__WithProvenance\";\n\n/** Suffix marking the per-field annotation schema. */\nconst ANNOTATION_SUFFIX = \"__Annotated\";\n\nconst CONFIDENCE_VALUES: FieldConfidence[] = [\"high\", \"medium\", \"low\"];\n\n/**\n * Extra prompt guidance for a provenance run.\n *\n * The JSON Schema already forces the shape; what it cannot convey is how to\n * judge confidence, which is the whole point of asking.\n */\nexport const PROVENANCE_INSTRUCTIONS = [\n \"\",\n \"Provenance:\",\n \"- Every field is wrapped as an object: put the extracted value in `value`.\",\n \"- Set `confidence` to how well the input supports that value:\",\n ' \"high\" — stated outright in the input;',\n ' \"medium\" — strongly implied, but not stated;',\n ' \"low\" — a guess from weak or indirect signals.',\n \"- Set `evidence` to the shortest quote from the input the value came from.\",\n \" Leave `evidence` out when you inferred the value rather than reading it —\",\n \" do not quote text that does not actually contain it.\",\n \"- Judge each field on its own. A confident value next to a guessed one is\",\n \" normal, and marking the guess honestly is more useful than looking sure.\",\n].join(\"\\n\");\n\n/**\n * Build the annotation schema wrapping one field's value.\n */\nfunction annotationSchema(\n parentId: string,\n field: FieldDescriptor,\n): RuntimeSchema {\n const valueField: FieldDescriptor = {\n name: \"value\",\n description: field.description,\n type: field.type,\n required: true,\n ...(field.constraints !== undefined ? { constraints: field.constraints } : {}),\n };\n\n return {\n id: `${parentId}__${field.name}${ANNOTATION_SUFFIX}`,\n description: `The extracted value for \"${field.name}\", with where it came from.`,\n fields: [\n valueField,\n {\n name: \"confidence\",\n description: \"How well the input supported this value.\",\n type: { kind: \"enum\", values: [...CONFIDENCE_VALUES] },\n required: true,\n },\n {\n name: \"evidence\",\n description:\n \"The shortest quote from the input this value was read from. Omit when the value was inferred rather than read.\",\n type: { kind: \"string\" },\n required: false,\n },\n ],\n };\n}\n\n/**\n * Derive the schema to actually request when provenance is wanted: the same\n * fields, each wrapped in `{ value, confidence, evidence }`.\n *\n * Only top-level fields are annotated. A nested object keeps its ordinary\n * shape inside `value`, so provenance is reported for the object as a whole\n * rather than per leaf — annotating every leaf multiplies both the schema and\n * the output for detail a review UI rarely acts on.\n *\n * Returns a bundle carrying the wrapper, the per-field annotation schemas, and\n * everything the original bundle held, so nested types still inline.\n */\nexport function toProvenanceSchema(\n schema: RuntimeSchema,\n bundle?: SchemaBundle,\n): { schema: RuntimeSchema; bundle: SchemaBundle } {\n const schemas: Record<string, RuntimeSchema> = { ...(bundle?.schemas ?? {}) };\n const fields: FieldDescriptor[] = [];\n\n for (const field of schema.fields) {\n const annotation = annotationSchema(schema.id, field);\n schemas[annotation.id] = annotation;\n fields.push({\n name: field.name,\n description: field.description,\n type: { kind: \"object\", nestedSchemaId: annotation.id },\n required: field.required,\n });\n }\n\n const wrapper: RuntimeSchema = {\n id: `${schema.id}${WRAPPER_SUFFIX}`,\n description: schema.description,\n fields,\n };\n schemas[wrapper.id] = wrapper;\n\n return { schema: wrapper, bundle: { schemas } };\n}\n\nfunction isConfidence(value: unknown): value is FieldConfidence {\n return CONFIDENCE_VALUES.includes(value as FieldConfidence);\n}\n\n/**\n * Split a provenance-shaped response back into plain data and per-field\n * provenance.\n *\n * A field the model returned unwrapped — or wrapped without a usable\n * `confidence` — still yields its value; the provenance is simply not\n * recorded. Losing an annotation is not a reason to lose the extraction, and\n * the missing key is visible to the caller.\n */\nexport function splitProvenance(\n response: Record<string, unknown>,\n schema: RuntimeSchema,\n): { data: Record<string, unknown>; provenance: Record<string, FieldProvenance> } {\n const data: Record<string, unknown> = {};\n const provenance: Record<string, FieldProvenance> = {};\n\n for (const field of schema.fields) {\n const annotated = response[field.name];\n if (annotated === undefined || annotated === null) {\n data[field.name] = annotated ?? null;\n continue;\n }\n\n if (typeof annotated !== \"object\" || Array.isArray(annotated) || !(\"value\" in annotated)) {\n data[field.name] = annotated;\n continue;\n }\n\n const record = annotated as Record<string, unknown>;\n data[field.name] = record.value ?? null;\n\n if (isConfidence(record.confidence)) {\n const evidence = record.evidence;\n provenance[field.name] = {\n confidence: record.confidence,\n ...(typeof evidence === \"string\" && evidence.length > 0 ? { evidence } : {}),\n };\n }\n }\n\n return { data, provenance };\n}\n","import type {\n RuntimeSchema,\n FieldDescriptor,\n FieldConstraints,\n FieldType,\n SchemaBundle,\n} from \"../schema/types.js\";\nimport type { ResolvedEnums } from \"../schema/enum-source.js\";\nimport type { FieldValidationIssue } from \"../errors/coerce-error.js\";\n\n/**\n * Options shared by both validation modes.\n */\nexport interface ValidationOptions {\n /** Legal values for dynamic enum sources, from `resolveEnumSources` */\n resolvedEnums?: ResolvedEnums;\n}\n\n/** How many allowed values to name before truncating an enum error message. */\nconst MAX_LISTED_VALUES = 10;\n\n/**\n * Render an allowed-value list for an error message without pasting a\n * several-hundred-entry CMS taxonomy into it.\n */\nfunction summarizeValues(values: readonly string[]): string {\n if (values.length <= MAX_LISTED_VALUES) {\n return values.join(\", \");\n }\n const shown = values.slice(0, MAX_LISTED_VALUES).join(\", \");\n return `${shown}, … (+${values.length - MAX_LISTED_VALUES} more)`;\n}\n\n/** \"1 entry\" / \"3 entries\" — limits read as instructions, so they should scan. */\nfunction entries(count: number): string {\n return `${count} ${count === 1 ? \"entry\" : \"entries\"}`;\n}\n\n/**\n * Check a single value against the constraints that apply to its runtime type.\n *\n * Array-level bounds are checked against the array; string and number bounds\n * are checked against each element, so a `string[]` field can carry both.\n */\nfunction validateConstraints(\n value: unknown,\n constraints: FieldConstraints,\n path: string,\n issues: FieldValidationIssue[],\n): void {\n const { minLength, maxLength, minimum, maximum, minItems, maxItems, pattern } =\n constraints;\n\n if (Array.isArray(value)) {\n if (minItems !== undefined && value.length < minItems) {\n issues.push({\n path,\n message: `Expected at least ${entries(minItems)}, got ${value.length}`,\n received: value,\n });\n }\n if (maxItems !== undefined && value.length > maxItems) {\n issues.push({\n path,\n message: `Expected at most ${entries(maxItems)}, got ${value.length}`,\n received: value,\n });\n }\n // Element bounds only — the array's own bounds were just checked.\n const { minItems: _min, maxItems: _max, ...itemConstraints } = constraints;\n for (let i = 0; i < value.length; i++) {\n validateConstraints(value[i], itemConstraints, `${path}[${i}]`, issues);\n }\n return;\n }\n\n if (typeof value === \"string\") {\n if (minLength !== undefined && value.length < minLength) {\n issues.push({\n path,\n message: `Expected at least ${minLength} characters, got ${value.length}`,\n received: value,\n });\n }\n if (maxLength !== undefined && value.length > maxLength) {\n issues.push({\n path,\n message: `Expected at most ${maxLength} characters, got ${value.length}`,\n received: value,\n });\n }\n if (pattern !== undefined && !new RegExp(pattern).test(value)) {\n issues.push({\n path,\n message: `Expected a value matching /${pattern}/, got ${JSON.stringify(value)}`,\n received: value,\n });\n }\n return;\n }\n\n if (typeof value === \"number\") {\n if (minimum !== undefined && value < minimum) {\n issues.push({\n path,\n message: `Expected a value >= ${minimum}, got ${value}`,\n received: value,\n });\n }\n if (maximum !== undefined && value > maximum) {\n issues.push({\n path,\n message: `Expected a value <= ${maximum}, got ${value}`,\n received: value,\n });\n }\n }\n}\n\n/**\n * Validate a value against a FieldType.\n * Returns true if the value matches the expected type.\n */\nfunction validateType(\n value: unknown,\n fieldType: FieldType,\n path: string,\n bundle: SchemaBundle | undefined,\n options: ValidationOptions,\n issues: FieldValidationIssue[],\n): void {\n if (value === null || value === undefined) {\n return; // Null/undefined handled at field level\n }\n\n switch (fieldType.kind) {\n case \"string\":\n if (typeof value !== \"string\") {\n issues.push({\n path,\n message: `Expected string, got ${typeof value}`,\n received: value,\n });\n }\n break;\n case \"number\":\n if (typeof value !== \"number\") {\n issues.push({\n path,\n message: `Expected number, got ${typeof value}`,\n received: value,\n });\n }\n break;\n case \"boolean\":\n if (typeof value !== \"boolean\") {\n issues.push({\n path,\n message: `Expected boolean, got ${typeof value}`,\n received: value,\n });\n }\n break;\n case \"enum\":\n if (typeof value !== \"string\" || !fieldType.values.includes(value)) {\n issues.push({\n path,\n message: `Expected one of [${fieldType.values.join(\", \")}], got ${JSON.stringify(value)}`,\n received: value,\n });\n }\n break;\n case \"dynamicEnum\": {\n const values = options.resolvedEnums?.[fieldType.sourceId];\n if (!values || values.length === 0) {\n // Unresolved source: the legal values are unknown, so a string is the\n // strongest claim we can make about the value.\n if (typeof value !== \"string\") {\n issues.push({\n path,\n message: `Expected string, got ${typeof value}`,\n received: value,\n });\n }\n } else if (typeof value !== \"string\" || !values.includes(value)) {\n issues.push({\n path,\n message: `Expected one of the ${values.length} allowed \"${fieldType.sourceId}\" values [${summarizeValues(values)}], got ${JSON.stringify(value)}`,\n received: value,\n });\n }\n break;\n }\n case \"array\":\n if (!Array.isArray(value)) {\n issues.push({\n path,\n message: `Expected array, got ${typeof value}`,\n received: value,\n });\n } else {\n for (let i = 0; i < value.length; i++) {\n validateType(\n value[i],\n fieldType.items,\n `${path}[${i}]`,\n bundle,\n options,\n issues,\n );\n }\n }\n break;\n case \"object\": {\n if (typeof value !== \"object\" || Array.isArray(value)) {\n issues.push({\n path,\n message: `Expected object, got ${Array.isArray(value) ? \"array\" : typeof value}`,\n received: value,\n });\n } else if (bundle) {\n const nested = bundle.schemas[fieldType.nestedSchemaId];\n if (nested) {\n validateFields(\n value as Record<string, unknown>,\n nested,\n path,\n bundle,\n true, // strict for nested objects in strict mode\n options,\n issues,\n );\n }\n }\n break;\n }\n }\n}\n\n/**\n * Validate fields of a data object against a RuntimeSchema.\n */\nfunction validateFields(\n data: Record<string, unknown>,\n schema: RuntimeSchema,\n parentPath: string,\n bundle: SchemaBundle | undefined,\n strict: boolean,\n options: ValidationOptions,\n issues: FieldValidationIssue[],\n): void {\n for (const field of schema.fields) {\n const path = parentPath ? `${parentPath}.${field.name}` : field.name;\n const value = data[field.name];\n\n if (value === null || value === undefined) {\n if (strict && field.required) {\n issues.push({\n path,\n message: \"Required field is missing\",\n received: value,\n });\n }\n continue;\n }\n\n validateType(value, field.type, path, bundle, options, issues);\n if (field.constraints) {\n validateConstraints(value, field.constraints, path, issues);\n }\n }\n}\n\n/**\n * Validate data against a RuntimeSchema in strict mode.\n * All required fields must be present and correctly typed.\n * Returns validation issues (empty array means valid).\n */\nexport function validateStrict(\n data: Record<string, unknown>,\n schema: RuntimeSchema,\n bundle?: SchemaBundle,\n options: ValidationOptions = {},\n): FieldValidationIssue[] {\n const issues: FieldValidationIssue[] = [];\n validateFields(data, schema, \"\", bundle, true, options, issues);\n return issues;\n}\n\n/**\n * Validate data against a RuntimeSchema in partial mode.\n * Only validates types of fields that ARE present; never fails for missing fields.\n * Returns validation issues (empty array means valid).\n */\nexport function validatePartial(\n data: Record<string, unknown>,\n schema: RuntimeSchema,\n bundle?: SchemaBundle,\n options: ValidationOptions = {},\n): FieldValidationIssue[] {\n const issues: FieldValidationIssue[] = [];\n validateFields(data, schema, \"\", bundle, false, options, issues);\n return issues;\n}\n","import type { TraceSpan, TraceSink, TraceContext } from \"./types.js\";\n\nlet spanCounter = 0;\n\nfunction generateSpanId(): string {\n return `span_${++spanCounter}_${Date.now()}`;\n}\n\n/**\n * Tracer implementation that creates spans, records events, and dispatches to sinks.\n */\nexport class Tracer implements TraceContext {\n private sinks: TraceSink[];\n\n constructor(sinks?: TraceSink[]) {\n this.sinks = sinks ?? [];\n }\n\n startSpan(\n name: string,\n attributes?: Record<string, unknown>,\n parent?: TraceSpan,\n ): TraceSpan {\n return {\n id: generateSpanId(),\n name,\n startTime: Date.now(),\n events: [],\n attributes,\n parentId: parent?.id,\n };\n }\n\n endSpan(span: TraceSpan): void {\n span.endTime = Date.now();\n for (const sink of this.sinks) {\n sink.write(span);\n }\n }\n\n addEvent(\n span: TraceSpan,\n name: string,\n attributes?: Record<string, unknown>,\n ): void {\n span.events.push({\n name,\n timestamp: Date.now(),\n attributes,\n });\n }\n}\n","import type { RuntimeSchema, SchemaBundle } from \"../schema/types.js\";\nimport type { EnumResolver, ResolvedEnums } from \"../schema/enum-source.js\";\nimport type { Provider } from \"../provider/types.js\";\nimport type { TraceSink, TraceSpan } from \"../tracing/types.js\";\nimport { CoerceError } from \"../errors/coerce-error.js\";\nimport { EnumResolutionError } from \"../errors/enum-resolution-error.js\";\nimport { runtimeSchemaToJsonSchema } from \"../schema/json-schema.js\";\nimport { resolveEnumSources } from \"../schema/resolve-enum-sources.js\";\nimport type { FieldValidationIssue } from \"../errors/coerce-error.js\";\nimport { buildPrompt } from \"./prompt-builder.js\";\nimport { buildRepairInput } from \"./repair.js\";\nimport {\n PROVENANCE_INSTRUCTIONS,\n splitProvenance,\n toProvenanceSchema,\n} from \"./provenance.js\";\nimport type { FieldProvenance, ProvenanceResult } from \"./provenance.js\";\nimport { validateStrict, validatePartial } from \"./validator.js\";\nimport { Tracer } from \"../tracing/tracer.js\";\n\n/**\n * Options for coerce and partialCoerce.\n */\nexport interface CoerceOptions {\n /** The LLM provider to use */\n provider: Provider;\n /** The target schema */\n schema: RuntimeSchema;\n /** Optional bundle for resolving nested schemas */\n bundle?: SchemaBundle;\n /** Optional resolver for @ValuesFrom enum sources */\n enumResolver?: EnumResolver;\n /** Optional trace sinks */\n traceSinks?: TraceSink[];\n /**\n * How many times to send validation failures back to the model for\n * correction before giving up. Defaults to 0 — no repair.\n *\n * A repair costs an extra call only when validation actually failed, so the\n * happy path is unaffected. It is off by default because it also multiplies\n * worst-case latency, which a caller should opt into knowingly. For\n * extraction from messy input — scraped HTML, third-party payloads — 1 is\n * usually the right setting.\n */\n maxRepairAttempts?: number;\n}\n\n/**\n * Resolve every dynamic enum source the schema reaches, under its own span.\n *\n * Throws EnumResolutionError when a source backing a required field could not\n * be resolved: widening a required field to a free-form string lets the model\n * emit values that pass coercion and fail downstream. Failures that only touch\n * optional fields are recorded as trace events and the field widens, so a\n * flaky taxonomy cannot take down an import for a field nobody required.\n */\nasync function resolveEnums(\n schema: RuntimeSchema,\n bundle: SchemaBundle | undefined,\n enumResolver: EnumResolver | undefined,\n tracer: Tracer,\n parent: TraceSpan,\n): Promise<ResolvedEnums | undefined> {\n if (!enumResolver) {\n return undefined;\n }\n\n const span = tracer.startSpan(\"resolveEnums\", {}, parent);\n try {\n const { enums, failures } = await resolveEnumSources(\n schema,\n enumResolver,\n bundle,\n );\n\n tracer.addEvent(span, \"enumsResolved\", {\n sourceIds: Object.keys(enums),\n valueCounts: Object.fromEntries(\n Object.entries(enums).map(([id, values]) => [id, values.length]),\n ),\n });\n\n for (const failure of failures) {\n tracer.addEvent(span, \"enumSourceFailed\", {\n sourceId: failure.sourceId,\n reason: failure.reason,\n required: failure.required,\n paths: failure.paths,\n });\n }\n\n const fatal = failures.filter((f) => f.required);\n if (fatal.length > 0) {\n throw new EnumResolutionError(fatal);\n }\n\n return enums;\n } finally {\n tracer.endSpan(span);\n }\n}\n\n/** What a pipeline run produced, before mode-specific post-processing. */\ninterface CoercionRun {\n data: Record<string, unknown>;\n provenance: Record<string, FieldProvenance>;\n}\n\ninterface RunOptions {\n mode: \"coerce\" | \"partialCoerce\";\n /** Ask the model to annotate each field with where the value came from. */\n provenance: boolean;\n}\n\n/**\n * Run the shared coercion pipeline: resolve enum sources, build the prompt and\n * JSON Schema from them, call the provider, validate, and — when asked — send\n * validation failures back for correction.\n *\n * All four modes trace the same spans; they differ in the root span name, in\n * which validator decides whether the response is acceptable, and in whether\n * the request is wrapped for provenance.\n */\nasync function runCoercion(\n input: string,\n options: CoerceOptions,\n { mode, provenance }: RunOptions,\n): Promise<CoercionRun> {\n const { provider, schema, bundle, enumResolver, traceSinks } = options;\n const maxRepairAttempts = options.maxRepairAttempts ?? 0;\n if (!Number.isInteger(maxRepairAttempts) || maxRepairAttempts < 0) {\n throw new RangeError(\n `maxRepairAttempts must be a non-negative integer, got ${String(options.maxRepairAttempts)}`,\n );\n }\n\n const tracer = new Tracer(traceSinks);\n const rootSpan = tracer.startSpan(mode, { schemaId: schema.id, provenance });\n\n try {\n // Sources are resolved against the target schema even in a provenance run:\n // wrapping does not change which sources are reachable, and the wrapper's\n // extra nesting would only make the walk more expensive.\n const resolvedEnums = await resolveEnums(\n schema,\n bundle,\n enumResolver,\n tracer,\n rootSpan,\n );\n\n // The prompt describes the target schema either way — its field semantics\n // are what the model needs. The wrapper shape is carried by the JSON\n // Schema, and how to judge confidence by the extra instructions.\n const promptSpan = tracer.startSpan(\"buildPrompt\", {}, rootSpan);\n const basePrompt = buildPrompt(schema, bundle, { resolvedEnums });\n const systemPrompt = provenance\n ? `${basePrompt}\\n${PROVENANCE_INSTRUCTIONS}`\n : basePrompt;\n tracer.addEvent(promptSpan, \"promptBuilt\", {\n promptLength: systemPrompt.length,\n });\n tracer.endSpan(promptSpan);\n\n const request = provenance\n ? toProvenanceSchema(schema, bundle)\n : { schema, bundle };\n\n const schemaSpan = tracer.startSpan(\"buildJsonSchema\", {}, rootSpan);\n const jsonSchema = runtimeSchemaToJsonSchema(request.schema, request.bundle, {\n resolvedEnums,\n });\n tracer.endSpan(schemaSpan);\n\n const validate = mode === \"coerce\" ? validateStrict : validatePartial;\n let userInput = input;\n let issues: FieldValidationIssue[] = [];\n let run: CoercionRun = { data: {}, provenance: {} };\n\n for (let attempt = 0; attempt <= maxRepairAttempts; attempt++) {\n const llmSpan = tracer.startSpan(\"llmCall\", { attempt }, rootSpan);\n const response = await provider.complete({\n systemPrompt,\n userInput,\n jsonSchema,\n schema: request.schema,\n bundle: request.bundle,\n resolvedEnums,\n });\n tracer.addEvent(llmSpan, \"responseReceived\", { usage: response.usage });\n tracer.endSpan(llmSpan);\n\n run = provenance\n ? splitProvenance(response.data, schema)\n : { data: response.data, provenance: {} };\n\n const validationSpan = tracer.startSpan(\"validate\", { attempt }, rootSpan);\n issues = validate(run.data, schema, bundle, { resolvedEnums });\n tracer.addEvent(validationSpan, \"validated\", { issueCount: issues.length });\n tracer.endSpan(validationSpan);\n\n if (issues.length === 0) {\n return run;\n }\n\n if (attempt < maxRepairAttempts) {\n tracer.addEvent(rootSpan, \"repairAttempt\", {\n attempt: attempt + 1,\n issueCount: issues.length,\n paths: issues.map((issue) => issue.path),\n });\n // Feed back the unwrapped data: it is what the issues refer to, and\n // the schema still forces the wrapper shape on the way back.\n userInput = buildRepairInput(input, run.data, issues);\n }\n }\n\n throw new CoerceError(issues);\n } finally {\n tracer.endSpan(rootSpan);\n }\n}\n\n/** Drop nulls, which a partial result reports as absence. */\nfunction stripNulls(data: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (value !== null) {\n result[key] = value;\n }\n }\n return result;\n}\n\n/**\n * Coerce user input into a fully validated instance of the target schema.\n * Throws CoerceError if validation fails (required fields missing, type\n * mismatches, constraint violations, values outside a resolved taxonomy).\n * Throws EnumResolutionError if a required field's enum source cannot be resolved.\n */\nexport async function coerce<T>(\n input: string,\n options: CoerceOptions,\n): Promise<T> {\n const { data } = await runCoercion(input, options, {\n mode: \"coerce\",\n provenance: false,\n });\n return data as T;\n}\n\n/**\n * Coerce user input into a partial instance of the target schema.\n * Only validates types of fields that are present; never throws for missing fields.\n * Throws CoerceError only if present fields have type mismatches or violate\n * their constraints, and EnumResolutionError if a required field's enum source\n * cannot be resolved.\n */\nexport async function partialCoerce<T>(\n input: string,\n options: CoerceOptions,\n): Promise<Partial<T>> {\n const { data } = await runCoercion(input, options, {\n mode: \"partialCoerce\",\n provenance: false,\n });\n return stripNulls(data) as Partial<T>;\n}\n\n/**\n * Like {@link coerce}, but each field also comes back with how well the input\n * supported it and the text it was read from.\n *\n * Costs a larger schema and a longer response, so reach for it where a human\n * reviews the result — a pre-filled form that should flag its guesses — rather\n * than on a hot path.\n */\nexport async function coerceWithProvenance<T>(\n input: string,\n options: CoerceOptions,\n): Promise<ProvenanceResult<T>> {\n const { data, provenance } = await runCoercion(input, options, {\n mode: \"coerce\",\n provenance: true,\n });\n return { data: data as T, provenance };\n}\n\n/**\n * Like {@link partialCoerce}, but each field also comes back with how well the\n * input supported it and the text it was read from.\n *\n * This is the one a form pre-fill usually wants: fields the input never\n * mentioned are simply absent, and the ones that are present say how much to\n * trust them.\n */\nexport async function partialCoerceWithProvenance<T>(\n input: string,\n options: CoerceOptions,\n): Promise<ProvenanceResult<Partial<T>>> {\n const { data, provenance } = await runCoercion(input, options, {\n mode: \"partialCoerce\",\n provenance: true,\n });\n return { data: stripNulls(data) as Partial<T>, provenance };\n}\n","import type { Provider } from \"../provider/types.js\";\nimport type { SchemaBundle } from \"../schema/types.js\";\nimport type { EnumResolver } from \"../schema/enum-source.js\";\nimport type { TraceSink } from \"../tracing/types.js\";\n\n/**\n * Configuration options shared by global and per-call config.\n */\nexport interface SemblGlobalConfig {\n /** The LLM provider to use */\n provider?: Provider;\n /** Optional bundle for resolving nested schemas */\n bundle?: SchemaBundle;\n /** Optional resolver for @ValuesFrom enum sources */\n enumResolver?: EnumResolver;\n /** Optional trace sinks */\n traceSinks?: TraceSink[];\n /** How many times to send validation failures back for correction. Default 0. */\n maxRepairAttempts?: number;\n}\n\n/**\n * Per-call configuration overrides passed to `sembl()`.\n */\nexport interface SemblCallConfig {\n /** Override the LLM provider for this call */\n provider?: Provider;\n /** Override the bundle for this call */\n bundle?: SchemaBundle;\n /** Override the enum source resolver for this call */\n enumResolver?: EnumResolver;\n /** Override trace sinks for this call */\n traceSinks?: TraceSink[];\n /** Override the repair attempt budget for this call */\n maxRepairAttempts?: number;\n}\n\n/**\n * Resolved configuration with a guaranteed provider.\n */\nexport interface ResolvedConfig {\n provider: Provider;\n bundle?: SchemaBundle;\n enumResolver?: EnumResolver;\n traceSinks?: TraceSink[];\n maxRepairAttempts?: number;\n}\n\n/**\n * Global configuration singleton for SEMBL.\n */\nexport class SemblConfig {\n private static _config: SemblGlobalConfig = {};\n\n /** Set global defaults. */\n static configure(config: SemblGlobalConfig): void {\n SemblConfig._config = { ...config };\n }\n\n /** Reset global config to empty (useful in tests). */\n static reset(): void {\n SemblConfig._config = {};\n }\n\n /** Read-only access to the current global config. */\n static get current(): Readonly<SemblGlobalConfig> {\n return SemblConfig._config;\n }\n}\n\n/**\n * Merge global config with per-call overrides.\n * Throws if no provider is available after merging.\n */\nexport function resolveConfig(callConfig?: SemblCallConfig): ResolvedConfig {\n const global = SemblConfig.current;\n const provider = callConfig?.provider ?? global.provider;\n\n if (!provider) {\n throw new Error(\n \"No provider configured. Call SemblConfig.configure({ provider }) or pass { provider } to sembl().\",\n );\n }\n\n return {\n provider,\n bundle: callConfig?.bundle ?? global.bundle,\n enumResolver: callConfig?.enumResolver ?? global.enumResolver,\n traceSinks: callConfig?.traceSinks ?? global.traceSinks,\n maxRepairAttempts: callConfig?.maxRepairAttempts ?? global.maxRepairAttempts,\n };\n}\n","import type { RuntimeSchema } from \"../schema/types.js\";\nimport type { SemblCallConfig, ResolvedConfig } from \"./config.js\";\nimport { resolveConfig } from \"./config.js\";\nimport { coerce, partialCoerce } from \"./coerce.js\";\n\n/**\n * Serialize a value to a string for use as LLM input.\n * Strings pass through; objects are JSON-stringified.\n */\nfunction serialize(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n return JSON.stringify(value);\n}\n\n/**\n * A chainable, thenable wrapper around coercion results.\n *\n * Each `.coerceTo()` / `.partialCoerceTo()` call eagerly triggers an LLM call,\n * serializing the previous result as the input string for the next step.\n *\n * Implements `PromiseLike<T>` so it can be `await`ed directly.\n *\n * There is no provenance variant here: an intermediate link's annotations\n * would be serialized into the next call's input and lost, and a terminal one\n * would have to return a different shape than every other link. Use\n * `coerceWithProvenance` / `partialCoerceWithProvenance` directly instead.\n */\nexport class Coercible<T> implements PromiseLike<T> {\n constructor(\n private readonly _promise: Promise<T>,\n private readonly _config: ResolvedConfig,\n ) {}\n\n /** The per-call options every link in the chain shares. */\n private _optionsFor(schema: RuntimeSchema) {\n return {\n provider: this._config.provider,\n schema,\n bundle: this._config.bundle,\n enumResolver: this._config.enumResolver,\n traceSinks: this._config.traceSinks,\n maxRepairAttempts: this._config.maxRepairAttempts,\n };\n }\n\n /**\n * Chain a full coercion to a new schema.\n * The current value is serialized and used as input for the next LLM call.\n */\n coerceTo<U>(schema: RuntimeSchema): Coercible<U> {\n const next = this._promise.then((value) =>\n coerce<U>(serialize(value), this._optionsFor(schema)),\n );\n return new Coercible<U>(next, this._config);\n }\n\n /**\n * Chain a partial coercion to a new schema.\n * The current value is serialized and used as input for the next LLM call.\n */\n partialCoerceTo<U>(schema: RuntimeSchema): Coercible<Partial<U>> {\n const next = this._promise.then((value) =>\n partialCoerce<U>(serialize(value), this._optionsFor(schema)),\n );\n return new Coercible<Partial<U>>(next, this._config);\n }\n\n then<TResult1 = T, TResult2 = never>(\n onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this._promise.then(onfulfilled, onrejected);\n }\n\n catch<TResult = never>(\n onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null,\n ): Promise<T | TResult> {\n return this._promise.catch(onrejected);\n }\n\n finally(onfinally?: (() => void) | null): Promise<T> {\n return this._promise.finally(onfinally);\n }\n}\n\n/**\n * Entry point for the fluent coercion API.\n *\n * Accepts a string or object as input. Objects are JSON-serialized.\n * Returns a `Coercible<string>` that can be chained with `.coerceTo()` / `.partialCoerceTo()`.\n *\n * @example\n * ```ts\n * SemblConfig.configure({ provider, bundle });\n * const result = await sembl(\"some user input\")\n * .partialCoerceTo(ProfileSchema)\n * .coerceTo(IntentSchema);\n * ```\n */\nexport function sembl(\n input: string | Record<string, unknown>,\n config?: SemblCallConfig,\n): Coercible<string> {\n const resolved = resolveConfig(config);\n const serialized = serialize(input);\n return new Coercible<string>(Promise.resolve(serialized), resolved);\n}\n","import type { TraceSpan, TraceSink } from \"./types.js\";\n\n/**\n * Default trace sink that writes spans to the console.\n */\nexport class ConsoleSink implements TraceSink {\n write(span: TraceSpan): void {\n const duration = span.endTime ? span.endTime - span.startTime : \"?\";\n const prefix = span.parentId ? \" \" : \"\";\n console.log(\n `${prefix}[trace] ${span.name} (${duration}ms)`,\n span.attributes ?? \"\",\n );\n for (const event of span.events) {\n console.log(\n `${prefix} [event] ${event.name}`,\n event.attributes ?? \"\",\n );\n }\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@sembl/core",
3
+ "version": "0.1.0",
4
+ "description": "Semantic coercion for TypeScript: turn unstructured input into validated instances of your types.",
5
+ "keywords": [
6
+ "llm",
7
+ "structured-output",
8
+ "json-schema",
9
+ "extraction",
10
+ "typescript",
11
+ "decorators",
12
+ "anthropic",
13
+ "openai"
14
+ ],
15
+ "license": "MIT",
16
+ "author": "Sembl contributors",
17
+ "homepage": "https://github.com/nickrunner/sembl#readme",
18
+ "bugs": {
19
+ "url": "https://github.com/nickrunner/sembl/issues"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/nickrunner/sembl.git",
24
+ "directory": "packages/core"
25
+ },
26
+ "type": "module",
27
+ "main": "./dist/index.js",
28
+ "types": "./dist/index.d.ts",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.js"
33
+ }
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "sideEffects": false,
41
+ "engines": {
42
+ "node": ">=20"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public",
46
+ "provenance": true
47
+ },
48
+ "devDependencies": {
49
+ "@types/node": "^25.5.0",
50
+ "tsup": "^8.0.0",
51
+ "typescript": "^5.5.0"
52
+ },
53
+ "scripts": {
54
+ "build": "tsup",
55
+ "dev": "tsup --watch"
56
+ }
57
+ }