@sembl/core 0.3.0 → 0.4.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.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,37 @@
1
+ /**
2
+ * Named string formats a field can be constrained to.
3
+ *
4
+ * Each one is validated locally, described in the prompt, and — where JSON
5
+ * Schema has a matching keyword — emitted in the schema dialects that honour
6
+ * it. They exist for the fields every pipeline ends up normalising by hand:
7
+ * a country that came back as "United States", a state as "Calif.", a
8
+ * currency as "dollars".
9
+ *
10
+ * - `"url"` — an absolute http(s) URL.
11
+ * - `"email"` — one address, no display name.
12
+ * - `"date"` — a calendar date as `YYYY-MM-DD`.
13
+ * - `"datetime"` — an ISO 8601 timestamp, e.g. `2026-09-05T14:30:00Z`.
14
+ * - `"iso-country"` — an ISO 3166-1 alpha-2 code: `US`, `DE`, `PT`.
15
+ * - `"us-state"` — a two-letter USPS state code: `CA`, `NY`, `DC`, `PR`.
16
+ * - `"us-state-name"` — a state's full name: `California`, `New York`.
17
+ * - `"currency"` — an ISO 4217 code: `USD`, `EUR`, `GBP`.
18
+ */
19
+ type FieldFormat = "url" | "email" | "date" | "datetime" | "iso-country" | "us-state" | "us-state-name" | "currency";
20
+ declare const FIELD_FORMATS: readonly FieldFormat[];
21
+ /**
22
+ * Check a string against a format. Returns a message describing what was
23
+ * expected when the value does not conform, undefined when it does.
24
+ */
25
+ declare function validateFormat(value: string, format: FieldFormat): string | undefined;
26
+ /** The phrase the prompt uses to state a format. */
27
+ declare function describeFormat(format: FieldFormat): string;
28
+ /**
29
+ * JSON Schema keywords for a format, in the standard dialect. The four with
30
+ * a JSON Schema `format` of their own use it; the code formats state their
31
+ * shape as a pattern, since a `format` a validator does not know is ignored.
32
+ */
33
+ declare function formatToJsonSchema(format: FieldFormat): Record<string, unknown>;
34
+
1
35
  /**
2
36
  * Bounds a field's value beyond its type.
3
37
  *
@@ -7,6 +41,8 @@
7
41
  * each element, so `string[]` can carry both `maxItems` and `maxLength`.
8
42
  */
9
43
  interface FieldConstraints {
44
+ /** A named string format: `"url"`, `"date"`, `"iso-country"`, `"currency"`, … */
45
+ format?: FieldFormat;
10
46
  /** Maximum string length, inclusive */
11
47
  maxLength?: number;
12
48
  /** Minimum string length, inclusive */
@@ -571,6 +607,12 @@ interface Source {
571
607
  label?: string;
572
608
  /** The text itself. */
573
609
  text: string;
610
+ /**
611
+ * A cap on this source's own characters, applied before the coercion's
612
+ * total `maxInputChars`, so one huge page cannot starve the others. Cut
613
+ * with the coercion's `truncate` policy.
614
+ */
615
+ maxChars?: number;
574
616
  }
575
617
  /**
576
618
  * What a coercion accepts as input: a plain string, one labelled source, or
@@ -637,7 +679,9 @@ interface BudgetResult {
637
679
  /**
638
680
  * Fit a set of sources into a character budget.
639
681
  *
640
- * The budget covers the sources' text as a whole. When they exceed it, it is
682
+ * A source's own `maxChars` is applied first, on its own, so a page known to
683
+ * be huge can be capped without starving the sources beside it. Then the
684
+ * total budget, when there is one, covers the sources' text as a whole. When they exceed it, it is
641
685
  * shared out so that every source that fits within an equal share keeps all
642
686
  * of its text, and what those leave unused goes to the longer ones. A short
643
687
  * email next to a long scraped page is therefore never touched; the page
@@ -645,7 +689,7 @@ interface BudgetResult {
645
689
  * so the model knows the text is incomplete rather than reading a
646
690
  * mid-sentence stop as the end.
647
691
  */
648
- declare function budgetSources(sources: readonly Source[], maxChars: number, policy?: TruncatePolicy): BudgetResult;
692
+ declare function budgetSources(sources: readonly Source[], maxChars: number | undefined, policy?: TruncatePolicy): BudgetResult;
649
693
 
650
694
  /**
651
695
  * What to do with a present field that fails validation.
@@ -750,6 +794,8 @@ interface ProvenanceResult<T> {
750
794
  * default `"throw"` policy, or when the response validated cleanly.
751
795
  */
752
796
  issues: ResolvedIssue[];
797
+ /** Token usage summed over every call the coercion made. */
798
+ usage: CoerceUsage;
753
799
  }
