@sembl/core 0.3.0 → 0.5.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 +463 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +234 -38
- package/dist/index.d.ts +234 -38
- package/dist/index.js +455 -76
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,155 @@
|
|
|
1
|
+
// src/schema/formats.ts
|
|
2
|
+
var FIELD_FORMATS = [
|
|
3
|
+
"url",
|
|
4
|
+
"email",
|
|
5
|
+
"date",
|
|
6
|
+
"datetime",
|
|
7
|
+
"iso-country",
|
|
8
|
+
"us-state",
|
|
9
|
+
"us-state-name",
|
|
10
|
+
"currency"
|
|
11
|
+
];
|
|
12
|
+
var ISO_COUNTRIES = new Set(
|
|
13
|
+
"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(" ")
|
|
14
|
+
);
|
|
15
|
+
var US_STATES = {
|
|
16
|
+
AL: "Alabama",
|
|
17
|
+
AK: "Alaska",
|
|
18
|
+
AZ: "Arizona",
|
|
19
|
+
AR: "Arkansas",
|
|
20
|
+
CA: "California",
|
|
21
|
+
CO: "Colorado",
|
|
22
|
+
CT: "Connecticut",
|
|
23
|
+
DE: "Delaware",
|
|
24
|
+
FL: "Florida",
|
|
25
|
+
GA: "Georgia",
|
|
26
|
+
HI: "Hawaii",
|
|
27
|
+
ID: "Idaho",
|
|
28
|
+
IL: "Illinois",
|
|
29
|
+
IN: "Indiana",
|
|
30
|
+
IA: "Iowa",
|
|
31
|
+
KS: "Kansas",
|
|
32
|
+
KY: "Kentucky",
|
|
33
|
+
LA: "Louisiana",
|
|
34
|
+
ME: "Maine",
|
|
35
|
+
MD: "Maryland",
|
|
36
|
+
MA: "Massachusetts",
|
|
37
|
+
MI: "Michigan",
|
|
38
|
+
MN: "Minnesota",
|
|
39
|
+
MS: "Mississippi",
|
|
40
|
+
MO: "Missouri",
|
|
41
|
+
MT: "Montana",
|
|
42
|
+
NE: "Nebraska",
|
|
43
|
+
NV: "Nevada",
|
|
44
|
+
NH: "New Hampshire",
|
|
45
|
+
NJ: "New Jersey",
|
|
46
|
+
NM: "New Mexico",
|
|
47
|
+
NY: "New York",
|
|
48
|
+
NC: "North Carolina",
|
|
49
|
+
ND: "North Dakota",
|
|
50
|
+
OH: "Ohio",
|
|
51
|
+
OK: "Oklahoma",
|
|
52
|
+
OR: "Oregon",
|
|
53
|
+
PA: "Pennsylvania",
|
|
54
|
+
RI: "Rhode Island",
|
|
55
|
+
SC: "South Carolina",
|
|
56
|
+
SD: "South Dakota",
|
|
57
|
+
TN: "Tennessee",
|
|
58
|
+
TX: "Texas",
|
|
59
|
+
UT: "Utah",
|
|
60
|
+
VT: "Vermont",
|
|
61
|
+
VA: "Virginia",
|
|
62
|
+
WA: "Washington",
|
|
63
|
+
WV: "West Virginia",
|
|
64
|
+
WI: "Wisconsin",
|
|
65
|
+
WY: "Wyoming",
|
|
66
|
+
DC: "District of Columbia",
|
|
67
|
+
PR: "Puerto Rico",
|
|
68
|
+
GU: "Guam",
|
|
69
|
+
VI: "U.S. Virgin Islands",
|
|
70
|
+
AS: "American Samoa",
|
|
71
|
+
MP: "Northern Mariana Islands"
|
|
72
|
+
};
|
|
73
|
+
var US_STATE_NAMES = new Set(Object.values(US_STATES));
|
|
74
|
+
var CURRENCIES = new Set(
|
|
75
|
+
"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(" ")
|
|
76
|
+
);
|
|
77
|
+
var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
78
|
+
var DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
79
|
+
var DATETIME = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?$/;
|
|
80
|
+
function isCalendarDate(y, m, d) {
|
|
81
|
+
const date = new Date(Date.UTC(y, m - 1, d));
|
|
82
|
+
return date.getUTCFullYear() === y && date.getUTCMonth() === m - 1 && date.getUTCDate() === d;
|
|
83
|
+
}
|
|
84
|
+
function validateFormat(value, format) {
|
|
85
|
+
switch (format) {
|
|
86
|
+
case "url": {
|
|
87
|
+
try {
|
|
88
|
+
const url = new URL(value);
|
|
89
|
+
if (url.protocol === "http:" || url.protocol === "https:") return void 0;
|
|
90
|
+
} catch {
|
|
91
|
+
}
|
|
92
|
+
return `Expected an absolute http(s) URL, got ${JSON.stringify(value)}`;
|
|
93
|
+
}
|
|
94
|
+
case "email":
|
|
95
|
+
return EMAIL.test(value) ? void 0 : `Expected an email address, got ${JSON.stringify(value)}`;
|
|
96
|
+
case "date": {
|
|
97
|
+
const m = DATE.exec(value);
|
|
98
|
+
if (m && isCalendarDate(Number(m[1]), Number(m[2]), Number(m[3]))) return void 0;
|
|
99
|
+
return `Expected a calendar date as YYYY-MM-DD, got ${JSON.stringify(value)}`;
|
|
100
|
+
}
|
|
101
|
+
case "datetime":
|
|
102
|
+
return DATETIME.test(value) && !Number.isNaN(Date.parse(value)) ? void 0 : `Expected an ISO 8601 timestamp, got ${JSON.stringify(value)}`;
|
|
103
|
+
case "iso-country":
|
|
104
|
+
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)}`;
|
|
105
|
+
case "us-state":
|
|
106
|
+
return value in US_STATES ? void 0 : `Expected a two-letter USPS state code such as CA or NY, got ${JSON.stringify(value)}`;
|
|
107
|
+
case "us-state-name":
|
|
108
|
+
return US_STATE_NAMES.has(value) ? void 0 : `Expected a US state's full name such as California, got ${JSON.stringify(value)}`;
|
|
109
|
+
case "currency":
|
|
110
|
+
return CURRENCIES.has(value) ? void 0 : `Expected an ISO 4217 currency code such as USD or EUR, got ${JSON.stringify(value)}`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function describeFormat(format) {
|
|
114
|
+
switch (format) {
|
|
115
|
+
case "url":
|
|
116
|
+
return "an absolute http(s) URL";
|
|
117
|
+
case "email":
|
|
118
|
+
return "an email address";
|
|
119
|
+
case "date":
|
|
120
|
+
return "a calendar date as YYYY-MM-DD";
|
|
121
|
+
case "datetime":
|
|
122
|
+
return "an ISO 8601 timestamp (e.g. 2026-09-05T14:30:00Z)";
|
|
123
|
+
case "iso-country":
|
|
124
|
+
return "an ISO 3166-1 alpha-2 country code (e.g. US, DE, PT), never a country name";
|
|
125
|
+
case "us-state":
|
|
126
|
+
return "a two-letter USPS state code (e.g. CA, NY), never the state's name";
|
|
127
|
+
case "us-state-name":
|
|
128
|
+
return "a US state's full name (e.g. California, New York), never its abbreviation";
|
|
129
|
+
case "currency":
|
|
130
|
+
return "an ISO 4217 currency code (e.g. USD, EUR, GBP), never a symbol or a word";
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function formatToJsonSchema(format) {
|
|
134
|
+
switch (format) {
|
|
135
|
+
case "url":
|
|
136
|
+
return { format: "uri" };
|
|
137
|
+
case "email":
|
|
138
|
+
return { format: "email" };
|
|
139
|
+
case "date":
|
|
140
|
+
return { format: "date" };
|
|
141
|
+
case "datetime":
|
|
142
|
+
return { format: "date-time" };
|
|
143
|
+
case "iso-country":
|
|
144
|
+
case "us-state":
|
|
145
|
+
return { pattern: "^[A-Z]{2}$" };
|
|
146
|
+
case "currency":
|
|
147
|
+
return { pattern: "^[A-Z]{3}$" };
|
|
148
|
+
case "us-state-name":
|
|
149
|
+
return {};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
1
153
|
// src/schema/json-schema.ts
|
|
2
154
|
var CONSTRAINT_KEYWORDS = [
|
|
3
155
|
"maxLength",
|
|
@@ -14,6 +166,9 @@ function constraintsToJsonSchema(constraints, dialect) {
|
|
|
14
166
|
return {};
|
|
15
167
|
}
|
|
16
168
|
const out = {};
|
|
169
|
+
if (constraints.format !== void 0) {
|
|
170
|
+
Object.assign(out, formatToJsonSchema(constraints.format));
|
|
171
|
+
}
|
|
17
172
|
for (const keyword of CONSTRAINT_KEYWORDS) {
|
|
18
173
|
const value = constraints[keyword];
|
|
19
174
|
if (value !== void 0) {
|
|
@@ -163,7 +318,7 @@ async function resolveEnumSources(schema, resolver, bundle) {
|
|
|
163
318
|
await Promise.all(
|
|
164
319
|
[...usages].map(async ([sourceId, usage]) => {
|
|
165
320
|
try {
|
|
166
|
-
const values = await resolver(sourceId);
|
|
321
|
+
const values = await resolver(sourceId, { sourceId, schema, ...usage });
|
|
167
322
|
if (!values || values.length === 0) {
|
|
168
323
|
failures.push({ sourceId, reason: "empty", ...usage });
|
|
169
324
|
return;
|
|
@@ -398,7 +553,7 @@ ${summary}`);
|
|
|
398
553
|
// src/coerce/sources.ts
|
|
399
554
|
var SOURCE_TAG = "source";
|
|
400
555
|
function isSource(value) {
|
|
401
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.text === "string" && (value.label === void 0 || typeof value.label === "string");
|
|
556
|
+
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");
|
|
402
557
|
}
|
|
403
558
|
function isCoerceInput(value) {
|
|
404
559
|
return typeof value === "string" || isSource(value) || Array.isArray(value) && value.every(isSource);
|
|
@@ -418,7 +573,9 @@ function toSources(input) {
|
|
|
418
573
|
}
|
|
419
574
|
function cleanLabel(source) {
|
|
420
575
|
const label = source.label?.trim();
|
|
421
|
-
|
|
576
|
+
const cleaned = label ? { label, text: source.text } : { text: source.text };
|
|
577
|
+
if (source.maxChars !== void 0) cleaned.maxChars = source.maxChars;
|
|
578
|
+
return cleaned;
|
|
422
579
|
}
|
|
423
580
|
function escapeText(text) {
|
|
424
581
|
return text.replace(new RegExp(`</(\\s*${SOURCE_TAG}\\b)`, "gi"), "<\\/$1");
|
|
@@ -456,7 +613,10 @@ function describeConstraints(constraints) {
|
|
|
456
613
|
return [];
|
|
457
614
|
}
|
|
458
615
|
const phrases = [];
|
|
459
|
-
const { minLength, maxLength, minimum, maximum, minItems, maxItems, pattern } = constraints;
|
|
616
|
+
const { minLength, maxLength, minimum, maximum, minItems, maxItems, pattern, format } = constraints;
|
|
617
|
+
if (format !== void 0) {
|
|
618
|
+
phrases.push(describeFormat(format));
|
|
619
|
+
}
|
|
460
620
|
if (minLength !== void 0 && maxLength !== void 0) {
|
|
461
621
|
phrases.push(`between ${minLength} and ${maxLength} characters`);
|
|
462
622
|
} else if (maxLength !== void 0) {
|
|
@@ -569,6 +729,8 @@ function buildPrompt(schema, bundle, options = {}) {
|
|
|
569
729
|
lines.push("Instructions:");
|
|
570
730
|
lines.push("- Extract values from the sources that match the schema fields.");
|
|
571
731
|
lines.push("- Use null for optional fields that cannot be determined from the input.");
|
|
732
|
+
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.");
|
|
733
|
+
lines.push("- Never return an empty object when the input states values for any field.");
|
|
572
734
|
lines.push("- Required fields must always have a valid, non-null value.");
|
|
573
735
|
lines.push("- Interpret the user's input semantically \u2014 infer meaning, don't just pattern match.");
|
|
574
736
|
lines.push("- Respect every stated limit exactly; truncate or drop lower-priority content to stay within it.");
|
|
@@ -594,7 +756,7 @@ function renderReceived(received) {
|
|
|
594
756
|
return text.length > MAX_RECEIVED_LENGTH ? `${text.slice(0, MAX_RECEIVED_LENGTH)}\u2026 (truncated)` : text;
|
|
595
757
|
}
|
|
596
758
|
function buildRepairInput(originalInput, rejected, issues) {
|
|
597
|
-
|
|
759
|
+
return [
|
|
598
760
|
originalInput,
|
|
599
761
|
"",
|
|
600
762
|
"---",
|
|
@@ -603,9 +765,11 @@ function buildRepairInput(originalInput, rejected, issues) {
|
|
|
603
765
|
"",
|
|
604
766
|
JSON.stringify(rejected, null, 2),
|
|
605
767
|
"",
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
768
|
+
buildRepairCorrection(issues)
|
|
769
|
+
].join("\n");
|
|
770
|
+
}
|
|
771
|
+
function buildRepairCorrection(issues) {
|
|
772
|
+
const lines = ["The output was rejected because:", ""];
|
|
609
773
|
for (const issue of issues) {
|
|
610
774
|
lines.push(`- ${issue.path}: ${issue.message} (received: ${renderReceived(issue.received)})`);
|
|
611
775
|
}
|
|
@@ -634,11 +798,31 @@ var PROVENANCE_INSTRUCTIONS = [
|
|
|
634
798
|
"- Judge each field on its own. A confident value next to a guessed one is",
|
|
635
799
|
" normal, and marking the guess honestly is more useful than looking sure."
|
|
636
800
|
].join("\n");
|
|
801
|
+
function provenanceFieldNames(schema, fields) {
|
|
802
|
+
if (fields === void 0) return new Set(schema.fields.map((f) => f.name));
|
|
803
|
+
const known = new Set(schema.fields.map((f) => f.name));
|
|
804
|
+
for (const name of fields) {
|
|
805
|
+
if (!known.has(name)) {
|
|
806
|
+
throw new RangeError(
|
|
807
|
+
`provenance field "${name}" is not a field of schema "${schema.id}" (fields: ${[...known].join(", ")})`
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
return new Set(fields);
|
|
812
|
+
}
|
|
637
813
|
function provenanceInstructions(options = {}) {
|
|
638
814
|
const labels = options.sourceLabels ?? [];
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
815
|
+
let text = PROVENANCE_INSTRUCTIONS;
|
|
816
|
+
if (options.fields !== void 0) {
|
|
817
|
+
text = text.replace(
|
|
818
|
+
"- Every field is wrapped as an object: put the extracted value in `value`.",
|
|
819
|
+
`- Only these fields are wrapped as objects, with the extracted value in \`value\`: ${options.fields.join(", ")}. Every other field is a plain value.`
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
if (labels.length >= 2) {
|
|
823
|
+
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`.";
|
|
824
|
+
}
|
|
825
|
+
return text;
|
|
642
826
|
}
|
|
643
827
|
function annotationSchema(parentId, field2, sourceLabels) {
|
|
644
828
|
const valueField = {
|
|
@@ -670,7 +854,7 @@ function annotationSchema(parentId, field2, sourceLabels) {
|
|
|
670
854
|
name: "source",
|
|
671
855
|
description: "The label of the source this value was read from.",
|
|
672
856
|
type: { kind: "enum", values: [...sourceLabels] },
|
|
673
|
-
required:
|
|
857
|
+
required: true
|
|
674
858
|
}
|
|
675
859
|
] : []
|
|
676
860
|
]
|
|
@@ -680,7 +864,12 @@ function toProvenanceSchema(schema, bundle, options = {}) {
|
|
|
680
864
|
const schemas = { ...bundle?.schemas ?? {} };
|
|
681
865
|
const fields = [];
|
|
682
866
|
const sourceLabels = options.sourceLabels ?? [];
|
|
867
|
+
const wrapped = provenanceFieldNames(schema, options.fields);
|
|
683
868
|
for (const field2 of schema.fields) {
|
|
869
|
+
if (!wrapped.has(field2.name)) {
|
|
870
|
+
fields.push(field2);
|
|
871
|
+
continue;
|
|
872
|
+
}
|
|
684
873
|
const annotation = annotationSchema(schema.id, field2, sourceLabels);
|
|
685
874
|
schemas[annotation.id] = annotation;
|
|
686
875
|
fields.push({
|
|
@@ -756,10 +945,30 @@ ${tailRoom > 0 ? text.slice(text.length - tailRoom) : ""}`;
|
|
|
756
945
|
}
|
|
757
946
|
}
|
|
758
947
|
function budgetSources(sources, maxChars, policy = "tail") {
|
|
759
|
-
const
|
|
760
|
-
|
|
761
|
-
|
|
948
|
+
const records = /* @__PURE__ */ new Map();
|
|
949
|
+
const record = (index, source, text) => {
|
|
950
|
+
const existing = records.get(index);
|
|
951
|
+
if (existing) {
|
|
952
|
+
existing.keptLength = text.length;
|
|
953
|
+
} else {
|
|
954
|
+
records.set(index, {
|
|
955
|
+
...source.label !== void 0 ? { label: source.label } : {},
|
|
956
|
+
originalLength: source.text.length,
|
|
957
|
+
keptLength: text.length
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
const capped = sources.map((source, index) => {
|
|
962
|
+
if (source.maxChars === void 0 || source.text.length <= source.maxChars) return source;
|
|
963
|
+
const text = truncateText(source.text, source.maxChars, policy);
|
|
964
|
+
record(index, source, text);
|
|
965
|
+
return { ...source, text };
|
|
966
|
+
});
|
|
967
|
+
const total = capped.reduce((sum, s) => sum + s.text.length, 0);
|
|
968
|
+
if (maxChars === void 0 || total <= maxChars) {
|
|
969
|
+
return { sources: capped, truncated: [...records.values()] };
|
|
762
970
|
}
|
|
971
|
+
sources = capped;
|
|
763
972
|
const allowance = /* @__PURE__ */ new Map();
|
|
764
973
|
const order = sources.map((s, i) => i).sort((a, b) => sources[a].text.length - sources[b].text.length);
|
|
765
974
|
let remaining = maxChars;
|
|
@@ -769,19 +978,14 @@ function budgetSources(sources, maxChars, policy = "tail") {
|
|
|
769
978
|
allowance.set(index, granted);
|
|
770
979
|
remaining -= granted;
|
|
771
980
|
});
|
|
772
|
-
const truncated = [];
|
|
773
981
|
const budgeted = sources.map((source, index) => {
|
|
774
982
|
const limit = allowance.get(index) ?? 0;
|
|
775
983
|
if (source.text.length <= limit) return source;
|
|
776
984
|
const text = truncateText(source.text, limit, policy);
|
|
777
|
-
|
|
778
|
-
...source.label !== void 0 ? { label: source.label } : {},
|
|
779
|
-
originalLength: source.text.length,
|
|
780
|
-
keptLength: text.length
|
|
781
|
-
});
|
|
985
|
+
record(index, source, text);
|
|
782
986
|
return { ...source, text };
|
|
783
987
|
});
|
|
784
|
-
return { sources: budgeted, truncated };
|
|
988
|
+
return { sources: budgeted, truncated: [...records.values()] };
|
|
785
989
|
}
|
|
786
990
|
|
|
787
991
|
// src/coerce/validator.ts
|
|
@@ -797,7 +1001,7 @@ function entries(count) {
|
|
|
797
1001
|
return `${count} ${count === 1 ? "entry" : "entries"}`;
|
|
798
1002
|
}
|
|
799
1003
|
function validateConstraints(value, constraints, path, issues) {
|
|
800
|
-
const { minLength, maxLength, minimum, maximum, minItems, maxItems, pattern } = constraints;
|
|
1004
|
+
const { minLength, maxLength, minimum, maximum, minItems, maxItems, pattern, format } = constraints;
|
|
801
1005
|
if (Array.isArray(value)) {
|
|
802
1006
|
if (minItems !== void 0 && value.length < minItems) {
|
|
803
1007
|
issues.push({
|
|
@@ -841,6 +1045,10 @@ function validateConstraints(value, constraints, path, issues) {
|
|
|
841
1045
|
received: value
|
|
842
1046
|
});
|
|
843
1047
|
}
|
|
1048
|
+
if (format !== void 0) {
|
|
1049
|
+
const message = validateFormat(value, format);
|
|
1050
|
+
if (message) issues.push({ path, message, received: value });
|
|
1051
|
+
}
|
|
844
1052
|
return;
|
|
845
1053
|
}
|
|
846
1054
|
if (typeof value === "number") {
|
|
@@ -1182,8 +1390,15 @@ function generateSpanId() {
|
|
|
1182
1390
|
}
|
|
1183
1391
|
var Tracer = class {
|
|
1184
1392
|
sinks;
|
|
1185
|
-
|
|
1393
|
+
baseAttributes;
|
|
1394
|
+
/**
|
|
1395
|
+
* `baseAttributes` are merged into every span this tracer opens — how a
|
|
1396
|
+
* batch stamps `itemIndex` on the spans of each item, so a sink can tell
|
|
1397
|
+
* whose `llmCall` it is looking at under concurrency.
|
|
1398
|
+
*/
|
|
1399
|
+
constructor(sinks, baseAttributes) {
|
|
1186
1400
|
this.sinks = sinks ?? [];
|
|
1401
|
+
this.baseAttributes = baseAttributes;
|
|
1187
1402
|
}
|
|
1188
1403
|
startSpan(name, attributes, parent) {
|
|
1189
1404
|
return {
|
|
@@ -1191,7 +1406,7 @@ var Tracer = class {
|
|
|
1191
1406
|
name,
|
|
1192
1407
|
startTime: Date.now(),
|
|
1193
1408
|
events: [],
|
|
1194
|
-
attributes,
|
|
1409
|
+
attributes: this.baseAttributes ? { ...this.baseAttributes, ...attributes } : attributes,
|
|
1195
1410
|
parentId: parent?.id
|
|
1196
1411
|
};
|
|
1197
1412
|
}
|
|
@@ -1246,15 +1461,31 @@ async function resolveEnums(schema, bundle, enumResolver, tracer, parent) {
|
|
|
1246
1461
|
tracer.endSpan(span);
|
|
1247
1462
|
}
|
|
1248
1463
|
}
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1464
|
+
function emptyUsage() {
|
|
1465
|
+
return { calls: 0, promptTokens: 0, completionTokens: 0, totalTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 };
|
|
1466
|
+
}
|
|
1467
|
+
function addUsage(into, usage) {
|
|
1468
|
+
into.calls += 1;
|
|
1469
|
+
if (!usage) return;
|
|
1470
|
+
into.promptTokens += usage.promptTokens;
|
|
1471
|
+
into.completionTokens += usage.completionTokens;
|
|
1472
|
+
into.totalTokens += usage.totalTokens;
|
|
1473
|
+
into.cacheReadTokens += usage.cacheReadTokens ?? 0;
|
|
1474
|
+
into.cacheWriteTokens += usage.cacheWriteTokens ?? 0;
|
|
1475
|
+
}
|
|
1476
|
+
function checkOptions(options) {
|
|
1252
1477
|
const maxRepairAttempts = options.maxRepairAttempts ?? 0;
|
|
1253
1478
|
if (!Number.isInteger(maxRepairAttempts) || maxRepairAttempts < 0) {
|
|
1254
1479
|
throw new RangeError(
|
|
1255
1480
|
`maxRepairAttempts must be a non-negative integer, got ${String(options.maxRepairAttempts)}`
|
|
1256
1481
|
);
|
|
1257
1482
|
}
|
|
1483
|
+
const retryOnEmpty = options.retryOnEmpty ?? 0;
|
|
1484
|
+
if (!Number.isInteger(retryOnEmpty) || retryOnEmpty < 0) {
|
|
1485
|
+
throw new RangeError(
|
|
1486
|
+
`retryOnEmpty must be a non-negative integer, got ${String(options.retryOnEmpty)}`
|
|
1487
|
+
);
|
|
1488
|
+
}
|
|
1258
1489
|
const instructions = normalizeInstructions(options.instructions);
|
|
1259
1490
|
const onInvalidField = options.onInvalidField ?? "throw";
|
|
1260
1491
|
if (!INVALID_FIELD_POLICIES.includes(onInvalidField)) {
|
|
@@ -1267,61 +1498,106 @@ async function runCoercion(input, options, { mode, provenance }) {
|
|
|
1267
1498
|
`maxInputChars must be a positive integer, got ${String(options.maxInputChars)}`
|
|
1268
1499
|
);
|
|
1269
1500
|
}
|
|
1501
|
+
return { maxRepairAttempts, retryOnEmpty, onInvalidField, instructions };
|
|
1502
|
+
}
|
|
1503
|
+
async function prepareRequest(options, { mode, provenance }, instructions, sourceLabels, tracer, rootSpan) {
|
|
1504
|
+
const { schema, enumResolver } = options;
|
|
1505
|
+
const bundle = options.bundle ?? bundleOf(schema);
|
|
1506
|
+
const resolvedEnums = await resolveEnums(schema, bundle, enumResolver, tracer, rootSpan);
|
|
1507
|
+
const promptSpan = tracer.startSpan("buildPrompt", {}, rootSpan);
|
|
1508
|
+
const basePrompt = buildPrompt(schema, bundle, { resolvedEnums, instructions });
|
|
1509
|
+
const provenanceOptions = { sourceLabels, fields: options.provenanceFields };
|
|
1510
|
+
const systemPrompt = provenance ? `${basePrompt}
|
|
1511
|
+
${provenanceInstructions(provenanceOptions)}` : basePrompt;
|
|
1512
|
+
tracer.addEvent(promptSpan, "promptBuilt", {
|
|
1513
|
+
promptLength: systemPrompt.length,
|
|
1514
|
+
instructionCount: instructions.length,
|
|
1515
|
+
mode
|
|
1516
|
+
});
|
|
1517
|
+
tracer.endSpan(promptSpan);
|
|
1518
|
+
const request = provenance ? toProvenanceSchema(schema, bundle, provenanceOptions) : { schema, bundle };
|
|
1519
|
+
const schemaSpan = tracer.startSpan("buildJsonSchema", {}, rootSpan);
|
|
1520
|
+
const jsonSchema = runtimeSchemaToJsonSchema(request.schema, request.bundle, {
|
|
1521
|
+
resolvedEnums
|
|
1522
|
+
});
|
|
1523
|
+
tracer.endSpan(schemaSpan);
|
|
1524
|
+
return { systemPrompt, jsonSchema, schema: request.schema, bundle: request.bundle, resolvedEnums };
|
|
1525
|
+
}
|
|
1526
|
+
function isEmptyResult(data) {
|
|
1527
|
+
return Object.values(data).every((value) => value === null || value === void 0);
|
|
1528
|
+
}
|
|
1529
|
+
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.";
|
|
1530
|
+
async function runCoercion(input, options, { mode, provenance, traceAttributes }) {
|
|
1531
|
+
const { provider, schema, traceSinks } = options;
|
|
1532
|
+
const bundle = options.bundle ?? bundleOf(schema);
|
|
1533
|
+
const { maxRepairAttempts, retryOnEmpty, onInvalidField, instructions } = checkOptions(options);
|
|
1270
1534
|
const rawSources = toSources(input);
|
|
1271
|
-
const tracer = new Tracer(traceSinks);
|
|
1535
|
+
const tracer = new Tracer(traceSinks, traceAttributes);
|
|
1272
1536
|
const rootSpan = tracer.startSpan(mode, {
|
|
1273
1537
|
schemaId: schema.id,
|
|
1274
1538
|
provenance,
|
|
1275
1539
|
onInvalidField,
|
|
1276
1540
|
sourceCount: rawSources.length
|
|
1277
1541
|
});
|
|
1542
|
+
const usage = emptyUsage();
|
|
1278
1543
|
try {
|
|
1279
1544
|
const sources = await prepareSources(rawSources, options, tracer, rootSpan);
|
|
1280
1545
|
const sourceLabels = sources.length > 1 ? sources.map((s) => s.label ?? "") : [];
|
|
1281
|
-
const
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1546
|
+
const prepared = await prepareRequest(
|
|
1547
|
+
options,
|
|
1548
|
+
{ mode, provenance },
|
|
1549
|
+
instructions,
|
|
1550
|
+
sourceLabels,
|
|
1285
1551
|
tracer,
|
|
1286
1552
|
rootSpan
|
|
1287
1553
|
);
|
|
1288
|
-
const
|
|
1289
|
-
const basePrompt = buildPrompt(schema, bundle, { resolvedEnums, instructions });
|
|
1290
|
-
const systemPrompt = provenance ? `${basePrompt}
|
|
1291
|
-
${provenanceInstructions({ sourceLabels })}` : basePrompt;
|
|
1292
|
-
tracer.addEvent(promptSpan, "promptBuilt", {
|
|
1293
|
-
promptLength: systemPrompt.length,
|
|
1294
|
-
instructionCount: instructions.length
|
|
1295
|
-
});
|
|
1296
|
-
tracer.endSpan(promptSpan);
|
|
1297
|
-
const request = provenance ? toProvenanceSchema(schema, bundle, { sourceLabels }) : { schema, bundle };
|
|
1298
|
-
const schemaSpan = tracer.startSpan("buildJsonSchema", {}, rootSpan);
|
|
1299
|
-
const jsonSchema = runtimeSchemaToJsonSchema(request.schema, request.bundle, {
|
|
1300
|
-
resolvedEnums
|
|
1301
|
-
});
|
|
1302
|
-
tracer.endSpan(schemaSpan);
|
|
1554
|
+
const { systemPrompt, jsonSchema, resolvedEnums } = prepared;
|
|
1303
1555
|
const validate = mode === "coerce" ? validateStrict : validatePartial;
|
|
1304
1556
|
const renderedInput = renderSources(sources);
|
|
1557
|
+
const hasInput = sources.some((s) => s.text.trim().length > 0);
|
|
1305
1558
|
tracer.addEvent(rootSpan, "inputRendered", {
|
|
1306
1559
|
sourceCount: sources.length,
|
|
1307
1560
|
inputLength: renderedInput.length
|
|
1308
1561
|
});
|
|
1309
1562
|
let userInput = renderedInput;
|
|
1310
1563
|
let issues = [];
|
|
1311
|
-
let run = { data: {}, provenance: {}, issues: [] };
|
|
1564
|
+
let run = { data: {}, provenance: {}, issues: [], usage };
|
|
1565
|
+
let emptyRetries = 0;
|
|
1566
|
+
const multiTurn = provider.supportsHistory === true;
|
|
1567
|
+
const history = [];
|
|
1568
|
+
const followUp = (rejected, text, folded) => {
|
|
1569
|
+
if (multiTurn) {
|
|
1570
|
+
history.push({ role: "assistant", data: rejected }, { role: "user", text });
|
|
1571
|
+
} else {
|
|
1572
|
+
userInput = folded;
|
|
1573
|
+
}
|
|
1574
|
+
};
|
|
1312
1575
|
for (let attempt = 0; attempt <= maxRepairAttempts; attempt++) {
|
|
1313
|
-
const llmSpan = tracer.startSpan("llmCall", { attempt }, rootSpan);
|
|
1576
|
+
const llmSpan = tracer.startSpan("llmCall", { attempt, turns: history.length }, rootSpan);
|
|
1314
1577
|
const response = await provider.complete({
|
|
1315
1578
|
systemPrompt,
|
|
1316
1579
|
userInput,
|
|
1580
|
+
...history.length > 0 ? { history: [...history] } : {},
|
|
1317
1581
|
jsonSchema,
|
|
1318
|
-
schema:
|
|
1319
|
-
bundle:
|
|
1582
|
+
schema: prepared.schema,
|
|
1583
|
+
bundle: prepared.bundle,
|
|
1320
1584
|
resolvedEnums
|
|
1321
1585
|
});
|
|
1586
|
+
addUsage(usage, response.usage);
|
|
1322
1587
|
tracer.addEvent(llmSpan, "responseReceived", { usage: response.usage });
|
|
1323
1588
|
tracer.endSpan(llmSpan);
|
|
1324
|
-
run = provenance ? { ...splitProvenance(response.data, schema), issues: [] } : { data: response.data, provenance: {}, issues: [] };
|
|
1589
|
+
run = provenance ? { ...splitProvenance(response.data, schema), issues: [], usage } : { data: response.data, provenance: {}, issues: [], usage };
|
|
1590
|
+
if (hasInput && emptyRetries < retryOnEmpty && isEmptyResult(run.data)) {
|
|
1591
|
+
emptyRetries += 1;
|
|
1592
|
+
tracer.addEvent(rootSpan, "emptyRetry", { retry: emptyRetries });
|
|
1593
|
+
followUp(response.data, EMPTY_RETRY_NOTE, `${renderedInput}
|
|
1594
|
+
|
|
1595
|
+
---
|
|
1596
|
+
|
|
1597
|
+
${EMPTY_RETRY_NOTE}`);
|
|
1598
|
+
attempt -= 1;
|
|
1599
|
+
continue;
|
|
1600
|
+
}
|
|
1325
1601
|
const validationSpan = tracer.startSpan("validate", { attempt }, rootSpan);
|
|
1326
1602
|
issues = validate(run.data, schema, bundle, { resolvedEnums });
|
|
1327
1603
|
tracer.addEvent(validationSpan, "validated", { issueCount: issues.length });
|
|
@@ -1347,7 +1623,8 @@ ${provenanceInstructions({ sourceLabels })}` : basePrompt;
|
|
|
1347
1623
|
return {
|
|
1348
1624
|
data: outcome.data,
|
|
1349
1625
|
provenance: pruneProvenance(run.provenance, outcome.resolved),
|
|
1350
|
-
issues: outcome.resolved
|
|
1626
|
+
issues: outcome.resolved,
|
|
1627
|
+
usage
|
|
1351
1628
|
};
|
|
1352
1629
|
}
|
|
1353
1630
|
}
|
|
@@ -1358,7 +1635,11 @@ ${provenanceInstructions({ sourceLabels })}` : basePrompt;
|
|
|
1358
1635
|
issueCount: issues.length,
|
|
1359
1636
|
paths: issues.map((issue) => issue.path)
|
|
1360
1637
|
});
|
|
1361
|
-
|
|
1638
|
+
followUp(
|
|
1639
|
+
response.data,
|
|
1640
|
+
buildRepairCorrection(issues),
|
|
1641
|
+
buildRepairInput(renderedInput, run.data, issues)
|
|
1642
|
+
);
|
|
1362
1643
|
}
|
|
1363
1644
|
}
|
|
1364
1645
|
throw new CoerceError(issues);
|
|
@@ -1368,7 +1649,8 @@ ${provenanceInstructions({ sourceLabels })}` : basePrompt;
|
|
|
1368
1649
|
}
|
|
1369
1650
|
async function prepareSources(sources, options, tracer, parent) {
|
|
1370
1651
|
const { preprocess, maxInputChars, truncate } = options;
|
|
1371
|
-
|
|
1652
|
+
const anyCapped = sources.some((s) => s.maxChars !== void 0);
|
|
1653
|
+
if (!preprocess && maxInputChars === void 0 && !anyCapped) {
|
|
1372
1654
|
return [...sources];
|
|
1373
1655
|
}
|
|
1374
1656
|
const span = tracer.startSpan("prepareInput", {}, parent);
|
|
@@ -1385,7 +1667,7 @@ async function prepareSources(sources, options, tracer, parent) {
|
|
|
1385
1667
|
lengths: prepared.map((s) => s.text.length)
|
|
1386
1668
|
});
|
|
1387
1669
|
}
|
|
1388
|
-
if (maxInputChars !== void 0) {
|
|
1670
|
+
if (maxInputChars !== void 0 || prepared.some((s) => s.maxChars !== void 0)) {
|
|
1389
1671
|
const budgeted = budgetSources(prepared, maxInputChars, truncate);
|
|
1390
1672
|
prepared = budgeted.sources;
|
|
1391
1673
|
if (budgeted.truncated.length > 0) {
|
|
@@ -1433,19 +1715,59 @@ async function partialCoerce(input, options) {
|
|
|
1433
1715
|
});
|
|
1434
1716
|
return stripNulls(data);
|
|
1435
1717
|
}
|
|
1718
|
+
async function coerceDetailed(input, options) {
|
|
1719
|
+
const { data, issues, usage } = await runCoercion(input, options, {
|
|
1720
|
+
mode: "coerce",
|
|
1721
|
+
provenance: false
|
|
1722
|
+
});
|
|
1723
|
+
return { data, issues, usage };
|
|
1724
|
+
}
|
|
1725
|
+
async function partialCoerceDetailed(input, options) {
|
|
1726
|
+
const { data, issues, usage } = await runCoercion(input, options, {
|
|
1727
|
+
mode: "partialCoerce",
|
|
1728
|
+
provenance: false
|
|
1729
|
+
});
|
|
1730
|
+
return { data: stripNulls(data), issues, usage };
|
|
1731
|
+
}
|
|
1732
|
+
var PRIME_INPUT = "Cache warm-up. There is no input to extract from; return an object with every field null.";
|
|
1733
|
+
async function primeCache(options) {
|
|
1734
|
+
const { mode = "coerce", provenance = false, ...coerceOptions } = options;
|
|
1735
|
+
const { instructions } = checkOptions(coerceOptions);
|
|
1736
|
+
const tracer = new Tracer(coerceOptions.traceSinks);
|
|
1737
|
+
const rootSpan = tracer.startSpan("primeCache", { schemaId: coerceOptions.schema.id, mode, provenance });
|
|
1738
|
+
const usage = emptyUsage();
|
|
1739
|
+
try {
|
|
1740
|
+
const prepared = await prepareRequest(coerceOptions, { mode, provenance }, instructions, [], tracer, rootSpan);
|
|
1741
|
+
const llmSpan = tracer.startSpan("llmCall", { attempt: 0, warmup: true }, rootSpan);
|
|
1742
|
+
const response = await coerceOptions.provider.complete({
|
|
1743
|
+
systemPrompt: prepared.systemPrompt,
|
|
1744
|
+
userInput: renderSources(toSources(PRIME_INPUT)),
|
|
1745
|
+
jsonSchema: prepared.jsonSchema,
|
|
1746
|
+
schema: prepared.schema,
|
|
1747
|
+
bundle: prepared.bundle,
|
|
1748
|
+
resolvedEnums: prepared.resolvedEnums
|
|
1749
|
+
});
|
|
1750
|
+
addUsage(usage, response.usage);
|
|
1751
|
+
tracer.addEvent(llmSpan, "responseReceived", { usage: response.usage });
|
|
1752
|
+
tracer.endSpan(llmSpan);
|
|
1753
|
+
return { schemaId: coerceOptions.schema.id, mode, provenance, usage, primedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
1754
|
+
} finally {
|
|
1755
|
+
tracer.endSpan(rootSpan);
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1436
1758
|
async function coerceWithProvenance(input, options) {
|
|
1437
|
-
const { data, provenance, issues } = await runCoercion(input, options, {
|
|
1759
|
+
const { data, provenance, issues, usage } = await runCoercion(input, options, {
|
|
1438
1760
|
mode: "coerce",
|
|
1439
1761
|
provenance: true
|
|
1440
1762
|
});
|
|
1441
|
-
return { data, provenance, issues };
|
|
1763
|
+
return { data, provenance, issues, usage };
|
|
1442
1764
|
}
|
|
1443
1765
|
async function partialCoerceWithProvenance(input, options) {
|
|
1444
|
-
const { data, provenance, issues } = await runCoercion(input, options, {
|
|
1766
|
+
const { data, provenance, issues, usage } = await runCoercion(input, options, {
|
|
1445
1767
|
mode: "partialCoerce",
|
|
1446
1768
|
provenance: true
|
|
1447
1769
|
});
|
|
1448
|
-
return { data: stripNulls(data), provenance, issues };
|
|
1770
|
+
return { data: stripNulls(data), provenance, issues, usage };
|
|
1449
1771
|
}
|
|
1450
1772
|
|
|
1451
1773
|
// src/coerce/coerce-many.ts
|
|
@@ -1486,60 +1808,107 @@ var BackoffGate = class {
|
|
|
1486
1808
|
this.streak = 0;
|
|
1487
1809
|
}
|
|
1488
1810
|
};
|
|
1811
|
+
var InputQueue = class {
|
|
1812
|
+
iterator;
|
|
1813
|
+
pulling = Promise.resolve();
|
|
1814
|
+
index = 0;
|
|
1815
|
+
constructor(inputs) {
|
|
1816
|
+
this.iterator = Symbol.asyncIterator in inputs ? inputs[Symbol.asyncIterator]() : inputs[Symbol.iterator]();
|
|
1817
|
+
}
|
|
1818
|
+
next() {
|
|
1819
|
+
const pull = this.pulling.then(async () => {
|
|
1820
|
+
const result = await this.iterator.next();
|
|
1821
|
+
if (result.done) return void 0;
|
|
1822
|
+
return { index: this.index++, input: result.value };
|
|
1823
|
+
});
|
|
1824
|
+
this.pulling = pull.catch(() => void 0);
|
|
1825
|
+
return pull;
|
|
1826
|
+
}
|
|
1827
|
+
};
|
|
1828
|
+
function labelOf(input) {
|
|
1829
|
+
if (typeof input === "string") return void 0;
|
|
1830
|
+
if (isSource(input)) return input.label;
|
|
1831
|
+
return input[0]?.label;
|
|
1832
|
+
}
|
|
1489
1833
|
async function coerceMany(inputs, options) {
|
|
1490
1834
|
const {
|
|
1491
1835
|
concurrency = DEFAULT_CONCURRENCY,
|
|
1492
1836
|
mode = "coerce",
|
|
1493
|
-
provenance = false,
|
|
1494
|
-
primeCache = true,
|
|
1837
|
+
provenance: provenanceOption = false,
|
|
1838
|
+
primeCache: primeCache2 = true,
|
|
1839
|
+
primed,
|
|
1495
1840
|
onItem,
|
|
1496
1841
|
signal,
|
|
1842
|
+
retry: retryOptions,
|
|
1497
1843
|
...coerceOptions
|
|
1498
1844
|
} = options;
|
|
1499
|
-
const retry = { ...DEFAULT_RETRY, ...
|
|
1845
|
+
const retry = { ...DEFAULT_RETRY, ...retryOptions };
|
|
1846
|
+
const provenance = provenanceOption !== false;
|
|
1847
|
+
if (Array.isArray(provenanceOption)) {
|
|
1848
|
+
coerceOptions.provenanceFields = provenanceOption;
|
|
1849
|
+
}
|
|
1500
1850
|
if (!Number.isInteger(concurrency) || concurrency < 1) {
|
|
1501
1851
|
throw new RangeError(`concurrency must be a positive integer, got ${String(concurrency)}`);
|
|
1502
1852
|
}
|
|
1503
1853
|
if (!Number.isInteger(retry.attempts) || retry.attempts < 0) {
|
|
1504
1854
|
throw new RangeError(`retry.attempts must be a non-negative integer, got ${String(retry.attempts)}`);
|
|
1505
1855
|
}
|
|
1506
|
-
const results =
|
|
1856
|
+
const results = [];
|
|
1507
1857
|
const gate = new BackoffGate(retry);
|
|
1508
|
-
|
|
1858
|
+
const queue = new InputQueue(inputs);
|
|
1859
|
+
async function runOne(index, input) {
|
|
1509
1860
|
let attempts = 0;
|
|
1510
1861
|
let result;
|
|
1862
|
+
let usage = emptyUsage();
|
|
1863
|
+
const label = labelOf(input);
|
|
1864
|
+
const traceAttributes = { itemIndex: index, ...label !== void 0 ? { itemLabel: label } : {} };
|
|
1511
1865
|
for (; ; ) {
|
|
1512
1866
|
if (signal?.aborted) {
|
|
1513
|
-
result = { ok: false, index, error: signal.reason ?? new Error("Batch aborted"), attempts };
|
|
1867
|
+
result = { ok: false, index, error: signal.reason ?? new Error("Batch aborted"), usage, attempts };
|
|
1514
1868
|
break;
|
|
1515
1869
|
}
|
|
1516
1870
|
await gate.wait();
|
|
1517
1871
|
attempts += 1;
|
|
1518
1872
|
try {
|
|
1519
|
-
const run = await runCoercion(
|
|
1873
|
+
const run = await runCoercion(input, coerceOptions, { mode, provenance, traceAttributes });
|
|
1520
1874
|
const data = mode === "partialCoerce" ? stripNulls(run.data) : run.data;
|
|
1521
1875
|
gate.succeeded();
|
|
1522
|
-
result = { ok: true, index, data, provenance: run.provenance, issues: run.issues, attempts };
|
|
1876
|
+
result = { ok: true, index, data, provenance: run.provenance, issues: run.issues, usage: run.usage, attempts };
|
|
1523
1877
|
break;
|
|
1524
1878
|
} catch (error) {
|
|
1879
|
+
usage = emptyUsage();
|
|
1525
1880
|
if (isRetryable(error) && attempts <= retry.attempts) {
|
|
1526
1881
|
gate.failed();
|
|
1527
1882
|
continue;
|
|
1528
1883
|
}
|
|
1529
|
-
result = { ok: false, index, error, attempts };
|
|
1884
|
+
result = { ok: false, index, error, usage, attempts };
|
|
1530
1885
|
break;
|
|
1531
1886
|
}
|
|
1532
1887
|
}
|
|
1533
1888
|
results[index] = result;
|
|
1534
1889
|
onItem?.(result);
|
|
1535
1890
|
}
|
|
1536
|
-
let
|
|
1537
|
-
|
|
1538
|
-
|
|
1891
|
+
let pending;
|
|
1892
|
+
const warmup = primed ?? (primeCache2 === "eager" ? primeCache({ ...coerceOptions, mode, provenance }) : void 0);
|
|
1893
|
+
if (warmup) {
|
|
1894
|
+
await Promise.resolve(warmup).catch(() => void 0);
|
|
1895
|
+
} else if (primeCache2 === true) {
|
|
1896
|
+
const first = await queue.next();
|
|
1897
|
+
if (first === void 0) return results;
|
|
1898
|
+
const second = await queue.next();
|
|
1899
|
+
if (second === void 0) {
|
|
1900
|
+
await runOne(first.index, first.input);
|
|
1901
|
+
return results;
|
|
1902
|
+
}
|
|
1903
|
+
await runOne(first.index, first.input);
|
|
1904
|
+
pending = second;
|
|
1539
1905
|
}
|
|
1540
|
-
const workers = Array.from({ length:
|
|
1541
|
-
|
|
1542
|
-
await
|
|
1906
|
+
const workers = Array.from({ length: concurrency }, async () => {
|
|
1907
|
+
for (; ; ) {
|
|
1908
|
+
const item = pending ?? await queue.next();
|
|
1909
|
+
pending = void 0;
|
|
1910
|
+
if (item === void 0) return;
|
|
1911
|
+
await runOne(item.index, item.input);
|
|
1543
1912
|
}
|
|
1544
1913
|
});
|
|
1545
1914
|
await Promise.all(workers);
|
|
@@ -1578,6 +1947,7 @@ function resolveConfig(callConfig) {
|
|
|
1578
1947
|
maxRepairAttempts: callConfig?.maxRepairAttempts ?? global.maxRepairAttempts,
|
|
1579
1948
|
onInvalidField: callConfig?.onInvalidField ?? global.onInvalidField,
|
|
1580
1949
|
instructions: callConfig?.instructions ?? global.instructions,
|
|
1950
|
+
retryOnEmpty: callConfig?.retryOnEmpty ?? global.retryOnEmpty,
|
|
1581
1951
|
maxInputChars: callConfig?.maxInputChars ?? global.maxInputChars,
|
|
1582
1952
|
truncate: callConfig?.truncate ?? global.truncate,
|
|
1583
1953
|
preprocess: callConfig?.preprocess ?? global.preprocess
|
|
@@ -1612,6 +1982,7 @@ var Coercible = class _Coercible {
|
|
|
1612
1982
|
maxRepairAttempts: this._config.maxRepairAttempts,
|
|
1613
1983
|
onInvalidField: this._config.onInvalidField,
|
|
1614
1984
|
instructions: this._config.instructions,
|
|
1985
|
+
retryOnEmpty: this._config.retryOnEmpty,
|
|
1615
1986
|
maxInputChars: this._config.maxInputChars,
|
|
1616
1987
|
truncate: this._config.truncate,
|
|
1617
1988
|
preprocess: this._config.preprocess
|
|
@@ -1677,6 +2048,7 @@ export {
|
|
|
1677
2048
|
Constrain,
|
|
1678
2049
|
Describe,
|
|
1679
2050
|
EnumResolutionError,
|
|
2051
|
+
FIELD_FORMATS,
|
|
1680
2052
|
PROVENANCE_INSTRUCTIONS,
|
|
1681
2053
|
SOURCE_INSTRUCTIONS,
|
|
1682
2054
|
Schema,
|
|
@@ -1686,19 +2058,25 @@ export {
|
|
|
1686
2058
|
ValuesFrom,
|
|
1687
2059
|
budgetSources,
|
|
1688
2060
|
buildPrompt,
|
|
2061
|
+
buildRepairCorrection,
|
|
1689
2062
|
buildRepairInput,
|
|
1690
2063
|
bundleOf,
|
|
1691
2064
|
coerce,
|
|
2065
|
+
coerceDetailed,
|
|
1692
2066
|
coerceMany,
|
|
1693
2067
|
coerceWithProvenance,
|
|
1694
2068
|
collectEnumSources,
|
|
1695
2069
|
defineSchema,
|
|
2070
|
+
describeFormat,
|
|
1696
2071
|
field,
|
|
2072
|
+
formatToJsonSchema,
|
|
1697
2073
|
isCoerceInput,
|
|
1698
2074
|
isSource,
|
|
1699
2075
|
normalizeInstructions,
|
|
1700
2076
|
partialCoerce,
|
|
2077
|
+
partialCoerceDetailed,
|
|
1701
2078
|
partialCoerceWithProvenance,
|
|
2079
|
+
primeCache,
|
|
1702
2080
|
provenanceInstructions,
|
|
1703
2081
|
renderSources,
|
|
1704
2082
|
resolveEnumSources,
|
|
@@ -1709,6 +2087,7 @@ export {
|
|
|
1709
2087
|
toOpenAIJsonSchema,
|
|
1710
2088
|
toProvenanceSchema,
|
|
1711
2089
|
toSources,
|
|
2090
|
+
validateFormat,
|
|
1712
2091
|
validatePartial,
|
|
1713
2092
|
validateStrict
|
|
1714
2093
|
};
|