@sembl/core 0.1.0 → 0.2.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,1165 @@
1
+ /**
2
+ * Bounds a field's value beyond its type.
3
+ *
4
+ * Which keys apply depends on the value being checked, not on the declared
5
+ * field type: string bounds apply to strings, numeric bounds to numbers, and
6
+ * item bounds to arrays. On an array field the string/number bounds apply to
7
+ * each element, so `string[]` can carry both `maxItems` and `maxLength`.
8
+ */
9
+ interface FieldConstraints {
10
+ /** Maximum string length, inclusive */
11
+ maxLength?: number;
12
+ /** Minimum string length, inclusive */
13
+ minLength?: number;
14
+ /** Minimum numeric value, inclusive */
15
+ minimum?: number;
16
+ /** Maximum numeric value, inclusive */
17
+ maximum?: number;
18
+ /** Minimum number of array entries, inclusive */
19
+ minItems?: number;
20
+ /** Maximum number of array entries, inclusive */
21
+ maxItems?: number;
22
+ /** Regular expression source a string value must match */
23
+ pattern?: string;
24
+ }
25
+ /**
26
+ * Describes the type of a schema field.
27
+ *
28
+ * `enum` values are fixed when the schema is compiled. `dynamicEnum` defers
29
+ * them to coercion time, naming a source the caller resolves — for value sets
30
+ * that live in a database or CMS rather than in the source tree.
31
+ */
32
+ type FieldType = {
33
+ kind: "string";
34
+ } | {
35
+ kind: "number";
36
+ } | {
37
+ kind: "boolean";
38
+ } | {
39
+ kind: "array";
40
+ items: FieldType;
41
+ } | {
42
+ kind: "object";
43
+ nestedSchemaId: string;
44
+ } | {
45
+ kind: "enum";
46
+ values: string[];
47
+ } | {
48
+ kind: "dynamicEnum";
49
+ sourceId: string;
50
+ };
51
+ /**
52
+ * Describes a single field in a schema.
53
+ */
54
+ interface FieldDescriptor {
55
+ /** Property name as it appears in the class */
56
+ name: string;
57
+ /** Semantic description from @Describe decorator */
58
+ description: string;
59
+ /** The resolved type of this field */
60
+ type: FieldType;
61
+ /** Whether this field is required (definite assignment) */
62
+ required: boolean;
63
+ /** Value bounds from the @Constrain decorator, if any */
64
+ constraints?: FieldConstraints;
65
+ }
66
+ /**
67
+ * A compiled runtime schema representing a decorated class.
68
+ */
69
+ interface RuntimeSchema {
70
+ /** Unique identifier, typically the class name */
71
+ id: string;
72
+ /** Semantic description from @Schema decorator */
73
+ description: string;
74
+ /** All fields extracted from the class */
75
+ fields: FieldDescriptor[];
76
+ }
77
+ /**
78
+ * A bundle of all schemas extracted from a set of source files.
79
+ */
80
+ interface SchemaBundle {
81
+ /** Map of schema ID to RuntimeSchema */
82
+ schemas: Record<string, RuntimeSchema>;
83
+ }
84
+
85
+ /**
86
+ * Supplies the legal values for a `dynamicEnum` source at coercion time.
87
+ *
88
+ * Sources are opaque to SEMBL: the id is whatever the schema author wrote in
89
+ * `@ValuesFrom("...")`, and the caller decides how to turn it into values (a
90
+ * CMS fetch, a database query, a static map). Called at most once per distinct
91
+ * source id per coercion; the caller owns any caching across coercions.
92
+ *
93
+ * ```ts
94
+ * const enumResolver: EnumResolver = async (sourceId) => {
95
+ * const docs = await cms.taxonomy(sourceId);
96
+ * return docs.map((d) => d.slug);
97
+ * };
98
+ * ```
99
+ */
100
+ type EnumResolver = (sourceId: string) => readonly string[] | Promise<readonly string[]>;
101
+ /**
102
+ * The legal values for every enum source that resolved successfully,
103
+ * keyed by source id.
104
+ *
105
+ * A source id absent from this map is *unresolved* — the field it backs falls
106
+ * back to a free-form string. Successful resolution always yields a non-empty
107
+ * array; an empty result is treated as a failure, not as "no legal values",
108
+ * because a field with zero legal values is unsatisfiable.
109
+ */
110
+ type ResolvedEnums = Readonly<Record<string, readonly string[]>>;
111
+
112
+ type JsonSchema = Record<string, unknown>;
113
+ /**
114
+ * Which flavour of JSON Schema to emit.
115
+ *
116
+ * - `"openai-strict"` — the subset OpenAI structured outputs accepts.
117
+ * - `"standard"` — ordinary JSON Schema, for validators and other providers.
118
+ */
119
+ type JsonSchemaDialect = "openai-strict" | "standard";
120
+ /**
121
+ * Options for JSON Schema generation.
122
+ */
123
+ interface JsonSchemaOptions {
124
+ /** Legal values for dynamic enum sources, from `resolveEnumSources` */
125
+ resolvedEnums?: ResolvedEnums;
126
+ /** Target dialect. Defaults to `"openai-strict"`. */
127
+ dialect?: JsonSchemaDialect;
128
+ }
129
+ /**
130
+ * Convert a RuntimeSchema to a JSON Schema object.
131
+ *
132
+ * Under `"openai-strict"`, every property is listed in `required` and an
133
+ * optional field becomes `anyOf: [T, null]`, as structured outputs demand.
134
+ * Under `"standard"`, only genuinely required fields are listed and optional
135
+ * ones are simply absent — which is what keeps an unmentioned field
136
+ * distinguishable from one the model explicitly nulled.
137
+ *
138
+ * Both dialects inline nested schemas (no `$ref`) and set
139
+ * `additionalProperties: false`. Dynamic enum fields become a string `enum`
140
+ * when their source resolved, and a plain string otherwise. FieldConstraints
141
+ * are emitted only in `"standard"` — see {@link CONSTRAINT_KEYWORDS}.
142
+ */
143
+ declare function runtimeSchemaToJsonSchema(schema: RuntimeSchema, bundle?: SchemaBundle, options?: JsonSchemaOptions): JsonSchema;
144
+ /**
145
+ * Wrap a RuntimeSchema as a top-level JSON Schema suitable for
146
+ * OpenAI's response_format.json_schema.schema parameter.
147
+ */
148
+ declare function toOpenAIJsonSchema(schema: RuntimeSchema, bundle?: SchemaBundle, options?: Omit<JsonSchemaOptions, "dialect">): JsonSchema;
149
+
150
+ /**
151
+ * An enum source that could not be turned into a usable set of legal values.
152
+ */
153
+ interface EnumSourceFailure {
154
+ /** The source id that failed */
155
+ sourceId: string;
156
+ /** Why it failed: the resolver threw, or it produced no values */
157
+ reason: "threw" | "empty";
158
+ /** The thrown value, when `reason` is "threw" */
159
+ cause?: unknown;
160
+ /**
161
+ * Whether a required field depends on this source. A field counts as
162
+ * required only if every object on the path to it is also required — an
163
+ * unreachable field cannot make a coercion fail.
164
+ */
165
+ required: boolean;
166
+ /** Field paths that reference this source, for error messages */
167
+ paths: string[];
168
+ }
169
+ /**
170
+ * The outcome of resolving every enum source a schema reaches.
171
+ */
172
+ interface EnumResolution {
173
+ /** Legal values for each source that resolved successfully */
174
+ enums: ResolvedEnums;
175
+ /** Sources that threw or produced nothing */
176
+ failures: EnumSourceFailure[];
177
+ }
178
+ /** How a single enum source is reached from the root schema. */
179
+ interface EnumSourceUsage {
180
+ /** Whether the source is reachable through an unbroken chain of required fields */
181
+ required: boolean;
182
+ /** Field paths that reference this source */
183
+ paths: string[];
184
+ }
185
+ /**
186
+ * Collect the distinct dynamic enum source ids a schema reaches, directly or
187
+ * through its bundle, along with whether each is reachable through a chain of
188
+ * required fields.
189
+ */
190
+ declare function collectEnumSources(schema: RuntimeSchema, bundle?: SchemaBundle): Map<string, EnumSourceUsage>;
191
+ /**
192
+ * Resolve every dynamic enum source a schema reaches, calling `resolver` once
193
+ * per distinct source id and awaiting all of them concurrently.
194
+ *
195
+ * Resolution never throws on the caller's behalf. A source whose resolver
196
+ * throws, or which yields no values, is reported in `failures` and left out of
197
+ * `enums` — downstream that means the field widens to a free-form string.
198
+ * Widening a *required* field is a silent correctness hole, so callers are
199
+ * expected to treat a failure with `required: true` as fatal; `coerce` and
200
+ * `partialCoerce` do exactly that.
201
+ */
202
+ declare function resolveEnumSources(schema: RuntimeSchema, resolver: EnumResolver, bundle?: SchemaBundle): Promise<EnumResolution>;
203
+
204
+ /**
205
+ * Registry for looking up compiled RuntimeSchemas by ID.
206
+ */
207
+ declare class SchemaRegistry {
208
+ private schemas;
209
+ /**
210
+ * Register a single schema.
211
+ */
212
+ register(schema: RuntimeSchema): void;
213
+ /**
214
+ * Register all schemas from a bundle.
215
+ */
216
+ registerBundle(bundle: SchemaBundle): void;
217
+ /**
218
+ * Look up a schema by ID.
219
+ */
220
+ get(id: string): RuntimeSchema | undefined;
221
+ /**
222
+ * Get a schema by ID, throwing if not found.
223
+ */
224
+ require(id: string): RuntimeSchema;
225
+ /**
226
+ * Get a SchemaBundle of all registered schemas.
227
+ */
228
+ toBundle(): SchemaBundle;
229
+ /**
230
+ * Get all registered schema IDs.
231
+ */
232
+ ids(): string[];
233
+ }
234
+
235
+ /**
236
+ * A field under construction. `T` is the TypeScript type a coerced value
237
+ * will have; `Required` is whether the model must supply it.
238
+ *
239
+ * Builders are immutable: every method returns a new one, so a builder can be
240
+ * reused across schemas.
241
+ */
242
+ interface FieldBuilder<T, Required extends boolean = true> {
243
+ /** Phantom carrier for `T`; never set at runtime. */
244
+ readonly __type?: T;
245
+ readonly type: FieldType;
246
+ readonly description: string;
247
+ readonly required: Required;
248
+ readonly constraints?: FieldConstraints;
249
+ /** Nested schemas this field's type refers to, keyed by id. */
250
+ readonly schemas: Readonly<Record<string, RuntimeSchema>>;
251
+ /** The model may leave this field out. */
252
+ optional(): FieldBuilder<T, false>;
253
+ /**
254
+ * Wrap the type in an array. String and number bounds already on the
255
+ * builder apply to each element, exactly as they do for a decorated
256
+ * `string[]`; item-count bounds go here.
257
+ */
258
+ array(constraints?: FieldConstraints): FieldBuilder<T[], Required>;
259
+ /** Replace the description. */
260
+ describe(description: string): FieldBuilder<T, Required>;
261
+ /** Add bounds, merged over any already set. */
262
+ constrain(constraints: FieldConstraints): FieldBuilder<T, Required>;
263
+ /** The descriptor this builder produces under a given name. */
264
+ toDescriptor(name: string): FieldDescriptor;
265
+ }
266
+ /**
267
+ * A schema built at runtime. It *is* a `RuntimeSchema`, so it goes anywhere
268
+ * one is accepted, and it also carries the bundle of every schema it refers
269
+ * to (itself included), which the coercion functions use when no bundle is
270
+ * passed explicitly.
271
+ */
272
+ interface DefinedSchema<T> extends RuntimeSchema {
273
+ /** Phantom carrier for `T`; never set at runtime. */
274
+ readonly __type?: T;
275
+ readonly bundle: SchemaBundle;
276
+ }
277
+ /** The TypeScript type of a defined schema or a field builder. */
278
+ type Infer<S> = S extends DefinedSchema<infer T> ? T : S extends FieldBuilder<infer T, boolean> ? T : never;
279
+ type Simplify<T> = {
280
+ [K in keyof T]: T[K];
281
+ } & {};
282
+ type FieldValue<B> = B extends FieldBuilder<infer T, boolean> ? T : never;
283
+ type RequiredKeys<F> = {
284
+ [K in keyof F]: F[K] extends FieldBuilder<unknown, true> ? K : never;
285
+ }[keyof F];
286
+ type OptionalKeys<F> = {
287
+ [K in keyof F]: F[K] extends FieldBuilder<unknown, false> ? K : never;
288
+ }[keyof F];
289
+ /** The object type a set of field builders describes. */
290
+ type InferFields<F> = Simplify<{
291
+ [K in RequiredKeys<F>]: FieldValue<F[K]>;
292
+ } & {
293
+ [K in OptionalKeys<F>]?: FieldValue<F[K]>;
294
+ }>;
295
+ /**
296
+ * Field builders. Each takes the field's description first — the semantics
297
+ * are the point — and returns a required field; call `.optional()` to let
298
+ * the model leave it out.
299
+ */
300
+ declare const field: {
301
+ string(description: string, constraints?: FieldConstraints): FieldBuilder<string, true>;
302
+ number(description: string, constraints?: FieldConstraints): FieldBuilder<number, true>;
303
+ boolean(description: string): FieldBuilder<boolean, true>;
304
+ /** A closed set of string values known at build time. */
305
+ enum<const V extends string>(values: readonly V[], description: string): FieldBuilder<V, true>;
306
+ /**
307
+ * A closed set of string values resolved at coercion time from a named
308
+ * source — the runtime equivalent of `@ValuesFrom`.
309
+ */
310
+ valuesFrom(sourceId: string, description: string, constraints?: FieldConstraints): FieldBuilder<string, true>;
311
+ /** A nested object shaped by another defined schema. */
312
+ object<S extends DefinedSchema<unknown>>(schema: S, description: string): FieldBuilder<Infer<S>, true>;
313
+ /** An array of whatever another builder describes; same as `item.array()`. */
314
+ array<T, R extends boolean>(item: FieldBuilder<T, R>, constraints?: FieldConstraints): FieldBuilder<T[], R>;
315
+ };
316
+ /**
317
+ * Define a schema at runtime, without decorators or a compile step.
318
+ *
319
+ * Produces exactly what `sembl extract` would emit for the equivalent
320
+ * decorated class — the same descriptors in the same order — so the two ways
321
+ * of defining a schema are interchangeable. The result carries a bundle of
322
+ * every schema it refers to, so nested objects work without assembling one
323
+ * by hand.
324
+ *
325
+ * ```ts
326
+ * const Address = defineSchema("Address", "Where a property is.", {
327
+ * city: field.string("City or municipality."),
328
+ * zip: field.string("Postal code.").optional(),
329
+ * });
330
+ * const Listing = defineSchema("Listing", "A short-term rental listing.", {
331
+ * name: field.string("Display name.", { maxLength: 40 }),
332
+ * amenities: field.valuesFrom("amenities", "What the property offers.").array({ maxItems: 5 }),
333
+ * address: field.object(Address, "Where the property is.").optional(),
334
+ * });
335
+ * type Listing = Infer<typeof Listing>;
336
+ * ```
337
+ */
338
+ declare function defineSchema<F extends Record<string, FieldBuilder<unknown, boolean>>>(id: string, description: string, fields: F): DefinedSchema<InferFields<F>>;
339
+ /** The bundle a schema carries, when it was made by {@link defineSchema}. */
340
+ declare function bundleOf(schema: RuntimeSchema): SchemaBundle | undefined;
341
+
342
+ /**
343
+ * Class decorator marking a schema class with a semantic description.
344
+ * No-op at runtime — parsed by the compiler from source AST.
345
+ */
346
+ declare function Schema(description: string): ClassDecorator;
347
+ /**
348
+ * Property decorator providing a field-level semantic description.
349
+ * No-op at runtime — parsed by the compiler from source AST.
350
+ */
351
+ declare function Describe(description: string): PropertyDecorator;
352
+ /**
353
+ * Property decorator bounding a field's legal values — lengths, numeric
354
+ * ranges, array sizes, a pattern.
355
+ *
356
+ * Takes an object literal of compile-time constants; the compiler reads it
357
+ * from source, so computed expressions are not supported.
358
+ *
359
+ * ```ts
360
+ * @Describe("Display name for the listing.")
361
+ * @Constrain({ maxLength: 40 })
362
+ * name!: string;
363
+ * ```
364
+ *
365
+ * No-op at runtime — parsed by the compiler from source AST.
366
+ */
367
+ declare function Constrain(constraints: FieldConstraints): PropertyDecorator;
368
+ /**
369
+ * Property decorator declaring that a field's legal values come from a named
370
+ * source resolved at coercion time rather than from the source tree — a CMS
371
+ * taxonomy, a database enum table.
372
+ *
373
+ * Applies to a string field or to the element type of a string array. The
374
+ * caller supplies an `EnumResolver` that maps `sourceId` to the legal values.
375
+ *
376
+ * ```ts
377
+ * @Describe("Amenities the property offers.")
378
+ * @ValuesFrom("amenities")
379
+ * amenities!: string[];
380
+ * ```
381
+ *
382
+ * No-op at runtime — parsed by the compiler from source AST.
383
+ */
384
+ declare function ValuesFrom(sourceId: string): PropertyDecorator;
385
+
386
+ /**
387
+ * Recursively makes all properties optional, including nested objects.
388
+ */
389
+ type DeepPartial<T> = {
390
+ [P in keyof T]?: T[P] extends (infer U)[] ? DeepPartial<U>[] : T[P] extends object ? DeepPartial<T[P]> : T[P];
391
+ };
392
+
393
+ /**
394
+ * Describes a single validation issue on a field.
395
+ */
396
+ interface FieldValidationIssue {
397
+ /** Dot-separated path to the field, e.g. "address.city" */
398
+ path: string;
399
+ /** What went wrong */
400
+ message: string;
401
+ /** The value that was received, if any */
402
+ received?: unknown;
403
+ }
404
+ /**
405
+ * Error thrown when coercion validation fails.
406
+ */
407
+ declare class CoerceError extends Error {
408
+ readonly issues: FieldValidationIssue[];
409
+ constructor(issues: FieldValidationIssue[]);
410
+ }
411
+
412
+ /**
413
+ * Error thrown when an enum source backing a required field could not be
414
+ * resolved.
415
+ *
416
+ * Falling back to a free-form string here would let the model invent values
417
+ * that pass coercion and fail downstream, so a required field with a dead
418
+ * taxonomy is a hard failure rather than a widening.
419
+ */
420
+ declare class EnumResolutionError extends Error {
421
+ readonly failures: EnumSourceFailure[];
422
+ constructor(failures: EnumSourceFailure[]);
423
+ }
424
+
425
+ /**
426
+ * Configuration for a provider.
427
+ */
428
+ interface ProviderConfig {
429
+ /** Model identifier, e.g. "gpt-4o" */
430
+ model: string;
431
+ /** Optional temperature override (0-2) */
432
+ temperature?: number;
433
+ /** Optional max tokens for the response */
434
+ maxTokens?: number;
435
+ }
436
+ /**
437
+ * Request sent to a provider for structured output.
438
+ */
439
+ interface ProviderRequest {
440
+ /** System prompt with semantic context */
441
+ systemPrompt: string;
442
+ /** User input to coerce */
443
+ userInput: string;
444
+ /** JSON Schema for structured output */
445
+ jsonSchema: Record<string, unknown>;
446
+ /** The runtime schema being targeted */
447
+ schema: RuntimeSchema;
448
+ /**
449
+ * Bundle used to resolve nested schemas, when one was supplied.
450
+ *
451
+ * `jsonSchema` above is already built against this bundle in the
452
+ * OpenAI-strict dialect. Providers whose API wants a different dialect
453
+ * should re-derive from `schema` + `bundle` rather than reaching for
454
+ * `schema` alone — dropping the bundle silently emits nested objects with
455
+ * no properties.
456
+ */
457
+ bundle?: SchemaBundle;
458
+ /**
459
+ * Legal values for the schema's `dynamicEnum` sources, already resolved.
460
+ * A provider that re-derives its own JSON Schema must pass these along —
461
+ * dropping them silently widens those fields back to free-form strings.
462
+ */
463
+ resolvedEnums?: ResolvedEnums;
464
+ }
465
+ /**
466
+ * Token accounting for a single provider call.
467
+ *
468
+ * The cache fields are reported as the provider reports them, and providers
469
+ * disagree about whether cached tokens also appear in `promptTokens` — so read
470
+ * them as an effectiveness signal, not as terms to add up. Each provider's
471
+ * README states which convention it follows.
472
+ */
473
+ interface ProviderUsage {
474
+ /** Input tokens, as the provider counts them. */
475
+ promptTokens: number;
476
+ /** Output tokens generated. */
477
+ completionTokens: number;
478
+ /** `promptTokens + completionTokens`. */
479
+ totalTokens: number;
480
+ /**
481
+ * Input tokens served from a prompt cache, when the provider reports it.
482
+ * Growing to cover the stable prefix across a batch is the signal that
483
+ * caching is working; a run of zeroes means it is not.
484
+ */
485
+ cacheReadTokens?: number;
486
+ /**
487
+ * Input tokens written to a prompt cache, when the provider reports it.
488
+ * Expect this on the first call of a batch and near zero afterwards; a
489
+ * write on every call means the cached prefix is being invalidated.
490
+ */
491
+ cacheWriteTokens?: number;
492
+ }
493
+ /**
494
+ * Response from a provider.
495
+ */
496
+ interface ProviderResponse {
497
+ /** The parsed structured output */
498
+ data: Record<string, unknown>;
499
+ /** Raw response metadata for tracing */
500
+ usage?: ProviderUsage;
501
+ }
502
+ /**
503
+ * Interface that LLM providers must implement.
504
+ */
505
+ interface Provider {
506
+ /**
507
+ * Send a structured output request to the LLM.
508
+ */
509
+ complete(request: ProviderRequest): Promise<ProviderResponse>;
510
+ }
511
+
512
+ /**
513
+ * A discrete event within a trace span.
514
+ */
515
+ interface TraceEvent {
516
+ /** Event name */
517
+ name: string;
518
+ /** Timestamp */
519
+ timestamp: number;
520
+ /** Arbitrary attributes */
521
+ attributes?: Record<string, unknown>;
522
+ }
523
+ /**
524
+ * A span representing a unit of work in the coercion pipeline.
525
+ */
526
+ interface TraceSpan {
527
+ /** Unique span ID */
528
+ id: string;
529
+ /** Human-readable name */
530
+ name: string;
531
+ /** Start timestamp */
532
+ startTime: number;
533
+ /** End timestamp (set when span completes) */
534
+ endTime?: number;
535
+ /** Events recorded during this span */
536
+ events: TraceEvent[];
537
+ /** Arbitrary attributes */
538
+ attributes?: Record<string, unknown>;
539
+ /** Parent span ID, if nested */
540
+ parentId?: string;
541
+ }
542
+ /**
543
+ * Sink that receives completed trace spans.
544
+ */
545
+ interface TraceSink {
546
+ /** Called when a span is completed */
547
+ write(span: TraceSpan): void;
548
+ }
549
+ /**
550
+ * Context for tracing within a coercion call.
551
+ */
552
+ interface TraceContext {
553
+ /** Start a new span */
554
+ startSpan(name: string, attributes?: Record<string, unknown>): TraceSpan;
555
+ /** End a span and dispatch to sinks */
556
+ endSpan(span: TraceSpan): void;
557
+ /** Add an event to the current span */
558
+ addEvent(span: TraceSpan, name: string, attributes?: Record<string, unknown>): void;
559
+ }
560
+
561
+ /**
562
+ * One piece of input to extract from.
563
+ *
564
+ * A label names where the text came from — "Airbnb listing", "Broker email" —
565
+ * so the model can tell sources apart and provenance can say which one a
566
+ * value was read from. Labels are optional for a single source and are filled
567
+ * in as "Source 1", "Source 2", … when several are given without them.
568
+ */
569
+ interface Source {
570
+ /** Where the text came from, for the model and for provenance. */
571
+ label?: string;
572
+ /** The text itself. */
573
+ text: string;
574
+ }
575
+ /**
576
+ * What a coercion accepts as input: a plain string, one labelled source, or
577
+ * several. Everything is normalised to a `Source[]` before it reaches the
578
+ * prompt, so the three forms behave identically.
579
+ */
580
+ type CoerceInput = string | Source | readonly Source[];
581
+ /** Whether a value has the shape of a {@link Source}. */
582
+ declare function isSource(value: unknown): value is Source;
583
+ /** Whether a value is any of the accepted input forms. */
584
+ declare function isCoerceInput(value: unknown): value is CoerceInput;
585
+ /**
586
+ * Normalise input to a list of sources, labelling every entry when there is
587
+ * more than one so each can be referred to unambiguously.
588
+ *
589
+ * Throws for an empty list: there is nothing to extract from, and a silent
590
+ * empty prompt would only produce a confident hallucination.
591
+ */
592
+ declare function toSources(input: CoerceInput): Source[];
593
+ /**
594
+ * Render sources as the user message: each one inside its own delimited
595
+ * block, with its label as an attribute when it has one.
596
+ *
597
+ * The delimiters are the whole point. They let the system prompt say "what
598
+ * is inside these tags is data, not instructions", which is what makes a
599
+ * scraped page reading "ignore previous instructions" inert.
600
+ */
601
+ declare function renderSources(sources: readonly Source[]): string;
602
+ /**
603
+ * How the system prompt explains the framing to the model.
604
+ *
605
+ * Stated as a rule about where instructions can come from rather than as a
606
+ * list of attacks to watch for: the model does not need to recognise an
607
+ * injection, only to know that nothing inside a source block can be one.
608
+ */
609
+ declare const SOURCE_INSTRUCTIONS: string;
610
+
611
+ /**
612
+ * Which part of an over-budget source to cut.
613
+ *
614
+ * - `"tail"` keeps the beginning. The default: most documents lead with what
615
+ * matters, and structured front-matter (a title, JSON-LD) sits there.
616
+ * - `"head"` keeps the end, for logs and transcripts where the latest text
617
+ * is the relevant part.
618
+ * - `"middle"` keeps both ends and cuts the middle, for pages that open with
619
+ * a summary and close with the details.
620
+ */
621
+ type TruncatePolicy = "tail" | "head" | "middle";
622
+ /** What was cut from one source. */
623
+ interface TruncationRecord {
624
+ /** The source's label, when it had one. */
625
+ label?: string;
626
+ /** Characters before the cut. */
627
+ originalLength: number;
628
+ /** Characters after it, marker included. */
629
+ keptLength: number;
630
+ }
631
+ /** The sources after budgeting, and what happened to them. */
632
+ interface BudgetResult {
633
+ sources: Source[];
634
+ /** One record per source that was cut. Empty when everything fit. */
635
+ truncated: TruncationRecord[];
636
+ }
637
+ /**
638
+ * Fit a set of sources into a character budget.
639
+ *
640
+ * The budget covers the sources' text as a whole. When they exceed it, it is
641
+ * shared out so that every source that fits within an equal share keeps all
642
+ * of its text, and what those leave unused goes to the longer ones. A short
643
+ * email next to a long scraped page is therefore never touched; the page
644
+ * takes the whole cut. A cut is marked in place with how much was omitted,
645
+ * so the model knows the text is incomplete rather than reading a
646
+ * mid-sentence stop as the end.
647
+ */
648
+ declare function budgetSources(sources: readonly Source[], maxChars: number, policy?: TruncatePolicy): BudgetResult;
649
+
650
+ /**
651
+ * What to do with a present field that fails validation.
652
+ *
653
+ * - `"throw"` — the whole coercion fails with a `CoerceError`. The default.
654
+ * - `"drop"` — remove the offending value and carry on. What gets removed is
655
+ * the smallest thing that can go: an array element, an optional field, or
656
+ * (in a partial coercion) any top-level field. A violation that only a
657
+ * required field can absorb is not droppable and still throws.
658
+ * - `"clamp"` — where a bound makes a clamp meaningful (`maxLength`,
659
+ * `minimum`, `maximum`, `maxItems`), cut the value down to the bound; where
660
+ * it does not (a type mismatch, a bad enum value, `minLength`, `pattern`),
661
+ * fall back to dropping.
662
+ *
663
+ * A form pre-fill usually wants `"drop"` or `"clamp"`: losing twenty good
664
+ * fields because one came back out of range is the wrong failure unit when a
665
+ * person is about to review the result anyway.
666
+ */
667
+ type InvalidFieldPolicy = "throw" | "drop" | "clamp";
668
+ /** What was done about a validation issue. */
669
+ type IssueResolution = "dropped" | "clamped";
670
+ /** A validation issue and how it was resolved without a repair round. */
671
+ interface ResolvedIssue extends FieldValidationIssue {
672
+ /** What was done about it. */
673
+ resolution: IssueResolution;
674
+ /**
675
+ * The path that was actually changed. For a drop this can be an ancestor of
676
+ * `path` — the nearest array element or optional field that could absorb
677
+ * the removal.
678
+ */
679
+ resolvedPath: string;
680
+ /** The value now at `resolvedPath`, for a clamp. */
681
+ replacement?: unknown;
682
+ }
683
+ /** Options for {@link resolveIssues}. */
684
+ interface ResolveIssuesOptions {
685
+ /** Bundle for nested schemas, the same one the validator was given. */
686
+ bundle?: SchemaBundle;
687
+ /** Legal values for dynamic enum sources, the same ones the validator used. */
688
+ resolvedEnums?: ResolvedEnums;
689
+ /**
690
+ * Which validator judged the data. In a partial coercion every top-level
691
+ * field is optional by definition, so any of them can be dropped.
692
+ */
693
+ mode: "coerce" | "partialCoerce";
694
+ /** The policy to apply. `"throw"` resolves nothing. */
695
+ policy: InvalidFieldPolicy;
696
+ }
697
+ /** The outcome of resolving a set of issues. */
698
+ interface ResolveIssuesResult {
699
+ /** The data after every drop and clamp. The input is never mutated. */
700
+ data: Record<string, unknown>;
701
+ /** Issues the policy could act on, in the order they were handled. */
702
+ resolved: ResolvedIssue[];
703
+ /** Issues nothing could absorb — a required field, at every level. */
704
+ unresolved: FieldValidationIssue[];
705
+ }
706
+ /**
707
+ * Apply an {@link InvalidFieldPolicy} to a validated response.
708
+ *
709
+ * Works one action at a time and re-validates after each, so a clamp that
710
+ * leaves a value still invalid (too long *and* failing its pattern, say) falls
711
+ * through to a drop, and removing an array element never leaves a stale
712
+ * index behind. Each action strictly shrinks the data, so the loop ends.
713
+ *
714
+ * Pure: the input data is cloned, never mutated.
715
+ */
716
+ declare function resolveIssues(data: Record<string, unknown>, issues: readonly FieldValidationIssue[], schema: RuntimeSchema, options: ResolveIssuesOptions): ResolveIssuesResult;
717
+
718
+ /**
719
+ * How well the input supported a value.
720
+ *
721
+ * A three-level scale rather than a number: models are poorly calibrated at
722
+ * producing a 0–1 score, and a review UI only ever needs to decide whether to
723
+ * flag a field for a human anyway.
724
+ */
725
+ type FieldConfidence = "high" | "medium" | "low";
726
+ /** Where a coerced field's value came from. */
727
+ interface FieldProvenance {
728
+ /** How well the input supported this value. */
729
+ confidence: FieldConfidence;
730
+ /**
731
+ * The span of input the value was read from, quoted. Absent when the value
732
+ * was inferred rather than read — which is itself the signal worth showing.
733
+ */
734
+ evidence?: string;
735
+ /**
736
+ * The label of the source the value was read from. Only present when the
737
+ * coercion was given more than one source.
738
+ */
739
+ source?: string;
740
+ }
741
+ /** A coercion result paired with per-field provenance. */
742
+ interface ProvenanceResult<T> {
743
+ /** The coerced data, in the shape of the target schema. */
744
+ data: T;
745
+ /** Provenance for each top-level field the model returned, keyed by name. */
746
+ provenance: Record<string, FieldProvenance>;
747
+ /**
748
+ * Validation issues the `onInvalidField` policy absorbed instead of
749
+ * throwing — each with what was dropped or clamped. Empty under the
750
+ * default `"throw"` policy, or when the response validated cleanly.
751
+ */
752
+ issues: ResolvedIssue[];
753
+ }
754
+ /**
755
+ * Extra prompt guidance for a provenance run.
756
+ *
757
+ * The JSON Schema already forces the shape; what it cannot convey is how to
758
+ * judge confidence, which is the whole point of asking.
759
+ */
760
+ declare const PROVENANCE_INSTRUCTIONS: string;
761
+ /** Options for {@link toProvenanceSchema} and {@link provenanceInstructions}. */
762
+ interface ProvenanceOptions {
763
+ /**
764
+ * Labels of the sources the coercion was given, when there are several.
765
+ * Each annotation then also asks which source the value was read from.
766
+ */
767
+ sourceLabels?: readonly string[];
768
+ }
769
+ /**
770
+ * The provenance guidance for a run, extended with the source rule when the
771
+ * run has several sources to choose between.
772
+ */
773
+ declare function provenanceInstructions(options?: ProvenanceOptions): string;
774
+ /**
775
+ * Derive the schema to actually request when provenance is wanted: the same
776
+ * fields, each wrapped in `{ value, confidence, evidence }`.
777
+ *
778
+ * Only top-level fields are annotated. A nested object keeps its ordinary
779
+ * shape inside `value`, so provenance is reported for the object as a whole
780
+ * rather than per leaf — annotating every leaf multiplies both the schema and
781
+ * the output for detail a review UI rarely acts on.
782
+ *
783
+ * Returns a bundle carrying the wrapper, the per-field annotation schemas, and
784
+ * everything the original bundle held, so nested types still inline.
785
+ */
786
+ declare function toProvenanceSchema(schema: RuntimeSchema, bundle?: SchemaBundle, options?: ProvenanceOptions): {
787
+ schema: RuntimeSchema;
788
+ bundle: SchemaBundle;
789
+ };
790
+ /**
791
+ * Split a provenance-shaped response back into plain data and per-field
792
+ * provenance.
793
+ *
794
+ * A field the model returned unwrapped — or wrapped without a usable
795
+ * `confidence` — still yields its value; the provenance is simply not
796
+ * recorded. Losing an annotation is not a reason to lose the extraction, and
797
+ * the missing key is visible to the caller.
798
+ */
799
+ declare function splitProvenance(response: Record<string, unknown>, schema: RuntimeSchema): {
800
+ data: Record<string, unknown>;
801
+ provenance: Record<string, FieldProvenance>;
802
+ };
803
+
804
+ /**
805
+ * Options for coerce and partialCoerce.
806
+ */
807
+ interface CoerceOptions {
808
+ /** The LLM provider to use */
809
+ provider: Provider;
810
+ /** The target schema */
811
+ schema: RuntimeSchema;
812
+ /** Optional bundle for resolving nested schemas */
813
+ bundle?: SchemaBundle;
814
+ /** Optional resolver for @ValuesFrom enum sources */
815
+ enumResolver?: EnumResolver;
816
+ /** Optional trace sinks */
817
+ traceSinks?: TraceSink[];
818
+ /**
819
+ * How many times to send validation failures back to the model for
820
+ * correction before giving up. Defaults to 0 — no repair.
821
+ *
822
+ * A repair costs an extra call only when validation actually failed, so the
823
+ * happy path is unaffected. It is off by default because it also multiplies
824
+ * worst-case latency, which a caller should opt into knowingly. For
825
+ * extraction from messy input — scraped HTML, third-party payloads — 1 is
826
+ * usually the right setting.
827
+ */
828
+ maxRepairAttempts?: number;
829
+ /**
830
+ * What to do with a present field that fails validation: `"throw"` (the
831
+ * default), `"drop"` it, or `"clamp"` it to its bounds where that is
832
+ * meaningful and drop it otherwise. Required fields are never dropped.
833
+ *
834
+ * Issues the policy can absorb never trigger a repair round; the provenance
835
+ * variants report them in `issues`, and every run records them in a trace
836
+ * event.
837
+ */
838
+ onInvalidField?: InvalidFieldPolicy;
839
+ /**
840
+ * Cap on the total characters of source text sent to the model, applied
841
+ * after `preprocess`. Sources over the cap are cut per `truncate`, each
842
+ * losing a share proportional to its length, and the cut is marked in
843
+ * place with how much was omitted. Unbounded by default.
844
+ *
845
+ * Tokens vary by model and tokenizer; as a rule of thumb English prose runs
846
+ * about four characters per token.
847
+ */
848
+ maxInputChars?: number;
849
+ /** Which part of an over-budget source to cut. Default `"tail"`. */
850
+ truncate?: TruncatePolicy;
851
+ /**
852
+ * Transform each source before budgeting and rendering: strip HTML down to
853
+ * text, redact, normalise. Returning a string keeps the source's label.
854
+ */
855
+ preprocess?: PreprocessSource;
856
+ }
857
+ /** A hook applied to each source before it is budgeted and rendered. */
858
+ type PreprocessSource = (source: Source, index: number) => Source | string | Promise<Source | string>;
859
+ /**
860
+ * Coerce user input into a fully validated instance of the target schema.
861
+ * Throws CoerceError if validation fails (required fields missing, type
862
+ * mismatches, constraint violations, values outside a resolved taxonomy).
863
+ * Throws EnumResolutionError if a required field's enum source cannot be resolved.
864
+ */
865
+ declare function coerce<T>(input: CoerceInput, options: CoerceOptions): Promise<T>;
866
+ /**
867
+ * Coerce user input into a partial instance of the target schema.
868
+ * Only validates types of fields that are present; never throws for missing fields.
869
+ * Throws CoerceError only if present fields have type mismatches or violate
870
+ * their constraints, and EnumResolutionError if a required field's enum source
871
+ * cannot be resolved.
872
+ */
873
+ declare function partialCoerce<T>(input: CoerceInput, options: CoerceOptions): Promise<Partial<T>>;
874
+ /**
875
+ * Like {@link coerce}, but each field also comes back with how well the input
876
+ * supported it and the text it was read from.
877
+ *
878
+ * Costs a larger schema and a longer response, so reach for it where a human
879
+ * reviews the result — a pre-filled form that should flag its guesses — rather
880
+ * than on a hot path.
881
+ */
882
+ declare function coerceWithProvenance<T>(input: CoerceInput, options: CoerceOptions): Promise<ProvenanceResult<T>>;
883
+ /**
884
+ * Like {@link partialCoerce}, but each field also comes back with how well the
885
+ * input supported it and the text it was read from.
886
+ *
887
+ * This is the one a form pre-fill usually wants: fields the input never
888
+ * mentioned are simply absent, and the ones that are present say how much to
889
+ * trust them.
890
+ */
891
+ declare function partialCoerceWithProvenance<T>(input: CoerceInput, options: CoerceOptions): Promise<ProvenanceResult<Partial<T>>>;
892
+
893
+ /** Options for {@link coerceMany}. Everything in `CoerceOptions` applies to each item. */
894
+ interface CoerceManyOptions extends CoerceOptions {
895
+ /** How many items may be in flight at once. Default 4. */
896
+ concurrency?: number;
897
+ /** Which coercion to run per item. Default `"coerce"`. */
898
+ mode?: "coerce" | "partialCoerce";
899
+ /** Ask for per-field provenance on every item. Default false. */
900
+ provenance?: boolean;
901
+ /**
902
+ * Run the first item alone before fanning out, so a provider that caches
903
+ * the prompt prefix writes it once and every later item reads it. Costs
904
+ * one item's latency up front; saves a cache write per concurrent worker.
905
+ * Default true.
906
+ */
907
+ primeCache?: boolean;
908
+ /** How the batch backs off when the provider pushes back. */
909
+ retry?: RetryOptions;
910
+ /** Called as each item settles, in completion order, for progress. */
911
+ onItem?: (result: CoerceManyResult<unknown>) => void;
912
+ /** Stop starting new items; those not yet started fail with the reason. */
913
+ signal?: AbortSignal;
914
+ }
915
+ /**
916
+ * Backoff for provider errors that are worth another try — `kind: "api"`
917
+ * with `retryable: true`, as both bundled providers report a 429, an
918
+ * overloaded 529 or a dropped connection.
919
+ *
920
+ * The pause is shared: one rate-limit answer holds every worker, rather than
921
+ * each item discovering the limit for itself and multiplying the pressure.
922
+ * The delay doubles with each consecutive retryable failure across the batch
923
+ * and resets on any success.
924
+ */
925
+ interface RetryOptions {
926
+ /** Extra attempts per item after the first. Default 2. */
927
+ attempts?: number;
928
+ /** First pause, in milliseconds. Default 1000. */
929
+ baseDelayMs?: number;
930
+ /** Longest pause, in milliseconds. Default 30000. */
931
+ maxDelayMs?: number;
932
+ }
933
+ /** One item's outcome. `index` is its position in the input list. */
934
+ type CoerceManyResult<T> = {
935
+ ok: true;
936
+ index: number;
937
+ data: T;
938
+ /** Per-field provenance when `provenance` was requested, else empty. */
939
+ provenance: Record<string, FieldProvenance>;
940
+ /** Issues the `onInvalidField` policy absorbed for this item. */
941
+ issues: ResolvedIssue[];
942
+ /** How many provider calls it took, repairs excluded. */
943
+ attempts: number;
944
+ } | {
945
+ ok: false;
946
+ index: number;
947
+ error: unknown;
948
+ attempts: number;
949
+ };
950
+ /**
951
+ * Coerce many inputs against one schema.
952
+ *
953
+ * Runs at most `concurrency` items at a time, keeps results in input order,
954
+ * and never rejects as a whole: each item settles to an `ok` or an error of
955
+ * its own, so one bad listing cannot take down an import. Retryable provider
956
+ * errors pause the whole batch and try the item again; anything else, a
957
+ * `CoerceError` included, is that item's final answer.
958
+ */
959
+ declare function coerceMany<T>(inputs: readonly CoerceInput[], options: CoerceManyOptions): Promise<CoerceManyResult<T>[]>;
960
+
961
+ /**
962
+ * Build the input for a repair attempt: the original input (already rendered
963
+ * as delimited source blocks), the output that was rejected, and what was
964
+ * wrong with it. The correction sits outside the source blocks, where the
965
+ * system prompt says instructions live.
966
+ *
967
+ * The `Provider` interface is single-turn, so the correction has to travel as
968
+ * user text rather than as a real assistant turn. In practice that reads to
969
+ * the model the same way, and it keeps repair working on every provider
970
+ * without widening the provider contract. Exported so a caller who wants
971
+ * different wording can build their own and call the provider directly.
972
+ */
973
+ declare function buildRepairInput(originalInput: string, rejected: Record<string, unknown>, issues: FieldValidationIssue[]): string;
974
+
975
+ /**
976
+ * Configuration options shared by global and per-call config.
977
+ */
978
+ interface SemblGlobalConfig {
979
+ /** The LLM provider to use */
980
+ provider?: Provider;
981
+ /** Optional bundle for resolving nested schemas */
982
+ bundle?: SchemaBundle;
983
+ /** Optional resolver for @ValuesFrom enum sources */
984
+ enumResolver?: EnumResolver;
985
+ /** Optional trace sinks */
986
+ traceSinks?: TraceSink[];
987
+ /** How many times to send validation failures back for correction. Default 0. */
988
+ maxRepairAttempts?: number;
989
+ /** What to do with a present field that fails validation. Default "throw". */
990
+ onInvalidField?: InvalidFieldPolicy;
991
+ /** Cap on total source characters sent to the model. Unbounded by default. */
992
+ maxInputChars?: number;
993
+ /** Which part of an over-budget source to cut. Default "tail". */
994
+ truncate?: TruncatePolicy;
995
+ /** Transform each source before budgeting and rendering. */
996
+ preprocess?: PreprocessSource;
997
+ }
998
+ /**
999
+ * Per-call configuration overrides passed to `sembl()`.
1000
+ */
1001
+ interface SemblCallConfig {
1002
+ /** Override the LLM provider for this call */
1003
+ provider?: Provider;
1004
+ /** Override the bundle for this call */
1005
+ bundle?: SchemaBundle;
1006
+ /** Override the enum source resolver for this call */
1007
+ enumResolver?: EnumResolver;
1008
+ /** Override trace sinks for this call */
1009
+ traceSinks?: TraceSink[];
1010
+ /** Override the repair attempt budget for this call */
1011
+ maxRepairAttempts?: number;
1012
+ /** Override the invalid-field policy for this call */
1013
+ onInvalidField?: InvalidFieldPolicy;
1014
+ /** Override the input character budget for this call */
1015
+ maxInputChars?: number;
1016
+ /** Override the truncation policy for this call */
1017
+ truncate?: TruncatePolicy;
1018
+ /** Override the source preprocessor for this call */
1019
+ preprocess?: PreprocessSource;
1020
+ }
1021
+ /**
1022
+ * Resolved configuration with a guaranteed provider.
1023
+ */
1024
+ interface ResolvedConfig {
1025
+ provider: Provider;
1026
+ bundle?: SchemaBundle;
1027
+ enumResolver?: EnumResolver;
1028
+ traceSinks?: TraceSink[];
1029
+ maxRepairAttempts?: number;
1030
+ onInvalidField?: InvalidFieldPolicy;
1031
+ maxInputChars?: number;
1032
+ truncate?: TruncatePolicy;
1033
+ preprocess?: PreprocessSource;
1034
+ }
1035
+ /**
1036
+ * Global configuration singleton for SEMBL.
1037
+ */
1038
+ declare class SemblConfig {
1039
+ private static _config;
1040
+ /** Set global defaults. */
1041
+ static configure(config: SemblGlobalConfig): void;
1042
+ /** Reset global config to empty (useful in tests). */
1043
+ static reset(): void;
1044
+ /** Read-only access to the current global config. */
1045
+ static get current(): Readonly<SemblGlobalConfig>;
1046
+ }
1047
+
1048
+ /**
1049
+ * A chainable, thenable wrapper around coercion results.
1050
+ *
1051
+ * Each `.coerceTo()` / `.partialCoerceTo()` call eagerly triggers an LLM call,
1052
+ * serializing the previous result as the input string for the next step.
1053
+ *
1054
+ * Implements `PromiseLike<T>` so it can be `await`ed directly.
1055
+ *
1056
+ * There is no provenance variant here: an intermediate link's annotations
1057
+ * would be serialized into the next call's input and lost, and a terminal one
1058
+ * would have to return a different shape than every other link. Use
1059
+ * `coerceWithProvenance` / `partialCoerceWithProvenance` directly instead.
1060
+ */
1061
+ declare class Coercible<T> implements PromiseLike<T> {
1062
+ private readonly _promise;
1063
+ private readonly _config;
1064
+ /**
1065
+ * Whether the promise holds the caller's original input rather than a
1066
+ * coerced result. Only the first link does: it passes labelled sources
1067
+ * through untouched, whereas every later link serializes the previous
1068
+ * result — a result that merely looks like a source is still a result.
1069
+ */
1070
+ private readonly _holdsInput;
1071
+ constructor(_promise: Promise<T>, _config: ResolvedConfig,
1072
+ /**
1073
+ * Whether the promise holds the caller's original input rather than a
1074
+ * coerced result. Only the first link does: it passes labelled sources
1075
+ * through untouched, whereas every later link serializes the previous
1076
+ * result — a result that merely looks like a source is still a result.
1077
+ */
1078
+ _holdsInput?: boolean);
1079
+ /** What the next link should send as its input. */
1080
+ private _inputFrom;
1081
+ /** The per-call options every link in the chain shares. */
1082
+ private _optionsFor;
1083
+ /**
1084
+ * Chain a full coercion to a new schema.
1085
+ * The current value is serialized and used as input for the next LLM call.
1086
+ */
1087
+ coerceTo<U>(schema: RuntimeSchema): Coercible<U>;
1088
+ /**
1089
+ * Chain a partial coercion to a new schema.
1090
+ * The current value is serialized and used as input for the next LLM call.
1091
+ */
1092
+ partialCoerceTo<U>(schema: RuntimeSchema): Coercible<Partial<U>>;
1093
+ then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
1094
+ catch<TResult = never>(onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null): Promise<T | TResult>;
1095
+ finally(onfinally?: (() => void) | null): Promise<T>;
1096
+ }
1097
+ /**
1098
+ * Entry point for the fluent coercion API.
1099
+ *
1100
+ * Accepts a string or object as input. Objects are JSON-serialized.
1101
+ * Returns a `Coercible<string>` that can be chained with `.coerceTo()` / `.partialCoerceTo()`.
1102
+ *
1103
+ * @example
1104
+ * ```ts
1105
+ * SemblConfig.configure({ provider, bundle });
1106
+ * const result = await sembl("some user input")
1107
+ * .partialCoerceTo(ProfileSchema)
1108
+ * .coerceTo(IntentSchema);
1109
+ * ```
1110
+ */
1111
+ declare function sembl(input: CoerceInput | Record<string, unknown>, config?: SemblCallConfig): Coercible<CoerceInput>;
1112
+
1113
+ /**
1114
+ * Options for prompt generation.
1115
+ */
1116
+ interface PromptOptions {
1117
+ /** Legal values for dynamic enum sources, from `resolveEnumSources` */
1118
+ resolvedEnums?: ResolvedEnums;
1119
+ }
1120
+ /**
1121
+ * Build a system prompt that provides semantic context for the target schema.
1122
+ * This assembles the semantic hierarchy so the LLM understands the meaning
1123
+ * of each field in context.
1124
+ */
1125
+ declare function buildPrompt(schema: RuntimeSchema, bundle?: SchemaBundle, options?: PromptOptions): string;
1126
+
1127
+ /**
1128
+ * Options shared by both validation modes.
1129
+ */
1130
+ interface ValidationOptions {
1131
+ /** Legal values for dynamic enum sources, from `resolveEnumSources` */
1132
+ resolvedEnums?: ResolvedEnums;
1133
+ }
1134
+ /**
1135
+ * Validate data against a RuntimeSchema in strict mode.
1136
+ * All required fields must be present and correctly typed.
1137
+ * Returns validation issues (empty array means valid).
1138
+ */
1139
+ declare function validateStrict(data: Record<string, unknown>, schema: RuntimeSchema, bundle?: SchemaBundle, options?: ValidationOptions): FieldValidationIssue[];
1140
+ /**
1141
+ * Validate data against a RuntimeSchema in partial mode.
1142
+ * Only validates types of fields that ARE present; never fails for missing fields.
1143
+ * Returns validation issues (empty array means valid).
1144
+ */
1145
+ declare function validatePartial(data: Record<string, unknown>, schema: RuntimeSchema, bundle?: SchemaBundle, options?: ValidationOptions): FieldValidationIssue[];
1146
+
1147
+ /**
1148
+ * Tracer implementation that creates spans, records events, and dispatches to sinks.
1149
+ */
1150
+ declare class Tracer implements TraceContext {
1151
+ private sinks;
1152
+ constructor(sinks?: TraceSink[]);
1153
+ startSpan(name: string, attributes?: Record<string, unknown>, parent?: TraceSpan): TraceSpan;
1154
+ endSpan(span: TraceSpan): void;
1155
+ addEvent(span: TraceSpan, name: string, attributes?: Record<string, unknown>): void;
1156
+ }
1157
+
1158
+ /**
1159
+ * Default trace sink that writes spans to the console.
1160
+ */
1161
+ declare class ConsoleSink implements TraceSink {
1162
+ write(span: TraceSpan): void;
1163
+ }
1164
+
1165
+ export { type BudgetResult, CoerceError, type CoerceInput, type CoerceManyOptions, type CoerceManyResult, type CoerceOptions, Coercible, ConsoleSink, Constrain, type DeepPartial, type DefinedSchema, Describe, type EnumResolution, EnumResolutionError, type EnumResolver, type EnumSourceFailure, type EnumSourceUsage, type FieldBuilder, type FieldConfidence, type FieldConstraints, type FieldDescriptor, type FieldProvenance, type FieldType, type FieldValidationIssue, type Infer, type InferFields, type InvalidFieldPolicy, type IssueResolution, type JsonSchemaDialect, type JsonSchemaOptions, PROVENANCE_INSTRUCTIONS, type PreprocessSource, type PromptOptions, type ProvenanceOptions, type ProvenanceResult, type Provider, type ProviderConfig, type ProviderRequest, type ProviderResponse, type ProviderUsage, type ResolveIssuesOptions, type ResolveIssuesResult, type ResolvedEnums, type ResolvedIssue, type RetryOptions, type RuntimeSchema, SOURCE_INSTRUCTIONS, Schema, type SchemaBundle, SchemaRegistry, type SemblCallConfig, SemblConfig, type SemblGlobalConfig, type Source, type TraceContext, type TraceEvent, type TraceSink, type TraceSpan, Tracer, type TruncatePolicy, type TruncationRecord, type ValidationOptions, ValuesFrom, budgetSources, buildPrompt, buildRepairInput, bundleOf, coerce, coerceMany, coerceWithProvenance, collectEnumSources, defineSchema, field, isCoerceInput, isSource, partialCoerce, partialCoerceWithProvenance, provenanceInstructions, renderSources, resolveEnumSources, resolveIssues, runtimeSchemaToJsonSchema, sembl, splitProvenance, toOpenAIJsonSchema, toProvenanceSchema, toSources, validatePartial, validateStrict };