754
800
  /**
755
801
  * Extra prompt guidance for a provenance run.
@@ -765,6 +811,13 @@ interface ProvenanceOptions {
765
811
  * Each annotation then also asks which source the value was read from.
766
812
  */
767
813
  sourceLabels?: readonly string[];
814
+ /**
815
+ * Only these top-level fields are wrapped; every other field comes back
816
+ * as a plain value with no provenance. Halves the output on schemas where
817
+ * a human reviews a handful of fields and code checks the rest. All
818
+ * fields when absent.
819
+ */
820
+ fields?: readonly string[];
768
821
  }
769
822
  /**
770
823
  * The provenance guidance for a run, extended with the source rule when the
@@ -836,6 +889,20 @@ interface CoerceOptions {
836
889
  * event.
837
890
  */
838
891
  onInvalidField?: InvalidFieldPolicy;
892
+ /**
893
+ * With `coerceWithProvenance` / `partialCoerceWithProvenance`: annotate only
894
+ * these top-level fields. The rest come back plain, which roughly halves
895
+ * the output when a human reviews a few fields and code checks the others.
896
+ * Ignored by the plain coercions.
897
+ */
898
+ provenanceFields?: readonly string[];
899
+ /**
900
+ * How many times to ask again when a non-empty input yields no fields at
901
+ * all. Default 0. A model occasionally answers `{}` for a page it could
902
+ * read; the retry tells it so and asks for every stated value. Counts
903
+ * separately from `maxRepairAttempts`.
904
+ */
905
+ retryOnEmpty?: number;
839
906
  /**
840
907
  * Extra guidance for this extraction that is not part of the schema: facts
841
908
  * about the source ("prices on this site are in cents"), context the model
@@ -869,6 +936,27 @@ interface CoerceOptions {
869
936
  }
870
937
  /** A hook applied to each source before it is budgeted and rendered. */
871
938
  type PreprocessSource = (source: Source, index: number) => Source | string | Promise<Source | string>;
939
+ /**
940
+ * Token accounting for a whole coercion, summed over every provider call it
941
+ * made — the first attempt, repairs, and empty-result retries.
942
+ */
943
+ interface CoerceUsage {
944
+ /** Provider calls made. */
945
+ calls: number;
946
+ promptTokens: number;
947
+ completionTokens: number;
948
+ totalTokens: number;
949
+ cacheReadTokens: number;
950
+ cacheWriteTokens: number;
951
+ }
952
+ /** The result of a detailed coercion: the data plus what it cost to get it. */
953
+ interface CoerceDetails<T> {
954
+ data: T;
955
+ /** Issues the `onInvalidField` policy absorbed. Empty under `"throw"`. */
956
+ issues: ResolvedIssue[];
957
+ /** Token usage summed over every call the coercion made. */
958
+ usage: CoerceUsage;
959
+ }
872
960
  /**
873
961
  * Coerce user input into a fully validated instance of the target schema.
874
962
  * Throws CoerceError if validation fails (required fields missing, type
@@ -884,6 +972,44 @@ declare function coerce<T>(input: CoerceInput, options: CoerceOptions): Promise<
884
972
  * cannot be resolved.
885
973
  */
886
974
  declare function partialCoerce<T>(input: CoerceInput, options: CoerceOptions): Promise<Partial<T>>;
