@sembl/core 0.2.1 → 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.cjs +459 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +210 -16
- package/dist/index.d.ts +210 -16
- package/dist/index.js +451 -68
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -26,6 +26,7 @@ __export(index_exports, {
|
|
|
26
26
|
Constrain: () => Constrain,
|
|
27
27
|
Describe: () => Describe,
|
|
28
28
|
EnumResolutionError: () => EnumResolutionError,
|
|
29
|
+
FIELD_FORMATS: () => FIELD_FORMATS,
|
|
29
30
|
PROVENANCE_INSTRUCTIONS: () => PROVENANCE_INSTRUCTIONS,
|
|
30
31
|
SOURCE_INSTRUCTIONS: () => SOURCE_INSTRUCTIONS,
|
|
31
32
|
Schema: () => Schema,
|
|
@@ -38,15 +39,21 @@ __export(index_exports, {
|
|
|
38
39
|
buildRepairInput: () => buildRepairInput,
|
|
39
40
|
bundleOf: () => bundleOf,
|
|
40
41
|
coerce: () => coerce,
|
|
42
|
+
coerceDetailed: () => coerceDetailed,
|
|
41
43
|
coerceMany: () => coerceMany,
|
|
42
44
|
coerceWithProvenance: () => coerceWithProvenance,
|
|
43
45
|
collectEnumSources: () => collectEnumSources,
|
|
44
46
|
defineSchema: () => defineSchema,
|
|
47
|
+
describeFormat: () => describeFormat,
|
|
45
48
|
field: () => field,
|
|
49
|
+
formatToJsonSchema: () => formatToJsonSchema,
|
|
46
50
|
isCoerceInput: () => isCoerceInput,
|
|
47
51
|
isSource: () => isSource,
|
|
52
|
+
normalizeInstructions: () => normalizeInstructions,
|
|
48
53
|
partialCoerce: () => partialCoerce,
|
|
54
|
+
partialCoerceDetailed: () => partialCoerceDetailed,
|
|
49
55
|
partialCoerceWithProvenance: () => partialCoerceWithProvenance,
|
|
56
|
+
primeCache: () => primeCache,
|
|
50
57
|
provenanceInstructions: () => provenanceInstructions,
|
|
51
58
|
renderSources: () => renderSources,
|
|
52
59
|
resolveEnumSources: () => resolveEnumSources,
|
|
@@ -57,11 +64,164 @@ __export(index_exports, {
|
|
|
57
64
|
toOpenAIJsonSchema: () => toOpenAIJsonSchema,
|
|
58
65
|
toProvenanceSchema: () => toProvenanceSchema,
|
|
59
66
|
toSources: () => toSources,
|
|
67
|
+
validateFormat: () => validateFormat,
|
|
60
68
|
validatePartial: () => validatePartial,
|
|
61
69
|
validateStrict: () => validateStrict
|
|
62
70
|
});
|
|
63
71
|
module.exports = __toCommonJS(index_exports);
|
|
64
72
|
|
|
73
|
+
// src/schema/formats.ts
|
|
74
|
+
var FIELD_FORMATS = [
|
|
75
|
+
"url",
|
|
76
|
+
"email",
|
|
77
|
+
"date",
|
|
78
|
+
"datetime",
|
|
79
|
+
"iso-country",
|
|
80
|
+
"us-state",
|
|
81
|
+
"us-state-name",
|
|
82
|
+
"currency"
|
|
83
|
+
];
|
|
84
|
+
var ISO_COUNTRIES = new Set(
|
|
85
|
+
"AD AE AF AG AI AL AM AO AQ AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ BL BM BN BO BQ BR BS BT BV BW BY BZ CA CC CD CF CG CH CI CK CL CM CN CO CR CU CV CW CX CY CZ DE DJ DK DM DO DZ EC EE EG EH ER ES ET FI FJ FK FM FO FR GA GB GD GE GF GG GH GI GL GM GN GP GQ GR GS GT GU GW GY HK HM HN HR HT HU ID IE IL IM IN IO IQ IR IS IT JE JM JO JP KE KG KH KI KM KN KP KR KW KY KZ LA LB LC LI LK LR LS LT LU LV LY MA MC MD ME MF MG MH MK ML MM MN MO MP MQ MR MS MT MU MV MW MX MY MZ NA NC NE NF NG NI NL NO NP NR NU NZ OM PA PE PF PG PH PK PL PM PN PR PS PT PW PY QA RE RO RS RU RW SA SB SC SD SE SG SH SI SJ SK SL SM SN SO SR SS ST SV SX SY SZ TC TD TF TG TH TJ TK TL TM TN TO TR TT TV TW TZ UA UG UM US UY UZ VA VC VE VG VI VN VU WF WS YE YT ZA ZM ZW".split(" ")
|
|
86
|
+
);
|
|
87
|
+
var US_STATES = {
|
|
88
|
+
AL: "Alabama",
|
|
89
|
+
AK: "Alaska",
|
|
90
|
+
AZ: "Arizona",
|
|
91
|
+
AR: "Arkansas",
|
|
92
|
+
CA: "California",
|
|
93
|
+
CO: "Colorado",
|
|
94
|
+
CT: "Connecticut",
|
|
95
|
+
DE: "Delaware",
|
|
96
|
+
FL: "Florida",
|
|
97
|
+
GA: "Georgia",
|
|
98
|
+
HI: "Hawaii",
|
|
99
|
+
ID: "Idaho",
|
|
100
|
+
IL: "Illinois",
|
|
101
|
+
IN: "Indiana",
|
|
102
|
+
IA: "Iowa",
|
|
103
|
+
KS: "Kansas",
|
|
104
|
+
KY: "Kentucky",
|
|
105
|
+
LA: "Louisiana",
|
|
106
|
+
ME: "Maine",
|
|
107
|
+
MD: "Maryland",
|
|
108
|
+
MA: "Massachusetts",
|
|
109
|
+
MI: "Michigan",
|
|
110
|
+
MN: "Minnesota",
|
|
111
|
+
MS: "Mississippi",
|
|
112
|
+
MO: "Missouri",
|
|
113
|
+
MT: "Montana",
|
|
114
|
+
NE: "Nebraska",
|
|
115
|
+
NV: "Nevada",
|
|
116
|
+
NH: "New Hampshire",
|
|
117
|
+
NJ: "New Jersey",
|
|
118
|
+
NM: "New Mexico",
|
|
119
|
+
NY: "New York",
|
|
120
|
+
NC: "North Carolina",
|
|
121
|
+
ND: "North Dakota",
|
|
122
|
+
OH: "Ohio",
|
|
123
|
+
OK: "Oklahoma",
|
|
124
|
+
OR: "Oregon",
|
|
125
|
+
PA: "Pennsylvania",
|
|
126
|
+
RI: "Rhode Island",
|
|
127
|
+
SC: "South Carolina",
|
|
128
|
+
SD: "South Dakota",
|
|
129
|
+
TN: "Tennessee",
|
|
130
|
+
TX: "Texas",
|
|
131
|
+
UT: "Utah",
|
|
132
|
+
VT: "Vermont",
|
|
133
|
+
VA: "Virginia",
|
|
134
|
+
WA: "Washington",
|
|
135
|
+
WV: "West Virginia",
|
|
136
|
+
WI: "Wisconsin",
|
|
137
|
+
WY: "Wyoming",
|
|
138
|
+
DC: "District of Columbia",
|
|
139
|
+
PR: "Puerto Rico",
|
|
140
|
+
GU: "Guam",
|
|
141
|
+
VI: "U.S. Virgin Islands",
|
|
142
|
+
AS: "American Samoa",
|
|
143
|
+
MP: "Northern Mariana Islands"
|
|
144
|
+
};
|
|
145
|
+
var US_STATE_NAMES = new Set(Object.values(US_STATES));
|
|
146
|
+
var CURRENCIES = new Set(
|
|
147
|
+
"AED AFN ALL AMD ANG AOA ARS AUD AWG AZN BAM BBD BDT BGN BHD BIF BMD BND BOB BRL BSD BTN BWP BYN BZD CAD CDF CHF CLP CNY COP CRC CUP CVE CZK DJF DKK DOP DZD EGP ERN ETB EUR FJD FKP GBP GEL GHS GIP GMD GNF GTQ GYD HKD HNL HTG HUF IDR ILS INR IQD IRR ISK JMD JOD JPY KES KGS KHR KMF KPW KRW KWD KYD KZT LAK LBP LKR LRD LSL LYD MAD MDL MGA MKD MMK MNT MOP MRU MUR MVR MWK MXN MYR MZN NAD NGN NIO NOK NPR NZD OMR PAB PEN PGK PHP PKR PLN PYG QAR RON RSD RUB RWF SAR SBD SCR SDG SEK SGD SHP SLE SOS SRD SSP STN SVC SYP SZL THB TJS TMT TND TOP TRY TTD TWD TZS UAH UGX USD UYU UZS VES VND VUV WST XAF XCD XOF XPF YER ZAR ZMW ZWG".split(" ")
|
|
148
|
+
);
|
|
149
|
+
var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
150
|
+
var DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
151
|
+
var DATETIME = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?$/;
|
|
152
|
+
function isCalendarDate(y, m, d) {
|
|
153
|
+
const date = new Date(Date.UTC(y, m - 1, d));
|
|
154
|
+
return date.getUTCFullYear() === y && date.getUTCMonth() === m - 1 && date.getUTCDate() === d;
|
|
155
|
+
}
|
|
156
|
+
function validateFormat(value, format) {
|
|
157
|
+
switch (format) {
|
|
158
|
+
case "url": {
|
|
159
|
+
try {
|
|
160
|
+
const url = new URL(value);
|
|
161
|
+
if (url.protocol === "http:" || url.protocol === "https:") return void 0;
|
|
162
|
+
} catch {
|
|
163
|
+
}
|
|
164
|
+
return `Expected an absolute http(s) URL, got ${JSON.stringify(value)}`;
|
|
165
|
+
}
|
|
166
|
+
case "email":
|
|
167
|
+
return EMAIL.test(value) ? void 0 : `Expected an email address, got ${JSON.stringify(value)}`;
|
|
168
|
+
case "date": {
|
|
169
|
+
const m = DATE.exec(value);
|
|
170
|
+
if (m && isCalendarDate(Number(m[1]), Number(m[2]), Number(m[3]))) return void 0;
|
|
171
|
+
return `Expected a calendar date as YYYY-MM-DD, got ${JSON.stringify(value)}`;
|
|
172
|
+
}
|
|
173
|
+
case "datetime":
|
|
174
|
+
return DATETIME.test(value) && !Number.isNaN(Date.parse(value)) ? void 0 : `Expected an ISO 8601 timestamp, got ${JSON.stringify(value)}`;
|
|
175
|
+
case "iso-country":
|
|
176
|
+
return ISO_COUNTRIES.has(value) ? void 0 : `Expected an ISO 3166-1 alpha-2 country code such as US or DE, got ${JSON.stringify(value)}`;
|
|
177
|
+
case "us-state":
|
|
178
|
+
return value in US_STATES ? void 0 : `Expected a two-letter USPS state code such as CA or NY, got ${JSON.stringify(value)}`;
|
|
179
|
+
case "us-state-name":
|
|
180
|
+
return US_STATE_NAMES.has(value) ? void 0 : `Expected a US state's full name such as California, got ${JSON.stringify(value)}`;
|
|
181
|
+
case "currency":
|
|
182
|
+
return CURRENCIES.has(value) ? void 0 : `Expected an ISO 4217 currency code such as USD or EUR, got ${JSON.stringify(value)}`;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function describeFormat(format) {
|
|
186
|
+
switch (format) {
|
|
187
|
+
case "url":
|
|
188
|
+
return "an absolute http(s) URL";
|
|
189
|
+
case "email":
|
|
190
|
+
return "an email address";
|
|
191
|
+
case "date":
|
|
192
|
+
return "a calendar date as YYYY-MM-DD";
|
|
193
|
+
case "datetime":
|
|
194
|
+
return "an ISO 8601 timestamp (e.g. 2026-09-05T14:30:00Z)";
|
|
195
|
+
case "iso-country":
|
|
196
|
+
return "an ISO 3166-1 alpha-2 country code (e.g. US, DE, PT), never a country name";
|
|
197
|
+
case "us-state":
|
|
198
|
+
return "a two-letter USPS state code (e.g. CA, NY), never the state's name";
|
|
199
|
+
case "us-state-name":
|
|
200
|
+
return "a US state's full name (e.g. California, New York), never its abbreviation";
|
|
201
|
+
case "currency":
|
|
202
|
+
return "an ISO 4217 currency code (e.g. USD, EUR, GBP), never a symbol or a word";
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function formatToJsonSchema(format) {
|
|
206
|
+
switch (format) {
|
|
207
|
+
case "url":
|
|
208
|
+
return { format: "uri" };
|
|
209
|
+
case "email":
|
|
210
|
+
return { format: "email" };
|
|
211
|
+
case "date":
|
|
212
|
+
return { format: "date" };
|
|
213
|
+
case "datetime":
|
|
214
|
+
return { format: "date-time" };
|
|
215
|
+
case "iso-country":
|
|
216
|
+
case "us-state":
|
|
217
|
+
return { pattern: "^[A-Z]{2}$" };
|
|
218
|
+
case "currency":
|
|
219
|
+
return { pattern: "^[A-Z]{3}$" };
|
|
220
|
+
case "us-state-name":
|
|
221
|
+
return {};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
65
225
|
// src/schema/json-schema.ts
|
|
66
226
|
var CONSTRAINT_KEYWORDS = [
|
|
67
227
|
"maxLength",
|
|
@@ -78,6 +238,9 @@ function constraintsToJsonSchema(constraints, dialect) {
|
|
|
78
238
|
return {};
|
|
79
239
|
}
|
|
80
240
|
const out = {};
|
|
241
|
+
if (constraints.format !== void 0) {
|
|
242
|
+
Object.assign(out, formatToJsonSchema(constraints.format));
|
|
243
|
+
}
|
|
81
244
|
for (const keyword of CONSTRAINT_KEYWORDS) {
|
|
82
245
|
const value = constraints[keyword];
|
|
83
246
|
if (value !== void 0) {
|
|
@@ -462,7 +625,7 @@ ${summary}`);
|
|
|
462
625
|
// src/coerce/sources.ts
|
|
463
626
|
var SOURCE_TAG = "source";
|
|
464
627
|
function isSource(value) {
|
|
465
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.text === "string" && (value.label === void 0 || typeof value.label === "string");
|
|
628
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.text === "string" && (value.label === void 0 || typeof value.label === "string") && (value.maxChars === void 0 || typeof value.maxChars === "number");
|
|
466
629
|
}
|
|
467
630
|
function isCoerceInput(value) {
|
|
468
631
|
return typeof value === "string" || isSource(value) || Array.isArray(value) && value.every(isSource);
|
|
@@ -482,7 +645,9 @@ function toSources(input) {
|
|
|
482
645
|
}
|
|
483
646
|
function cleanLabel(source) {
|
|
484
647
|
const label = source.label?.trim();
|
|
485
|
-
|
|
648
|
+
const cleaned = label ? { label, text: source.text } : { text: source.text };
|
|
649
|
+
if (source.maxChars !== void 0) cleaned.maxChars = source.maxChars;
|
|
650
|
+
return cleaned;
|
|
486
651
|
}
|
|
487
652
|
function escapeText(text) {
|
|
488
653
|
return text.replace(new RegExp(`</(\\s*${SOURCE_TAG}\\b)`, "gi"), "<\\/$1");
|
|
@@ -507,12 +672,23 @@ var SOURCE_INSTRUCTIONS = [
|
|
|
507
672
|
].join("\n");
|
|
508
673
|
|
|
509
674
|
// src/coerce/prompt-builder.ts
|
|
675
|
+
function normalizeInstructions(instructions) {
|
|
676
|
+
if (instructions === void 0) return [];
|
|
677
|
+
const list = typeof instructions === "string" ? [instructions] : instructions;
|
|
678
|
+
if (!Array.isArray(list) || list.some((entry) => typeof entry !== "string")) {
|
|
679
|
+
throw new RangeError("instructions must be a string or an array of strings");
|
|
680
|
+
}
|
|
681
|
+
return list.map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
682
|
+
}
|
|
510
683
|
function describeConstraints(constraints) {
|
|
511
684
|
if (!constraints) {
|
|
512
685
|
return [];
|
|
513
686
|
}
|
|
514
687
|
const phrases = [];
|
|
515
|
-
const { minLength, maxLength, minimum, maximum, minItems, maxItems, pattern } = constraints;
|
|
688
|
+
const { minLength, maxLength, minimum, maximum, minItems, maxItems, pattern, format } = constraints;
|
|
689
|
+
if (format !== void 0) {
|
|
690
|
+
phrases.push(describeFormat(format));
|
|
691
|
+
}
|
|
516
692
|
if (minLength !== void 0 && maxLength !== void 0) {
|
|
517
693
|
phrases.push(`between ${minLength} and ${maxLength} characters`);
|
|
518
694
|
} else if (maxLength !== void 0) {
|
|
@@ -625,10 +801,20 @@ function buildPrompt(schema, bundle, options = {}) {
|
|
|
625
801
|
lines.push("Instructions:");
|
|
626
802
|
lines.push("- Extract values from the sources that match the schema fields.");
|
|
627
803
|
lines.push("- Use null for optional fields that cannot be determined from the input.");
|
|
804
|
+
lines.push("- A value the input states is never omitted because it looks like a default: return 1, 0, false or an empty list when that is what the input says.");
|
|
805
|
+
lines.push("- Never return an empty object when the input states values for any field.");
|
|
628
806
|
lines.push("- Required fields must always have a valid, non-null value.");
|
|
629
807
|
lines.push("- Interpret the user's input semantically \u2014 infer meaning, don't just pattern match.");
|
|
630
808
|
lines.push("- Respect every stated limit exactly; truncate or drop lower-priority content to stay within it.");
|
|
631
809
|
lines.push("- Return only the structured JSON output matching the schema.");
|
|
810
|
+
const instructions = normalizeInstructions(options.instructions);
|
|
811
|
+
if (instructions.length > 0) {
|
|
812
|
+
lines.push("");
|
|
813
|
+
lines.push("Additional guidance for this extraction:");
|
|
814
|
+
for (const instruction of instructions) {
|
|
815
|
+
lines.push(`- ${instruction}`);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
632
818
|
return lines.join("\n");
|
|
633
819
|
}
|
|
634
820
|
|
|
@@ -682,11 +868,31 @@ var PROVENANCE_INSTRUCTIONS = [
|
|
|
682
868
|
"- Judge each field on its own. A confident value next to a guessed one is",
|
|
683
869
|
" normal, and marking the guess honestly is more useful than looking sure."
|
|
684
870
|
].join("\n");
|
|
871
|
+
function provenanceFieldNames(schema, fields) {
|
|
872
|
+
if (fields === void 0) return new Set(schema.fields.map((f) => f.name));
|
|
873
|
+
const known = new Set(schema.fields.map((f) => f.name));
|
|
874
|
+
for (const name of fields) {
|
|
875
|
+
if (!known.has(name)) {
|
|
876
|
+
throw new RangeError(
|
|
877
|
+
`provenance field "${name}" is not a field of schema "${schema.id}" (fields: ${[...known].join(", ")})`
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
return new Set(fields);
|
|
882
|
+
}
|
|
685
883
|
function provenanceInstructions(options = {}) {
|
|
686
884
|
const labels = options.sourceLabels ?? [];
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
885
|
+
let text = PROVENANCE_INSTRUCTIONS;
|
|
886
|
+
if (options.fields !== void 0) {
|
|
887
|
+
text = text.replace(
|
|
888
|
+
"- Every field is wrapped as an object: put the extracted value in `value`.",
|
|
889
|
+
`- Only these fields are wrapped as objects, with the extracted value in \`value\`: ${options.fields.join(", ")}. Every other field is a plain value.`
|
|
890
|
+
);
|
|
891
|
+
}
|
|
892
|
+
if (labels.length >= 2) {
|
|
893
|
+
text += "\n- Always set `source` to the label of the source the value was read from. When several agree, name the one quoted in `evidence`.";
|
|
894
|
+
}
|
|
895
|
+
return text;
|
|
690
896
|
}
|
|
691
897
|
function annotationSchema(parentId, field2, sourceLabels) {
|
|
692
898
|
const valueField = {
|
|
@@ -718,7 +924,7 @@ function annotationSchema(parentId, field2, sourceLabels) {
|
|
|
718
924
|
name: "source",
|
|
719
925
|
description: "The label of the source this value was read from.",
|
|
720
926
|
type: { kind: "enum", values: [...sourceLabels] },
|
|
721
|
-
required:
|
|
927
|
+
required: true
|
|
722
928
|
}
|
|
723
929
|
] : []
|
|
724
930
|
]
|
|
@@ -728,7 +934,12 @@ function toProvenanceSchema(schema, bundle, options = {}) {
|
|
|
728
934
|
const schemas = { ...bundle?.schemas ?? {} };
|
|
729
935
|
const fields = [];
|
|
730
936
|
const sourceLabels = options.sourceLabels ?? [];
|
|
937
|
+
const wrapped = provenanceFieldNames(schema, options.fields);
|
|
731
938
|
for (const field2 of schema.fields) {
|
|
939
|
+
if (!wrapped.has(field2.name)) {
|
|
940
|
+
fields.push(field2);
|
|
941
|
+
continue;
|
|
942
|
+
}
|
|
732
943
|
const annotation = annotationSchema(schema.id, field2, sourceLabels);
|
|
733
944
|
schemas[annotation.id] = annotation;
|
|
734
945
|
fields.push({
|
|
@@ -804,10 +1015,30 @@ ${tailRoom > 0 ? text.slice(text.length - tailRoom) : ""}`;
|
|
|
804
1015
|
}
|
|
805
1016
|
}
|
|
806
1017
|
function budgetSources(sources, maxChars, policy = "tail") {
|
|
807
|
-
const
|
|
808
|
-
|
|
809
|
-
|
|
1018
|
+
const records = /* @__PURE__ */ new Map();
|
|
1019
|
+
const record = (index, source, text) => {
|
|
1020
|
+
const existing = records.get(index);
|
|
1021
|
+
if (existing) {
|
|
1022
|
+
existing.keptLength = text.length;
|
|
1023
|
+
} else {
|
|
1024
|
+
records.set(index, {
|
|
1025
|
+
...source.label !== void 0 ? { label: source.label } : {},
|
|
1026
|
+
originalLength: source.text.length,
|
|
1027
|
+
keptLength: text.length
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
};
|
|
1031
|
+
const capped = sources.map((source, index) => {
|
|
1032
|
+
if (source.maxChars === void 0 || source.text.length <= source.maxChars) return source;
|
|
1033
|
+
const text = truncateText(source.text, source.maxChars, policy);
|
|
1034
|
+
record(index, source, text);
|
|
1035
|
+
return { ...source, text };
|
|
1036
|
+
});
|
|
1037
|
+
const total = capped.reduce((sum, s) => sum + s.text.length, 0);
|
|
1038
|
+
if (maxChars === void 0 || total <= maxChars) {
|
|
1039
|
+
return { sources: capped, truncated: [...records.values()] };
|
|
810
1040
|
}
|
|
1041
|
+
sources = capped;
|
|
811
1042
|
const allowance = /* @__PURE__ */ new Map();
|
|
812
1043
|
const order = sources.map((s, i) => i).sort((a, b) => sources[a].text.length - sources[b].text.length);
|
|
813
1044
|
let remaining = maxChars;
|
|
@@ -817,19 +1048,14 @@ function budgetSources(sources, maxChars, policy = "tail") {
|
|
|
817
1048
|
allowance.set(index, granted);
|
|
818
1049
|
remaining -= granted;
|
|
819
1050
|
});
|
|
820
|
-
const truncated = [];
|
|
821
1051
|
const budgeted = sources.map((source, index) => {
|
|
822
1052
|
const limit = allowance.get(index) ?? 0;
|
|
823
1053
|
if (source.text.length <= limit) return source;
|
|
824
1054
|
const text = truncateText(source.text, limit, policy);
|
|
825
|
-
|
|
826
|
-
...source.label !== void 0 ? { label: source.label } : {},
|
|
827
|
-
originalLength: source.text.length,
|
|
828
|
-
keptLength: text.length
|
|
829
|
-
});
|
|
1055
|
+
record(index, source, text);
|
|
830
1056
|
return { ...source, text };
|
|
831
1057
|
});
|
|
832
|
-
return { sources: budgeted, truncated };
|
|
1058
|
+
return { sources: budgeted, truncated: [...records.values()] };
|
|
833
1059
|
}
|
|
834
1060
|
|
|
835
1061
|
// src/coerce/validator.ts
|
|
@@ -845,7 +1071,7 @@ function entries(count) {
|
|
|
845
1071
|
return `${count} ${count === 1 ? "entry" : "entries"}`;
|
|
846
1072
|
}
|
|
847
1073
|
function validateConstraints(value, constraints, path, issues) {
|
|
848
|
-
const { minLength, maxLength, minimum, maximum, minItems, maxItems, pattern } = constraints;
|
|
1074
|
+
const { minLength, maxLength, minimum, maximum, minItems, maxItems, pattern, format } = constraints;
|
|
849
1075
|
if (Array.isArray(value)) {
|
|
850
1076
|
if (minItems !== void 0 && value.length < minItems) {
|
|
851
1077
|
issues.push({
|
|
@@ -889,6 +1115,10 @@ function validateConstraints(value, constraints, path, issues) {
|
|
|
889
1115
|
received: value
|
|
890
1116
|
});
|
|
891
1117
|
}
|
|
1118
|
+
if (format !== void 0) {
|
|
1119
|
+
const message = validateFormat(value, format);
|
|
1120
|
+
if (message) issues.push({ path, message, received: value });
|
|
1121
|
+
}
|
|
892
1122
|
return;
|
|
893
1123
|
}
|
|
894
1124
|
if (typeof value === "number") {
|
|
@@ -1230,8 +1460,15 @@ function generateSpanId() {
|
|
|
1230
1460
|
}
|
|
1231
1461
|
var Tracer = class {
|
|
1232
1462
|
sinks;
|
|
1233
|
-
|
|
1463
|
+
baseAttributes;
|
|
1464
|
+
/**
|
|
1465
|
+
* `baseAttributes` are merged into every span this tracer opens — how a
|
|
1466
|
+
* batch stamps `itemIndex` on the spans of each item, so a sink can tell
|
|
1467
|
+
* whose `llmCall` it is looking at under concurrency.
|
|
1468
|
+
*/
|
|
1469
|
+
constructor(sinks, baseAttributes) {
|
|
1234
1470
|
this.sinks = sinks ?? [];
|
|
1471
|
+
this.baseAttributes = baseAttributes;
|
|
1235
1472
|
}
|
|
1236
1473
|
startSpan(name, attributes, parent) {
|
|
1237
1474
|
return {
|
|
@@ -1239,7 +1476,7 @@ var Tracer = class {
|
|
|
1239
1476
|
name,
|
|
1240
1477
|
startTime: Date.now(),
|
|
1241
1478
|
events: [],
|
|
1242
|
-
attributes,
|
|
1479
|
+
attributes: this.baseAttributes ? { ...this.baseAttributes, ...attributes } : attributes,
|
|
1243
1480
|
parentId: parent?.id
|
|
1244
1481
|
};
|
|
1245
1482
|
}
|
|
@@ -1294,15 +1531,32 @@ async function resolveEnums(schema, bundle, enumResolver, tracer, parent) {
|
|
|
1294
1531
|
tracer.endSpan(span);
|
|
1295
1532
|
}
|
|
1296
1533
|
}
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1534
|
+
function emptyUsage() {
|
|
1535
|
+
return { calls: 0, promptTokens: 0, completionTokens: 0, totalTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 };
|
|
1536
|
+
}
|
|
1537
|
+
function addUsage(into, usage) {
|
|
1538
|
+
into.calls += 1;
|
|
1539
|
+
if (!usage) return;
|
|
1540
|
+
into.promptTokens += usage.promptTokens;
|
|
1541
|
+
into.completionTokens += usage.completionTokens;
|
|
1542
|
+
into.totalTokens += usage.totalTokens;
|
|
1543
|
+
into.cacheReadTokens += usage.cacheReadTokens ?? 0;
|
|
1544
|
+
into.cacheWriteTokens += usage.cacheWriteTokens ?? 0;
|
|
1545
|
+
}
|
|
1546
|
+
function checkOptions(options) {
|
|
1300
1547
|
const maxRepairAttempts = options.maxRepairAttempts ?? 0;
|
|
1301
1548
|
if (!Number.isInteger(maxRepairAttempts) || maxRepairAttempts < 0) {
|
|
1302
1549
|
throw new RangeError(
|
|
1303
1550
|
`maxRepairAttempts must be a non-negative integer, got ${String(options.maxRepairAttempts)}`
|
|
1304
1551
|
);
|
|
1305
1552
|
}
|
|
1553
|
+
const retryOnEmpty = options.retryOnEmpty ?? 0;
|
|
1554
|
+
if (!Number.isInteger(retryOnEmpty) || retryOnEmpty < 0) {
|
|
1555
|
+
throw new RangeError(
|
|
1556
|
+
`retryOnEmpty must be a non-negative integer, got ${String(options.retryOnEmpty)}`
|
|
1557
|
+
);
|
|
1558
|
+
}
|
|
1559
|
+
const instructions = normalizeInstructions(options.instructions);
|
|
1306
1560
|
const onInvalidField = options.onInvalidField ?? "throw";
|
|
1307
1561
|
if (!INVALID_FIELD_POLICIES.includes(onInvalidField)) {
|
|
1308
1562
|
throw new RangeError(
|
|
@@ -1314,60 +1568,96 @@ async function runCoercion(input, options, { mode, provenance }) {
|
|
|
1314
1568
|
`maxInputChars must be a positive integer, got ${String(options.maxInputChars)}`
|
|
1315
1569
|
);
|
|
1316
1570
|
}
|
|
1571
|
+
return { maxRepairAttempts, retryOnEmpty, onInvalidField, instructions };
|
|
1572
|
+
}
|
|
1573
|
+
async function prepareRequest(options, { mode, provenance }, instructions, sourceLabels, tracer, rootSpan) {
|
|
1574
|
+
const { schema, enumResolver } = options;
|
|
1575
|
+
const bundle = options.bundle ?? bundleOf(schema);
|
|
1576
|
+
const resolvedEnums = await resolveEnums(schema, bundle, enumResolver, tracer, rootSpan);
|
|
1577
|
+
const promptSpan = tracer.startSpan("buildPrompt", {}, rootSpan);
|
|
1578
|
+
const basePrompt = buildPrompt(schema, bundle, { resolvedEnums, instructions });
|
|
1579
|
+
const provenanceOptions = { sourceLabels, fields: options.provenanceFields };
|
|
1580
|
+
const systemPrompt = provenance ? `${basePrompt}
|
|
1581
|
+
${provenanceInstructions(provenanceOptions)}` : basePrompt;
|
|
1582
|
+
tracer.addEvent(promptSpan, "promptBuilt", {
|
|
1583
|
+
promptLength: systemPrompt.length,
|
|
1584
|
+
instructionCount: instructions.length,
|
|
1585
|
+
mode
|
|
1586
|
+
});
|
|
1587
|
+
tracer.endSpan(promptSpan);
|
|
1588
|
+
const request = provenance ? toProvenanceSchema(schema, bundle, provenanceOptions) : { schema, bundle };
|
|
1589
|
+
const schemaSpan = tracer.startSpan("buildJsonSchema", {}, rootSpan);
|
|
1590
|
+
const jsonSchema = runtimeSchemaToJsonSchema(request.schema, request.bundle, {
|
|
1591
|
+
resolvedEnums
|
|
1592
|
+
});
|
|
1593
|
+
tracer.endSpan(schemaSpan);
|
|
1594
|
+
return { systemPrompt, jsonSchema, schema: request.schema, bundle: request.bundle, resolvedEnums };
|
|
1595
|
+
}
|
|
1596
|
+
function isEmptyResult(data) {
|
|
1597
|
+
return Object.values(data).every((value) => value === null || value === void 0);
|
|
1598
|
+
}
|
|
1599
|
+
var EMPTY_RETRY_NOTE = "A previous attempt at this extraction returned no fields. The sources above do state values for at least some fields; read them again and return every value that is stated, leaving out only what the sources genuinely do not say.";
|
|
1600
|
+
async function runCoercion(input, options, { mode, provenance, traceAttributes }) {
|
|
1601
|
+
const { provider, schema, traceSinks } = options;
|
|
1602
|
+
const bundle = options.bundle ?? bundleOf(schema);
|
|
1603
|
+
const { maxRepairAttempts, retryOnEmpty, onInvalidField, instructions } = checkOptions(options);
|
|
1317
1604
|
const rawSources = toSources(input);
|
|
1318
|
-
const tracer = new Tracer(traceSinks);
|
|
1605
|
+
const tracer = new Tracer(traceSinks, traceAttributes);
|
|
1319
1606
|
const rootSpan = tracer.startSpan(mode, {
|
|
1320
1607
|
schemaId: schema.id,
|
|
1321
1608
|
provenance,
|
|
1322
1609
|
onInvalidField,
|
|
1323
1610
|
sourceCount: rawSources.length
|
|
1324
1611
|
});
|
|
1612
|
+
const usage = emptyUsage();
|
|
1325
1613
|
try {
|
|
1326
1614
|
const sources = await prepareSources(rawSources, options, tracer, rootSpan);
|
|
1327
1615
|
const sourceLabels = sources.length > 1 ? sources.map((s) => s.label ?? "") : [];
|
|
1328
|
-
const
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1616
|
+
const prepared = await prepareRequest(
|
|
1617
|
+
options,
|
|
1618
|
+
{ mode, provenance },
|
|
1619
|
+
instructions,
|
|
1620
|
+
sourceLabels,
|
|
1332
1621
|
tracer,
|
|
1333
1622
|
rootSpan
|
|
1334
1623
|
);
|
|
1335
|
-
const
|
|
1336
|
-
const basePrompt = buildPrompt(schema, bundle, { resolvedEnums });
|
|
1337
|
-
const systemPrompt = provenance ? `${basePrompt}
|
|
1338
|
-
${provenanceInstructions({ sourceLabels })}` : basePrompt;
|
|
1339
|
-
tracer.addEvent(promptSpan, "promptBuilt", {
|
|
1340
|
-
promptLength: systemPrompt.length
|
|
1341
|
-
});
|
|
1342
|
-
tracer.endSpan(promptSpan);
|
|
1343
|
-
const request = provenance ? toProvenanceSchema(schema, bundle, { sourceLabels }) : { schema, bundle };
|
|
1344
|
-
const schemaSpan = tracer.startSpan("buildJsonSchema", {}, rootSpan);
|
|
1345
|
-
const jsonSchema = runtimeSchemaToJsonSchema(request.schema, request.bundle, {
|
|
1346
|
-
resolvedEnums
|
|
1347
|
-
});
|
|
1348
|
-
tracer.endSpan(schemaSpan);
|
|
1624
|
+
const { systemPrompt, jsonSchema, resolvedEnums } = prepared;
|
|
1349
1625
|
const validate = mode === "coerce" ? validateStrict : validatePartial;
|
|
1350
1626
|
const renderedInput = renderSources(sources);
|
|
1627
|
+
const hasInput = sources.some((s) => s.text.trim().length > 0);
|
|
1351
1628
|
tracer.addEvent(rootSpan, "inputRendered", {
|
|
1352
1629
|
sourceCount: sources.length,
|
|
1353
1630
|
inputLength: renderedInput.length
|
|
1354
1631
|
});
|
|
1355
1632
|
let userInput = renderedInput;
|
|
1356
1633
|
let issues = [];
|
|
1357
|
-
let run = { data: {}, provenance: {}, issues: [] };
|
|
1634
|
+
let run = { data: {}, provenance: {}, issues: [], usage };
|
|
1635
|
+
let emptyRetries = 0;
|
|
1358
1636
|
for (let attempt = 0; attempt <= maxRepairAttempts; attempt++) {
|
|
1359
1637
|
const llmSpan = tracer.startSpan("llmCall", { attempt }, rootSpan);
|
|
1360
1638
|
const response = await provider.complete({
|
|
1361
1639
|
systemPrompt,
|
|
1362
1640
|
userInput,
|
|
1363
1641
|
jsonSchema,
|
|
1364
|
-
schema:
|
|
1365
|
-
bundle:
|
|
1642
|
+
schema: prepared.schema,
|
|
1643
|
+
bundle: prepared.bundle,
|
|
1366
1644
|
resolvedEnums
|
|
1367
1645
|
});
|
|
1646
|
+
addUsage(usage, response.usage);
|
|
1368
1647
|
tracer.addEvent(llmSpan, "responseReceived", { usage: response.usage });
|
|
1369
1648
|
tracer.endSpan(llmSpan);
|
|
1370
|
-
run = provenance ? { ...splitProvenance(response.data, schema), issues: [] } : { data: response.data, provenance: {}, issues: [] };
|
|
1649
|
+
run = provenance ? { ...splitProvenance(response.data, schema), issues: [], usage } : { data: response.data, provenance: {}, issues: [], usage };
|
|
1650
|
+
if (hasInput && emptyRetries < retryOnEmpty && isEmptyResult(run.data)) {
|
|
1651
|
+
emptyRetries += 1;
|
|
1652
|
+
tracer.addEvent(rootSpan, "emptyRetry", { retry: emptyRetries });
|
|
1653
|
+
userInput = `${renderedInput}
|
|
1654
|
+
|
|
1655
|
+
---
|
|
1656
|
+
|
|
1657
|
+
${EMPTY_RETRY_NOTE}`;
|
|
1658
|
+
attempt -= 1;
|
|
1659
|
+
continue;
|
|
1660
|
+
}
|
|
1371
1661
|
const validationSpan = tracer.startSpan("validate", { attempt }, rootSpan);
|
|
1372
1662
|
issues = validate(run.data, schema, bundle, { resolvedEnums });
|
|
1373
1663
|
tracer.addEvent(validationSpan, "validated", { issueCount: issues.length });
|
|
@@ -1393,7 +1683,8 @@ ${provenanceInstructions({ sourceLabels })}` : basePrompt;
|
|
|
1393
1683
|
return {
|
|
1394
1684
|
data: outcome.data,
|
|
1395
1685
|
provenance: pruneProvenance(run.provenance, outcome.resolved),
|
|
1396
|
-
issues: outcome.resolved
|
|
1686
|
+
issues: outcome.resolved,
|
|
1687
|
+
usage
|
|
1397
1688
|
};
|
|
1398
1689
|
}
|
|
1399
1690
|
}
|
|
@@ -1414,7 +1705,8 @@ ${provenanceInstructions({ sourceLabels })}` : basePrompt;
|
|
|
1414
1705
|
}
|
|
1415
1706
|
async function prepareSources(sources, options, tracer, parent) {
|
|
1416
1707
|
const { preprocess, maxInputChars, truncate } = options;
|
|
1417
|
-
|
|
1708
|
+
const anyCapped = sources.some((s) => s.maxChars !== void 0);
|
|
1709
|
+
if (!preprocess && maxInputChars === void 0 && !anyCapped) {
|
|
1418
1710
|
return [...sources];
|
|
1419
1711
|
}
|
|
1420
1712
|
const span = tracer.startSpan("prepareInput", {}, parent);
|
|
@@ -1431,7 +1723,7 @@ async function prepareSources(sources, options, tracer, parent) {
|
|
|
1431
1723
|
lengths: prepared.map((s) => s.text.length)
|
|
1432
1724
|
});
|
|
1433
1725
|
}
|
|
1434
|
-
if (maxInputChars !== void 0) {
|
|
1726
|
+
if (maxInputChars !== void 0 || prepared.some((s) => s.maxChars !== void 0)) {
|
|
1435
1727
|
const budgeted = budgetSources(prepared, maxInputChars, truncate);
|
|
1436
1728
|
prepared = budgeted.sources;
|
|
1437
1729
|
if (budgeted.truncated.length > 0) {
|
|
@@ -1479,19 +1771,59 @@ async function partialCoerce(input, options) {
|
|
|
1479
1771
|
});
|
|
1480
1772
|
return stripNulls(data);
|
|
1481
1773
|
}
|
|
1774
|
+
async function coerceDetailed(input, options) {
|
|
1775
|
+
const { data, issues, usage } = await runCoercion(input, options, {
|
|
1776
|
+
mode: "coerce",
|
|
1777
|
+
provenance: false
|
|
1778
|
+
});
|
|
1779
|
+
return { data, issues, usage };
|
|
1780
|
+
}
|
|
1781
|
+
async function partialCoerceDetailed(input, options) {
|
|
1782
|
+
const { data, issues, usage } = await runCoercion(input, options, {
|
|
1783
|
+
mode: "partialCoerce",
|
|
1784
|
+
provenance: false
|
|
1785
|
+
});
|
|
1786
|
+
return { data: stripNulls(data), issues, usage };
|
|
1787
|
+
}
|
|
1788
|
+
var PRIME_INPUT = "Cache warm-up. There is no input to extract from; return an object with every field null.";
|
|
1789
|
+
async function primeCache(options) {
|
|
1790
|
+
const { mode = "coerce", provenance = false, ...coerceOptions } = options;
|
|
1791
|
+
const { instructions } = checkOptions(coerceOptions);
|
|
1792
|
+
const tracer = new Tracer(coerceOptions.traceSinks);
|
|
1793
|
+
const rootSpan = tracer.startSpan("primeCache", { schemaId: coerceOptions.schema.id, mode, provenance });
|
|
1794
|
+
const usage = emptyUsage();
|
|
1795
|
+
try {
|
|
1796
|
+
const prepared = await prepareRequest(coerceOptions, { mode, provenance }, instructions, [], tracer, rootSpan);
|
|
1797
|
+
const llmSpan = tracer.startSpan("llmCall", { attempt: 0, warmup: true }, rootSpan);
|
|
1798
|
+
const response = await coerceOptions.provider.complete({
|
|
1799
|
+
systemPrompt: prepared.systemPrompt,
|
|
1800
|
+
userInput: renderSources(toSources(PRIME_INPUT)),
|
|
1801
|
+
jsonSchema: prepared.jsonSchema,
|
|
1802
|
+
schema: prepared.schema,
|
|
1803
|
+
bundle: prepared.bundle,
|
|
1804
|
+
resolvedEnums: prepared.resolvedEnums
|
|
1805
|
+
});
|
|
1806
|
+
addUsage(usage, response.usage);
|
|
1807
|
+
tracer.addEvent(llmSpan, "responseReceived", { usage: response.usage });
|
|
1808
|
+
tracer.endSpan(llmSpan);
|
|
1809
|
+
return { schemaId: coerceOptions.schema.id, mode, provenance, usage, primedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
1810
|
+
} finally {
|
|
1811
|
+
tracer.endSpan(rootSpan);
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1482
1814
|
async function coerceWithProvenance(input, options) {
|
|
1483
|
-
const { data, provenance, issues } = await runCoercion(input, options, {
|
|
1815
|
+
const { data, provenance, issues, usage } = await runCoercion(input, options, {
|
|
1484
1816
|
mode: "coerce",
|
|
1485
1817
|
provenance: true
|
|
1486
1818
|
});
|
|
1487
|
-
return { data, provenance, issues };
|
|
1819
|
+
return { data, provenance, issues, usage };
|
|
1488
1820
|
}
|
|
1489
1821
|
async function partialCoerceWithProvenance(input, options) {
|
|
1490
|
-
const { data, provenance, issues } = await runCoercion(input, options, {
|
|
1822
|
+
const { data, provenance, issues, usage } = await runCoercion(input, options, {
|
|
1491
1823
|
mode: "partialCoerce",
|
|
1492
1824
|
provenance: true
|
|
1493
1825
|
});
|
|
1494
|
-
return { data: stripNulls(data), provenance, issues };
|
|
1826
|
+
return { data: stripNulls(data), provenance, issues, usage };
|
|
1495
1827
|
}
|
|
1496
1828
|
|
|
1497
1829
|
// src/coerce/coerce-many.ts
|
|
@@ -1532,60 +1864,107 @@ var BackoffGate = class {
|
|
|
1532
1864
|
this.streak = 0;
|
|
1533
1865
|
}
|
|
1534
1866
|
};
|
|
1867
|
+
var InputQueue = class {
|
|
1868
|
+
iterator;
|
|
1869
|
+
pulling = Promise.resolve();
|
|
1870
|
+
index = 0;
|
|
1871
|
+
constructor(inputs) {
|
|
1872
|
+
this.iterator = Symbol.asyncIterator in inputs ? inputs[Symbol.asyncIterator]() : inputs[Symbol.iterator]();
|
|
1873
|
+
}
|
|
1874
|
+
next() {
|
|
1875
|
+
const pull = this.pulling.then(async () => {
|
|
1876
|
+
const result = await this.iterator.next();
|
|
1877
|
+
if (result.done) return void 0;
|
|
1878
|
+
return { index: this.index++, input: result.value };
|
|
1879
|
+
});
|
|
1880
|
+
this.pulling = pull.catch(() => void 0);
|
|
1881
|
+
return pull;
|
|
1882
|
+
}
|
|
1883
|
+
};
|
|
1884
|
+
function labelOf(input) {
|
|
1885
|
+
if (typeof input === "string") return void 0;
|
|
1886
|
+
if (isSource(input)) return input.label;
|
|
1887
|
+
return input[0]?.label;
|
|
1888
|
+
}
|
|
1535
1889
|
async function coerceMany(inputs, options) {
|
|
1536
1890
|
const {
|
|
1537
1891
|
concurrency = DEFAULT_CONCURRENCY,
|
|
1538
1892
|
mode = "coerce",
|
|
1539
|
-
provenance = false,
|
|
1540
|
-
primeCache = true,
|
|
1893
|
+
provenance: provenanceOption = false,
|
|
1894
|
+
primeCache: primeCache2 = true,
|
|
1895
|
+
primed,
|
|
1541
1896
|
onItem,
|
|
1542
1897
|
signal,
|
|
1898
|
+
retry: retryOptions,
|
|
1543
1899
|
...coerceOptions
|
|
1544
1900
|
} = options;
|
|
1545
|
-
const retry = { ...DEFAULT_RETRY, ...
|
|
1901
|
+
const retry = { ...DEFAULT_RETRY, ...retryOptions };
|
|
1902
|
+
const provenance = provenanceOption !== false;
|
|
1903
|
+
if (Array.isArray(provenanceOption)) {
|
|
1904
|
+
coerceOptions.provenanceFields = provenanceOption;
|
|
1905
|
+
}
|
|
1546
1906
|
if (!Number.isInteger(concurrency) || concurrency < 1) {
|
|
1547
1907
|
throw new RangeError(`concurrency must be a positive integer, got ${String(concurrency)}`);
|
|
1548
1908
|
}
|
|
1549
1909
|
if (!Number.isInteger(retry.attempts) || retry.attempts < 0) {
|
|
1550
1910
|
throw new RangeError(`retry.attempts must be a non-negative integer, got ${String(retry.attempts)}`);
|
|
1551
1911
|
}
|
|
1552
|
-
const results =
|
|
1912
|
+
const results = [];
|
|
1553
1913
|
const gate = new BackoffGate(retry);
|
|
1554
|
-
|
|
1914
|
+
const queue = new InputQueue(inputs);
|
|
1915
|
+
async function runOne(index, input) {
|
|
1555
1916
|
let attempts = 0;
|
|
1556
1917
|
let result;
|
|
1918
|
+
let usage = emptyUsage();
|
|
1919
|
+
const label = labelOf(input);
|
|
1920
|
+
const traceAttributes = { itemIndex: index, ...label !== void 0 ? { itemLabel: label } : {} };
|
|
1557
1921
|
for (; ; ) {
|
|
1558
1922
|
if (signal?.aborted) {
|
|
1559
|
-
result = { ok: false, index, error: signal.reason ?? new Error("Batch aborted"), attempts };
|
|
1923
|
+
result = { ok: false, index, error: signal.reason ?? new Error("Batch aborted"), usage, attempts };
|
|
1560
1924
|
break;
|
|
1561
1925
|
}
|
|
1562
1926
|
await gate.wait();
|
|
1563
1927
|
attempts += 1;
|
|
1564
1928
|
try {
|
|
1565
|
-
const run = await runCoercion(
|
|
1929
|
+
const run = await runCoercion(input, coerceOptions, { mode, provenance, traceAttributes });
|
|
1566
1930
|
const data = mode === "partialCoerce" ? stripNulls(run.data) : run.data;
|
|
1567
1931
|
gate.succeeded();
|
|
1568
|
-
result = { ok: true, index, data, provenance: run.provenance, issues: run.issues, attempts };
|
|
1932
|
+
result = { ok: true, index, data, provenance: run.provenance, issues: run.issues, usage: run.usage, attempts };
|
|
1569
1933
|
break;
|
|
1570
1934
|
} catch (error) {
|
|
1935
|
+
usage = emptyUsage();
|
|
1571
1936
|
if (isRetryable(error) && attempts <= retry.attempts) {
|
|
1572
1937
|
gate.failed();
|
|
1573
1938
|
continue;
|
|
1574
1939
|
}
|
|
1575
|
-
result = { ok: false, index, error, attempts };
|
|
1940
|
+
result = { ok: false, index, error, usage, attempts };
|
|
1576
1941
|
break;
|
|
1577
1942
|
}
|
|
1578
1943
|
}
|
|
1579
1944
|
results[index] = result;
|
|
1580
1945
|
onItem?.(result);
|
|
1581
1946
|
}
|
|
1582
|
-
let
|
|
1583
|
-
|
|
1584
|
-
|
|
1947
|
+
let pending;
|
|
1948
|
+
const warmup = primed ?? (primeCache2 === "eager" ? primeCache({ ...coerceOptions, mode, provenance }) : void 0);
|
|
1949
|
+
if (warmup) {
|
|
1950
|
+
await Promise.resolve(warmup).catch(() => void 0);
|
|
1951
|
+
} else if (primeCache2 === true) {
|
|
1952
|
+
const first = await queue.next();
|
|
1953
|
+
if (first === void 0) return results;
|
|
1954
|
+
const second = await queue.next();
|
|
1955
|
+
if (second === void 0) {
|
|
1956
|
+
await runOne(first.index, first.input);
|
|
1957
|
+
return results;
|
|
1958
|
+
}
|
|
1959
|
+
await runOne(first.index, first.input);
|
|
1960
|
+
pending = second;
|
|
1585
1961
|
}
|
|
1586
|
-
const workers = Array.from({ length:
|
|
1587
|
-
|
|
1588
|
-
await
|
|
1962
|
+
const workers = Array.from({ length: concurrency }, async () => {
|
|
1963
|
+
for (; ; ) {
|
|
1964
|
+
const item = pending ?? await queue.next();
|
|
1965
|
+
pending = void 0;
|
|
1966
|
+
if (item === void 0) return;
|
|
1967
|
+
await runOne(item.index, item.input);
|
|
1589
1968
|
}
|
|
1590
1969
|
});
|
|
1591
1970
|
await Promise.all(workers);
|
|
@@ -1623,6 +2002,8 @@ function resolveConfig(callConfig) {
|
|
|
1623
2002
|
traceSinks: callConfig?.traceSinks ?? global.traceSinks,
|
|
1624
2003
|
maxRepairAttempts: callConfig?.maxRepairAttempts ?? global.maxRepairAttempts,
|
|
1625
2004
|
onInvalidField: callConfig?.onInvalidField ?? global.onInvalidField,
|
|
2005
|
+
instructions: callConfig?.instructions ?? global.instructions,
|
|
2006
|
+
retryOnEmpty: callConfig?.retryOnEmpty ?? global.retryOnEmpty,
|
|
1626
2007
|
maxInputChars: callConfig?.maxInputChars ?? global.maxInputChars,
|
|
1627
2008
|
truncate: callConfig?.truncate ?? global.truncate,
|
|
1628
2009
|
preprocess: callConfig?.preprocess ?? global.preprocess
|
|
@@ -1656,6 +2037,8 @@ var Coercible = class _Coercible {
|
|
|
1656
2037
|
traceSinks: this._config.traceSinks,
|
|
1657
2038
|
maxRepairAttempts: this._config.maxRepairAttempts,
|
|
1658
2039
|
onInvalidField: this._config.onInvalidField,
|
|
2040
|
+
instructions: this._config.instructions,
|
|
2041
|
+
retryOnEmpty: this._config.retryOnEmpty,
|
|
1659
2042
|
maxInputChars: this._config.maxInputChars,
|
|
1660
2043
|
truncate: this._config.truncate,
|
|
1661
2044
|
preprocess: this._config.preprocess
|
|
@@ -1722,6 +2105,7 @@ var ConsoleSink = class {
|
|
|
1722
2105
|
Constrain,
|
|
1723
2106
|
Describe,
|
|
1724
2107
|
EnumResolutionError,
|
|
2108
|
+
FIELD_FORMATS,
|
|
1725
2109
|
PROVENANCE_INSTRUCTIONS,
|
|
1726
2110
|
SOURCE_INSTRUCTIONS,
|
|
1727
2111
|
Schema,
|
|
@@ -1734,15 +2118,21 @@ var ConsoleSink = class {
|
|
|
1734
2118
|
buildRepairInput,
|
|
1735
2119
|
bundleOf,
|
|
1736
2120
|
coerce,
|
|
2121
|
+
coerceDetailed,
|
|
1737
2122
|
coerceMany,
|
|
1738
2123
|
coerceWithProvenance,
|
|
1739
2124
|
collectEnumSources,
|
|
1740
2125
|
defineSchema,
|
|
2126
|
+
describeFormat,
|
|
1741
2127
|
field,
|
|
2128
|
+
formatToJsonSchema,
|
|
1742
2129
|
isCoerceInput,
|
|
1743
2130
|
isSource,
|
|
2131
|
+
normalizeInstructions,
|
|
1744
2132
|
partialCoerce,
|
|
2133
|
+
partialCoerceDetailed,
|
|
1745
2134
|
partialCoerceWithProvenance,
|
|
2135
|
+
primeCache,
|
|
1746
2136
|
provenanceInstructions,
|
|
1747
2137
|
renderSources,
|
|
1748
2138
|
resolveEnumSources,
|
|
@@ -1753,6 +2143,7 @@ var ConsoleSink = class {
|
|
|
1753
2143
|
toOpenAIJsonSchema,
|
|
1754
2144
|
toProvenanceSchema,
|
|
1755
2145
|
toSources,
|
|
2146
|
+
validateFormat,
|
|
1756
2147
|
validatePartial,
|
|
1757
2148
|
validateStrict
|
|
1758
2149
|
});
|