@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,742 @@
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
+ * Class decorator marking a schema class with a semantic description.
237
+ * No-op at runtime — parsed by the compiler from source AST.
238
+ */
239
+ declare function Schema(description: string): ClassDecorator;
240
+ /**
241
+ * Property decorator providing a field-level semantic description.
242
+ * No-op at runtime — parsed by the compiler from source AST.
243
+ */
244
+ declare function Describe(description: string): PropertyDecorator;
245
+ /**
246
+ * Property decorator bounding a field's legal values — lengths, numeric
247
+ * ranges, array sizes, a pattern.
248
+ *
249
+ * Takes an object literal of compile-time constants; the compiler reads it
250
+ * from source, so computed expressions are not supported.
251
+ *
252
+ * ```ts
253
+ * @Describe("Display name for the listing.")
254
+ * @Constrain({ maxLength: 40 })
255
+ * name!: string;
256
+ * ```
257
+ *
258
+ * No-op at runtime — parsed by the compiler from source AST.
259
+ */
260
+ declare function Constrain(constraints: FieldConstraints): PropertyDecorator;
261
+ /**
262
+ * Property decorator declaring that a field's legal values come from a named
263
+ * source resolved at coercion time rather than from the source tree — a CMS
264
+ * taxonomy, a database enum table.
265
+ *
266
+ * Applies to a string field or to the element type of a string array. The
267
+ * caller supplies an `EnumResolver` that maps `sourceId` to the legal values.
268
+ *
269
+ * ```ts
270
+ * @Describe("Amenities the property offers.")
271
+ * @ValuesFrom("amenities")
272
+ * amenities!: string[];
273
+ * ```
274
+ *
275
+ * No-op at runtime — parsed by the compiler from source AST.
276
+ */
277
+ declare function ValuesFrom(sourceId: string): PropertyDecorator;
278
+
279
+ /**
280
+ * Recursively makes all properties optional, including nested objects.
281
+ */
282
+ type DeepPartial<T> = {
283
+ [P in keyof T]?: T[P] extends (infer U)[] ? DeepPartial<U>[] : T[P] extends object ? DeepPartial<T[P]> : T[P];
284
+ };
285
+
286
+ /**
287
+ * Describes a single validation issue on a field.
288
+ */
289
+ interface FieldValidationIssue {
290
+ /** Dot-separated path to the field, e.g. "address.city" */
291
+ path: string;
292
+ /** What went wrong */
293
+ message: string;
294
+ /** The value that was received, if any */
295
+ received?: unknown;
296
+ }
297
+ /**
298
+ * Error thrown when coercion validation fails.
299
+ */
300
+ declare class CoerceError extends Error {
301
+ readonly issues: FieldValidationIssue[];
302
+ constructor(issues: FieldValidationIssue[]);
303
+ }
304
+
305
+ /**
306
+ * Error thrown when an enum source backing a required field could not be
307
+ * resolved.
308
+ *
309
+ * Falling back to a free-form string here would let the model invent values
310
+ * that pass coercion and fail downstream, so a required field with a dead
311
+ * taxonomy is a hard failure rather than a widening.
312
+ */
313
+ declare class EnumResolutionError extends Error {
314
+ readonly failures: EnumSourceFailure[];
315
+ constructor(failures: EnumSourceFailure[]);
316
+ }
317
+
318
+ /**
319
+ * Configuration for a provider.
320
+ */
321
+ interface ProviderConfig {
322
+ /** Model identifier, e.g. "gpt-4o" */
323
+ model: string;
324
+ /** Optional temperature override (0-2) */
325
+ temperature?: number;
326
+ /** Optional max tokens for the response */
327
+ maxTokens?: number;
328
+ }
329
+ /**
330
+ * Request sent to a provider for structured output.
331
+ */
332
+ interface ProviderRequest {
333
+ /** System prompt with semantic context */
334
+ systemPrompt: string;
335
+ /** User input to coerce */
336
+ userInput: string;
337
+ /** JSON Schema for structured output */
338
+ jsonSchema: Record<string, unknown>;
339
+ /** The runtime schema being targeted */
340
+ schema: RuntimeSchema;
341
+ /**
342
+ * Bundle used to resolve nested schemas, when one was supplied.
343
+ *
344
+ * `jsonSchema` above is already built against this bundle in the
345
+ * OpenAI-strict dialect. Providers whose API wants a different dialect
346
+ * should re-derive from `schema` + `bundle` rather than reaching for
347
+ * `schema` alone — dropping the bundle silently emits nested objects with
348
+ * no properties.
349
+ */
350
+ bundle?: SchemaBundle;
351
+ /**
352
+ * Legal values for the schema's `dynamicEnum` sources, already resolved.
353
+ * A provider that re-derives its own JSON Schema must pass these along —
354
+ * dropping them silently widens those fields back to free-form strings.
355
+ */
356
+ resolvedEnums?: ResolvedEnums;
357
+ }
358
+ /**
359
+ * Token accounting for a single provider call.
360
+ *
361
+ * The cache fields are reported as the provider reports them, and providers
362
+ * disagree about whether cached tokens also appear in `promptTokens` — so read
363
+ * them as an effectiveness signal, not as terms to add up. Each provider's
364
+ * README states which convention it follows.
365
+ */
366
+ interface ProviderUsage {
367
+ /** Input tokens, as the provider counts them. */
368
+ promptTokens: number;
369
+ /** Output tokens generated. */
370
+ completionTokens: number;
371
+ /** `promptTokens + completionTokens`. */
372
+ totalTokens: number;
373
+ /**
374
+ * Input tokens served from a prompt cache, when the provider reports it.
375
+ * Growing to cover the stable prefix across a batch is the signal that
376
+ * caching is working; a run of zeroes means it is not.
377
+ */
378
+ cacheReadTokens?: number;
379
+ /**
380
+ * Input tokens written to a prompt cache, when the provider reports it.
381
+ * Expect this on the first call of a batch and near zero afterwards; a
382
+ * write on every call means the cached prefix is being invalidated.
383
+ */
384
+ cacheWriteTokens?: number;
385
+ }
386
+ /**
387
+ * Response from a provider.
388
+ */
389
+ interface ProviderResponse {
390
+ /** The parsed structured output */
391
+ data: Record<string, unknown>;
392
+ /** Raw response metadata for tracing */
393
+ usage?: ProviderUsage;
394
+ }
395
+ /**
396
+ * Interface that LLM providers must implement.
397
+ */
398
+ interface Provider {
399
+ /**
400
+ * Send a structured output request to the LLM.
401
+ */
402
+ complete(request: ProviderRequest): Promise<ProviderResponse>;
403
+ }
404
+
405
+ /**
406
+ * A discrete event within a trace span.
407
+ */
408
+ interface TraceEvent {
409
+ /** Event name */
410
+ name: string;
411
+ /** Timestamp */
412
+ timestamp: number;
413
+ /** Arbitrary attributes */
414
+ attributes?: Record<string, unknown>;
415
+ }
416
+ /**
417
+ * A span representing a unit of work in the coercion pipeline.
418
+ */
419
+ interface TraceSpan {
420
+ /** Unique span ID */
421
+ id: string;
422
+ /** Human-readable name */
423
+ name: string;
424
+ /** Start timestamp */
425
+ startTime: number;
426
+ /** End timestamp (set when span completes) */
427
+ endTime?: number;
428
+ /** Events recorded during this span */
429
+ events: TraceEvent[];
430
+ /** Arbitrary attributes */
431
+ attributes?: Record<string, unknown>;
432
+ /** Parent span ID, if nested */
433
+ parentId?: string;
434
+ }
435
+ /**
436
+ * Sink that receives completed trace spans.
437
+ */
438
+ interface TraceSink {
439
+ /** Called when a span is completed */
440
+ write(span: TraceSpan): void;
441
+ }
442
+ /**
443
+ * Context for tracing within a coercion call.
444
+ */
445
+ interface TraceContext {
446
+ /** Start a new span */
447
+ startSpan(name: string, attributes?: Record<string, unknown>): TraceSpan;
448
+ /** End a span and dispatch to sinks */
449
+ endSpan(span: TraceSpan): void;
450
+ /** Add an event to the current span */
451
+ addEvent(span: TraceSpan, name: string, attributes?: Record<string, unknown>): void;
452
+ }
453
+
454
+ /**
455
+ * How well the input supported a value.
456
+ *
457
+ * A three-level scale rather than a number: models are poorly calibrated at
458
+ * producing a 0–1 score, and a review UI only ever needs to decide whether to
459
+ * flag a field for a human anyway.
460
+ */
461
+ type FieldConfidence = "high" | "medium" | "low";
462
+ /** Where a coerced field's value came from. */
463
+ interface FieldProvenance {
464
+ /** How well the input supported this value. */
465
+ confidence: FieldConfidence;
466
+ /**
467
+ * The span of input the value was read from, quoted. Absent when the value
468
+ * was inferred rather than read — which is itself the signal worth showing.
469
+ */
470
+ evidence?: string;
471
+ }
472
+ /** A coercion result paired with per-field provenance. */
473
+ interface ProvenanceResult<T> {
474
+ /** The coerced data, in the shape of the target schema. */
475
+ data: T;
476
+ /** Provenance for each top-level field the model returned, keyed by name. */
477
+ provenance: Record<string, FieldProvenance>;
478
+ }
479
+ /**
480
+ * Extra prompt guidance for a provenance run.
481
+ *
482
+ * The JSON Schema already forces the shape; what it cannot convey is how to
483
+ * judge confidence, which is the whole point of asking.
484
+ */
485
+ declare const PROVENANCE_INSTRUCTIONS: string;
486
+ /**
487
+ * Derive the schema to actually request when provenance is wanted: the same
488
+ * fields, each wrapped in `{ value, confidence, evidence }`.
489
+ *
490
+ * Only top-level fields are annotated. A nested object keeps its ordinary
491
+ * shape inside `value`, so provenance is reported for the object as a whole
492
+ * rather than per leaf — annotating every leaf multiplies both the schema and
493
+ * the output for detail a review UI rarely acts on.
494
+ *
495
+ * Returns a bundle carrying the wrapper, the per-field annotation schemas, and
496
+ * everything the original bundle held, so nested types still inline.
497
+ */
498
+ declare function toProvenanceSchema(schema: RuntimeSchema, bundle?: SchemaBundle): {
499
+ schema: RuntimeSchema;
500
+ bundle: SchemaBundle;
501
+ };
502
+ /**
503
+ * Split a provenance-shaped response back into plain data and per-field
504
+ * provenance.
505
+ *
506
+ * A field the model returned unwrapped — or wrapped without a usable
507
+ * `confidence` — still yields its value; the provenance is simply not
508
+ * recorded. Losing an annotation is not a reason to lose the extraction, and
509
+ * the missing key is visible to the caller.
510
+ */
511
+ declare function splitProvenance(response: Record<string, unknown>, schema: RuntimeSchema): {
512
+ data: Record<string, unknown>;
513
+ provenance: Record<string, FieldProvenance>;
514
+ };
515
+
516
+ /**
517
+ * Options for coerce and partialCoerce.
518
+ */
519
+ interface CoerceOptions {
520
+ /** The LLM provider to use */
521
+ provider: Provider;
522
+ /** The target schema */
523
+ schema: RuntimeSchema;
524
+ /** Optional bundle for resolving nested schemas */
525
+ bundle?: SchemaBundle;
526
+ /** Optional resolver for @ValuesFrom enum sources */
527
+ enumResolver?: EnumResolver;
528
+ /** Optional trace sinks */
529
+ traceSinks?: TraceSink[];
530
+ /**
531
+ * How many times to send validation failures back to the model for
532
+ * correction before giving up. Defaults to 0 — no repair.
533
+ *
534
+ * A repair costs an extra call only when validation actually failed, so the
535
+ * happy path is unaffected. It is off by default because it also multiplies
536
+ * worst-case latency, which a caller should opt into knowingly. For
537
+ * extraction from messy input — scraped HTML, third-party payloads — 1 is
538
+ * usually the right setting.
539
+ */
540
+ maxRepairAttempts?: number;
541
+ }
542
+ /**
543
+ * Coerce user input into a fully validated instance of the target schema.
544
+ * Throws CoerceError if validation fails (required fields missing, type
545
+ * mismatches, constraint violations, values outside a resolved taxonomy).
546
+ * Throws EnumResolutionError if a required field's enum source cannot be resolved.
547
+ */
548
+ declare function coerce<T>(input: string, options: CoerceOptions): Promise<T>;
549
+ /**
550
+ * Coerce user input into a partial instance of the target schema.
551
+ * Only validates types of fields that are present; never throws for missing fields.
552
+ * Throws CoerceError only if present fields have type mismatches or violate
553
+ * their constraints, and EnumResolutionError if a required field's enum source
554
+ * cannot be resolved.
555
+ */
556
+ declare function partialCoerce<T>(input: string, options: CoerceOptions): Promise<Partial<T>>;
557
+ /**
558
+ * Like {@link coerce}, but each field also comes back with how well the input
559
+ * supported it and the text it was read from.
560
+ *
561
+ * Costs a larger schema and a longer response, so reach for it where a human
562
+ * reviews the result — a pre-filled form that should flag its guesses — rather
563
+ * than on a hot path.
564
+ */
565
+ declare function coerceWithProvenance<T>(input: string, options: CoerceOptions): Promise<ProvenanceResult<T>>;
566
+ /**
567
+ * Like {@link partialCoerce}, but each field also comes back with how well the
568
+ * input supported it and the text it was read from.
569
+ *
570
+ * This is the one a form pre-fill usually wants: fields the input never
571
+ * mentioned are simply absent, and the ones that are present say how much to
572
+ * trust them.
573
+ */
574
+ declare function partialCoerceWithProvenance<T>(input: string, options: CoerceOptions): Promise<ProvenanceResult<Partial<T>>>;
575
+
576
+ /**
577
+ * Build the input for a repair attempt: the original input, the output that
578
+ * was rejected, and what was wrong with it.
579
+ *
580
+ * The `Provider` interface is single-turn, so the correction has to travel as
581
+ * user text rather than as a real assistant turn. In practice that reads to
582
+ * the model the same way, and it keeps repair working on every provider
583
+ * without widening the provider contract. Exported so a caller who wants
584
+ * different wording can build their own and call the provider directly.
585
+ */
586
+ declare function buildRepairInput(originalInput: string, rejected: Record<string, unknown>, issues: FieldValidationIssue[]): string;
587
+
588
+ /**
589
+ * Configuration options shared by global and per-call config.
590
+ */
591
+ interface SemblGlobalConfig {
592
+ /** The LLM provider to use */
593
+ provider?: Provider;
594
+ /** Optional bundle for resolving nested schemas */
595
+ bundle?: SchemaBundle;
596
+ /** Optional resolver for @ValuesFrom enum sources */
597
+ enumResolver?: EnumResolver;
598
+ /** Optional trace sinks */
599
+ traceSinks?: TraceSink[];
600
+ /** How many times to send validation failures back for correction. Default 0. */
601
+ maxRepairAttempts?: number;
602
+ }
603
+ /**
604
+ * Per-call configuration overrides passed to `sembl()`.
605
+ */
606
+ interface SemblCallConfig {
607
+ /** Override the LLM provider for this call */
608
+ provider?: Provider;
609
+ /** Override the bundle for this call */
610
+ bundle?: SchemaBundle;
611
+ /** Override the enum source resolver for this call */
612
+ enumResolver?: EnumResolver;
613
+ /** Override trace sinks for this call */
614
+ traceSinks?: TraceSink[];
615
+ /** Override the repair attempt budget for this call */
616
+ maxRepairAttempts?: number;
617
+ }
618
+ /**
619
+ * Resolved configuration with a guaranteed provider.
620
+ */
621
+ interface ResolvedConfig {
622
+ provider: Provider;
623
+ bundle?: SchemaBundle;
624
+ enumResolver?: EnumResolver;
625
+ traceSinks?: TraceSink[];
626
+ maxRepairAttempts?: number;
627
+ }
628
+ /**
629
+ * Global configuration singleton for SEMBL.
630
+ */
631
+ declare class SemblConfig {
632
+ private static _config;
633
+ /** Set global defaults. */
634
+ static configure(config: SemblGlobalConfig): void;
635
+ /** Reset global config to empty (useful in tests). */
636
+ static reset(): void;
637
+ /** Read-only access to the current global config. */
638
+ static get current(): Readonly<SemblGlobalConfig>;
639
+ }
640
+
641
+ /**
642
+ * A chainable, thenable wrapper around coercion results.
643
+ *
644
+ * Each `.coerceTo()` / `.partialCoerceTo()` call eagerly triggers an LLM call,
645
+ * serializing the previous result as the input string for the next step.
646
+ *
647
+ * Implements `PromiseLike<T>` so it can be `await`ed directly.
648
+ *
649
+ * There is no provenance variant here: an intermediate link's annotations
650
+ * would be serialized into the next call's input and lost, and a terminal one
651
+ * would have to return a different shape than every other link. Use
652
+ * `coerceWithProvenance` / `partialCoerceWithProvenance` directly instead.
653
+ */
654
+ declare class Coercible<T> implements PromiseLike<T> {
655
+ private readonly _promise;
656
+ private readonly _config;
657
+ constructor(_promise: Promise<T>, _config: ResolvedConfig);
658
+ /** The per-call options every link in the chain shares. */
659
+ private _optionsFor;
660
+ /**
661
+ * Chain a full coercion to a new schema.
662
+ * The current value is serialized and used as input for the next LLM call.
663
+ */
664
+ coerceTo<U>(schema: RuntimeSchema): Coercible<U>;
665
+ /**
666
+ * Chain a partial coercion to a new schema.
667
+ * The current value is serialized and used as input for the next LLM call.
668
+ */
669
+ partialCoerceTo<U>(schema: RuntimeSchema): Coercible<Partial<U>>;
670
+ then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
671
+ catch<TResult = never>(onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null): Promise<T | TResult>;
672
+ finally(onfinally?: (() => void) | null): Promise<T>;
673
+ }
674
+ /**
675
+ * Entry point for the fluent coercion API.
676
+ *
677
+ * Accepts a string or object as input. Objects are JSON-serialized.
678
+ * Returns a `Coercible<string>` that can be chained with `.coerceTo()` / `.partialCoerceTo()`.
679
+ *
680
+ * @example
681
+ * ```ts
682
+ * SemblConfig.configure({ provider, bundle });
683
+ * const result = await sembl("some user input")
684
+ * .partialCoerceTo(ProfileSchema)
685
+ * .coerceTo(IntentSchema);
686
+ * ```
687
+ */
688
+ declare function sembl(input: string | Record<string, unknown>, config?: SemblCallConfig): Coercible<string>;
689
+
690
+ /**
691
+ * Options for prompt generation.
692
+ */
693
+ interface PromptOptions {
694
+ /** Legal values for dynamic enum sources, from `resolveEnumSources` */
695
+ resolvedEnums?: ResolvedEnums;
696
+ }
697
+ /**
698
+ * Build a system prompt that provides semantic context for the target schema.
699
+ * This assembles the semantic hierarchy so the LLM understands the meaning
700
+ * of each field in context.
701
+ */
702
+ declare function buildPrompt(schema: RuntimeSchema, bundle?: SchemaBundle, options?: PromptOptions): string;
703
+
704
+ /**
705
+ * Options shared by both validation modes.
706
+ */
707
+ interface ValidationOptions {
708
+ /** Legal values for dynamic enum sources, from `resolveEnumSources` */
709
+ resolvedEnums?: ResolvedEnums;
710
+ }
711
+ /**
712
+ * Validate data against a RuntimeSchema in strict mode.
713
+ * All required fields must be present and correctly typed.
714
+ * Returns validation issues (empty array means valid).
715
+ */
716
+ declare function validateStrict(data: Record<string, unknown>, schema: RuntimeSchema, bundle?: SchemaBundle, options?: ValidationOptions): FieldValidationIssue[];
717
+ /**
718
+ * Validate data against a RuntimeSchema in partial mode.
719
+ * Only validates types of fields that ARE present; never fails for missing fields.
720
+ * Returns validation issues (empty array means valid).
721
+ */
722
+ declare function validatePartial(data: Record<string, unknown>, schema: RuntimeSchema, bundle?: SchemaBundle, options?: ValidationOptions): FieldValidationIssue[];
723
+
724
+ /**
725
+ * Tracer implementation that creates spans, records events, and dispatches to sinks.
726
+ */
727
+ declare class Tracer implements TraceContext {
728
+ private sinks;
729
+ constructor(sinks?: TraceSink[]);
730
+ startSpan(name: string, attributes?: Record<string, unknown>, parent?: TraceSpan): TraceSpan;
731
+ endSpan(span: TraceSpan): void;
732
+ addEvent(span: TraceSpan, name: string, attributes?: Record<string, unknown>): void;
733
+ }
734
+
735
+ /**
736
+ * Default trace sink that writes spans to the console.
737
+ */
738
+ declare class ConsoleSink implements TraceSink {
739
+ write(span: TraceSpan): void;
740
+ }
741
+
742
+ export { CoerceError, type CoerceOptions, Coercible, ConsoleSink, Constrain, type DeepPartial, Describe, type EnumResolution, EnumResolutionError, type EnumResolver, type EnumSourceFailure, type EnumSourceUsage, type FieldConfidence, type FieldConstraints, type FieldDescriptor, type FieldProvenance, type FieldType, type FieldValidationIssue, type JsonSchemaDialect, type JsonSchemaOptions, PROVENANCE_INSTRUCTIONS, type PromptOptions, type ProvenanceResult, type Provider, type ProviderConfig, type ProviderRequest, type ProviderResponse, type ResolvedEnums, type RuntimeSchema, Schema, type SchemaBundle, SchemaRegistry, type SemblCallConfig, SemblConfig, type SemblGlobalConfig, type TraceContext, type TraceEvent, type TraceSink, type TraceSpan, Tracer, type ValidationOptions, ValuesFrom, buildPrompt, buildRepairInput, coerce, coerceWithProvenance, collectEnumSources, partialCoerce, partialCoerceWithProvenance, resolveEnumSources, runtimeSchemaToJsonSchema, sembl, splitProvenance, toOpenAIJsonSchema, toProvenanceSchema, validatePartial, validateStrict };