975
+ /**
976
+ * Like {@link coerce}, but also returns the issues the `onInvalidField` policy
977
+ * absorbed and the token usage of every call made — without the cost of
978
+ * provenance. The one to use when a pipeline accounts for spend or shows
979
+ * dropped fields but never needs per-field confidence.
980
+ */
981
+ declare function coerceDetailed<T>(input: CoerceInput, options: CoerceOptions): Promise<CoerceDetails<T>>;
982
+ /** Like {@link partialCoerce}, with the issues and usage of {@link coerceDetailed}. */
983
+ declare function partialCoerceDetailed<T>(input: CoerceInput, options: CoerceOptions): Promise<CoerceDetails<Partial<T>>>;
984
+ /** What {@link primeCache} produced: a record that the prefix was sent once. */
985
+ interface PrimedPrefix {
986
+ schemaId: string;
987
+ mode: "coerce" | "partialCoerce";
988
+ provenance: boolean;
989
+ /** Usage of the warm-up call. `cacheWriteTokens` shows the prefix landed. */
990
+ usage: CoerceUsage;
991
+ primedAt: string;
992
+ }
993
+ /** Options for {@link primeCache}: the coercion options the batch will use. */
994
+ interface PrimeCacheOptions extends CoerceOptions {
995
+ mode?: "coerce" | "partialCoerce";
996
+ provenance?: boolean;
997
+ }
998
+ /**
999
+ * Send the stable prefix — system prompt and schema — once, ahead of a batch,
1000
+ * so a provider that caches it writes the cache before the batch starts.
1001
+ *
1002
+ * Meant to overlap the caller's own preparation: start it while fetching
1003
+ * pages, then pass the promise to `coerceMany` as `primed`. The batch then
1004
+ * fans out at once instead of running its first item alone. The warm-up
1005
+ * costs one call with a trivial input and a near-empty answer; the answer is
1006
+ * not validated and never returned.
1007
+ *
1008
+ * Only the prefix matters, so the same options the batch will use must be
1009
+ * passed — a different schema, mode, provenance setting or instructions is
1010
+ * a different prefix and warms nothing.
1011
+ */
1012
+ declare function primeCache(options: PrimeCacheOptions): Promise<PrimedPrefix>;
887
1013
  /**
888
1014
  * Like {@link coerce}, but each field also comes back with how well the input
889
1015
  * supported it and the text it was read from.
@@ -903,25 +1029,44 @@ declare function coerceWithProvenance<T>(input: CoerceInput, options: CoerceOpti
903
1029
  */
904
1030
  declare function partialCoerceWithProvenance<T>(input: CoerceInput, options: CoerceOptions): Promise<ProvenanceResult<Partial<T>>>;
905
1031
 
1032
+ /** What a batch accepts: an array, or anything that can be iterated, lazily or not. */
1033
+ type CoerceManyInputs = Iterable<CoerceInput> | AsyncIterable<CoerceInput>;
906
1034
  /** Options for {@link coerceMany}. Everything in `CoerceOptions` applies to each item. */
907
- interface CoerceManyOptions extends CoerceOptions {
1035
+ interface CoerceManyOptions<T = unknown> extends CoerceOptions {
908
1036
  /** How many items may be in flight at once. Default 4. */
909
1037
  concurrency?: number;
910
1038
  /** Which coercion to run per item. Default `"coerce"`. */
911
1039
  mode?: "coerce" | "partialCoerce";
912
- /** Ask for per-field provenance on every item. Default false. */
913
- provenance?: boolean;
914
1040
  /**
915
- * Run the first item alone before fanning out, so a provider that caches
916
- * the prompt prefix writes it once and every later item reads it. Costs
917
- * one item's latency up front; saves a cache write per concurrent worker.
918
- * Default true.
1041
+ * Ask for provenance on every item: `true` for every field, or the names
1042
+ * of the top-level fields to annotate. Default false.
1043
+ */
1044
+ provenance?: boolean | readonly string[];
1045
+ /**
1046
+ * How to warm a provider's prompt cache before fanning out, so the stable
1047
+ * prefix is written once and every item reads it.
1048
+ *
1049
+ * - `true` (default): run the first item alone, then fan out. No extra
1050
+ * call, but the batch waits for one full item.
1051
+ * - `"eager"`: send a warm-up call the moment the batch starts and fan out
1052
+ * as soon as it lands. One extra small call; no item waits on another.
1053
+ * The right choice when inputs stream in from an async iterable.
1054
+ * - `false`: fan out immediately.
1055
+ *
1056
+ * Ignored when `primed` is given.
1057
+ */
1058
+ primeCache?: boolean | "eager";
1059
+ /**
1060
+ * A prefix already warmed with {@link primeCache}, or the promise of one.
1061
+ * Start it while fetching inputs and hand it over here: the batch waits
1062
+ * for it (not for an item) and then fans out. A warm-up that fails is
1063
+ * traced and otherwise ignored — the batch runs, only colder.
919
1064
  */
920
- primeCache?: boolean;
1065
+ primed?: PrimedPrefix | Promise<PrimedPrefix>;
921
1066
  /** How the batch backs off when the provider pushes back. */
922
1067
  retry?: RetryOptions;
923
1068
  /** Called as each item settles, in completion order, for progress. */
924
- onItem?: (result: CoerceManyResult<unknown>) => void;
1069
+ onItem?: (result: CoerceManyResult<T>) => void;
925
1070
  /** Stop starting new items; those not yet started fail with the reason. */
926
1071
  signal?: AbortSignal;
927
1072
  }
@@ -943,7 +1088,7 @@ interface RetryOptions {
943
1088
  /** Longest pause, in milliseconds. Default 30000. */
944
1089
  maxDelayMs?: number;
945
1090
  }
946
- /** One item's outcome. `index` is its position in the input list. */
1091
+ /** One item's outcome. `index` is its position in the input sequence. */
947
1092
  type CoerceManyResult<T> = {
948
1093
  ok: true;
949
1094
  index: number;
@@ -952,12 +1097,16 @@ type CoerceManyResult<T> = {
952
1097
  provenance: Record<string, FieldProvenance>;
953
1098
  /** Issues the `onInvalidField` policy absorbed for this item. */
954
1099
  issues: ResolvedIssue[];
955
- /** How many provider calls it took, repairs excluded. */
1100
+ /** Token usage over every call this item made, repairs included. */
1101
+ usage: CoerceUsage;
1102
+ /** How many times the item was started, retries included. */
956
1103
  attempts: number;
957
1104
  } | {
958
1105
  ok: false;
959
1106
  index: number;
960
1107
  error: unknown;
1108
+ /** Usage of the calls made before giving up. */
1109
+ usage: CoerceUsage;
961
1110
  attempts: number;
962
1111
  };
963
1112
  /**
@@ -968,8 +1117,13 @@ type CoerceManyResult<T> = {
968
1117
  * its own, so one bad listing cannot take down an import. Retryable provider
969
1118
  * errors pause the whole batch and try the item again; anything else, a
970
1119
  * `CoerceError` included, is that item's final answer.
1120
+ *
1121
+ * Inputs may be an array or any iterable, including an async one, so a
1122
+ * batch can start while its inputs are still being fetched. Every span an
1123
+ * item emits carries `itemIndex` (and `itemLabel` when the input is
1124
+ * labelled), so a trace sink can attribute usage under concurrency.
971
1125
  */
972
- declare function coerceMany<T>(inputs: readonly CoerceInput[], options: CoerceManyOptions): Promise<CoerceManyResult<T>[]>;
1126
+ declare function coerceMany<T>(inputs: CoerceManyInputs, options: CoerceManyOptions<T>): Promise<CoerceManyResult<T>[]>;
973
1127
 
974
1128
  /**
975
1129
  * Build the input for a repair attempt: the original input (already rendered
@@ -1003,6 +1157,8 @@ interface SemblGlobalConfig {
1003
1157
  onInvalidField?: InvalidFieldPolicy;
1004
1158
  /** Extra guidance rendered into every system prompt. */
1005
1159
  instructions?: string | readonly string[];
1160
+ /** Retries when a non-empty input yields no fields. Default 0. */
1161
+ retryOnEmpty?: number;
1006
1162
  /** Cap on total source characters sent to the model. Unbounded by default. */
1007
1163
  maxInputChars?: number;
1008
1164
  /** Which part of an over-budget source to cut. Default "tail". */
@@ -1028,6 +1184,8 @@ interface SemblCallConfig {
1028
1184
  onInvalidField?: InvalidFieldPolicy;
1029
1185
  /** Guidance for this call. Replaces, rather than extends, the global list. */
1030
1186
  instructions?: string | readonly string[];
1187
+ /** Override the empty-result retry budget for this call */
1188
+ retryOnEmpty?: number;
1031
1189
  /** Override the input character budget for this call */
1032
1190
  maxInputChars?: number;
1033
1191
  /** Override the truncation policy for this call */
@@ -1046,6 +1204,7 @@ interface ResolvedConfig {
1046
1204
  maxRepairAttempts?: number;
1047
1205
  onInvalidField?: InvalidFieldPolicy;
1048
1206
  instructions?: string | readonly string[];
1207
+ retryOnEmpty?: number;
1049
1208
  maxInputChars?: number;
1050
1209
  truncate?: TruncatePolicy;
1051
1210
  preprocess?: PreprocessSource;
@@ -1178,7 +1337,13 @@ declare function validatePartial(data: Record<string, unknown>, schema: RuntimeS
1178
1337
  */
1179
1338
  declare class Tracer implements TraceContext {
1180
1339
  private sinks;
1181
- constructor(sinks?: TraceSink[]);
1340
+ private readonly baseAttributes;
1341
+ /**
1342
+ * `baseAttributes` are merged into every span this tracer opens — how a
1343
+ * batch stamps `itemIndex` on the spans of each item, so a sink can tell
1344
+ * whose `llmCall` it is looking at under concurrency.
1345
+ */
1346
+ constructor(sinks?: TraceSink[], baseAttributes?: Record<string, unknown>);
1182
1347
  startSpan(name: string, attributes?: Record<string, unknown>, parent?: TraceSpan): TraceSpan;
1183
1348
  endSpan(span: TraceSpan): void;
1184
1349
  addEvent(span: TraceSpan, name: string, attributes?: Record<string, unknown>): void;
@@ -1191,4 +1356,4 @@ declare class ConsoleSink implements TraceSink {
1191
1356
  write(span: TraceSpan): void;
1192
1357
  }
1193
1358
 
1194
- 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, normalizeInstructions, partialCoerce, partialCoerceWithProvenance, provenanceInstructions, renderSources, resolveEnumSources, resolveIssues, runtimeSchemaToJsonSchema, sembl, splitProvenance, toOpenAIJsonSchema, toProvenanceSchema, toSources, validatePartial, validateStrict };
1359
+ export { type BudgetResult, type CoerceDetails, CoerceError, type CoerceInput, type CoerceManyOptions, type CoerceManyResult, type CoerceOptions, type CoerceUsage, Coercible, ConsoleSink, Constrain, type DeepPartial, type DefinedSchema, Describe, type EnumResolution, EnumResolutionError, type EnumResolver, type EnumSourceFailure, type EnumSourceUsage, FIELD_FORMATS, type FieldBuilder, type FieldConfidence, type FieldConstraints, type FieldDescriptor, type FieldFormat, type FieldProvenance, type FieldType, type FieldValidationIssue, type Infer, type InferFields, type InvalidFieldPolicy, type IssueResolution, type JsonSchemaDialect, type JsonSchemaOptions, PROVENANCE_INSTRUCTIONS, type PreprocessSource, type PrimeCacheOptions, type PrimedPrefix, 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, coerceDetailed, coerceMany, coerceWithProvenance, collectEnumSources, defineSchema, describeFormat, field, formatToJsonSchema, isCoerceInput, isSource, normalizeInstructions, partialCoerce, partialCoerceDetailed, partialCoerceWithProvenance, primeCache, provenanceInstructions, renderSources, resolveEnumSources, resolveIssues, runtimeSchemaToJsonSchema, sembl, splitProvenance, toOpenAIJsonSchema, toProvenanceSchema, toSources, validateFormat, validatePartial, validateStrict };