@jaypie/llm 1.3.1 → 1.3.3
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/cjs/index.cjs +136 -13
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +661 -0
- package/dist/cjs/operate/OperateLoop.d.ts +6 -3
- package/dist/cjs/providers/anthropic/utils.d.ts +2 -1
- package/dist/cjs/providers/bedrock/utils.d.ts +2 -1
- package/dist/cjs/providers/google/utils.d.ts +2 -1
- package/dist/cjs/providers/openai/utils.d.ts +2 -1
- package/dist/cjs/providers/openrouter/utils.d.ts +2 -1
- package/dist/cjs/providers/xai/utils.d.ts +2 -1
- package/dist/cjs/util/index.d.ts +1 -0
- package/dist/cjs/util/logger.d.ts +2 -1
- package/dist/cjs/util/repairFormatKeys.d.ts +19 -0
- package/dist/esm/index.d.ts +661 -16
- package/dist/esm/index.js +136 -13
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/operate/OperateLoop.d.ts +6 -3
- package/dist/esm/providers/anthropic/utils.d.ts +2 -1
- package/dist/esm/providers/bedrock/utils.d.ts +2 -1
- package/dist/esm/providers/google/utils.d.ts +2 -1
- package/dist/esm/providers/openai/utils.d.ts +2 -1
- package/dist/esm/providers/openrouter/utils.d.ts +2 -1
- package/dist/esm/providers/xai/utils.d.ts +2 -1
- package/dist/esm/util/index.d.ts +1 -0
- package/dist/esm/util/logger.d.ts +2 -1
- package/dist/esm/util/repairFormatKeys.d.ts +19 -0
- package/package.json +11 -5
package/dist/cjs/index.cjs
CHANGED
|
@@ -641,7 +641,7 @@ function naturalZodSchema(definition) {
|
|
|
641
641
|
//
|
|
642
642
|
// Helpers
|
|
643
643
|
//
|
|
644
|
-
function isPlainObject(value) {
|
|
644
|
+
function isPlainObject$1(value) {
|
|
645
645
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
646
646
|
}
|
|
647
647
|
/**
|
|
@@ -650,11 +650,11 @@ function isPlainObject(value) {
|
|
|
650
650
|
* provider adapters perform in `formatOutputSchema`, but without any
|
|
651
651
|
* provider-specific sanitization.
|
|
652
652
|
*/
|
|
653
|
-
function formatToJsonSchema(format) {
|
|
653
|
+
function formatToJsonSchema$1(format) {
|
|
654
654
|
if (format instanceof v4.z.ZodType) {
|
|
655
655
|
return v4.z.toJSONSchema(format);
|
|
656
656
|
}
|
|
657
|
-
if (isPlainObject(format) && format.type === "json_schema") {
|
|
657
|
+
if (isPlainObject$1(format) && format.type === "json_schema") {
|
|
658
658
|
const clone = structuredClone(format);
|
|
659
659
|
clone.type = "object";
|
|
660
660
|
return clone;
|
|
@@ -672,7 +672,7 @@ function formatToJsonSchema(format) {
|
|
|
672
672
|
* properties and array items so nested declared arrays are also backfilled.
|
|
673
673
|
*/
|
|
674
674
|
function fillFromSchema(schema, value) {
|
|
675
|
-
if (!isPlainObject(schema)) {
|
|
675
|
+
if (!isPlainObject$1(schema)) {
|
|
676
676
|
return value;
|
|
677
677
|
}
|
|
678
678
|
const type = schema.type;
|
|
@@ -682,18 +682,18 @@ function fillFromSchema(schema, value) {
|
|
|
682
682
|
return [];
|
|
683
683
|
}
|
|
684
684
|
const items = schema.items;
|
|
685
|
-
if (Array.isArray(value) && isPlainObject(items)) {
|
|
685
|
+
if (Array.isArray(value) && isPlainObject$1(items)) {
|
|
686
686
|
return value.map((entry) => fillFromSchema(items, entry));
|
|
687
687
|
}
|
|
688
688
|
return value;
|
|
689
689
|
}
|
|
690
690
|
const isObject = type === "object" || (type === undefined && "properties" in schema);
|
|
691
691
|
if (isObject) {
|
|
692
|
-
if (!isPlainObject(value)) {
|
|
692
|
+
if (!isPlainObject$1(value)) {
|
|
693
693
|
return value;
|
|
694
694
|
}
|
|
695
695
|
const properties = schema.properties;
|
|
696
|
-
if (isPlainObject(properties)) {
|
|
696
|
+
if (isPlainObject$1(properties)) {
|
|
697
697
|
for (const [key, propSchema] of Object.entries(properties)) {
|
|
698
698
|
value[key] = fillFromSchema(propSchema, value[key]);
|
|
699
699
|
}
|
|
@@ -716,7 +716,7 @@ function fillFromSchema(schema, value) {
|
|
|
716
716
|
* through untouched.
|
|
717
717
|
*/
|
|
718
718
|
function fillFormatArrays({ content, format, }) {
|
|
719
|
-
const schema = formatToJsonSchema(format);
|
|
719
|
+
const schema = formatToJsonSchema$1(format);
|
|
720
720
|
if (!schema) {
|
|
721
721
|
return content;
|
|
722
722
|
}
|
|
@@ -978,6 +978,116 @@ function random$1(defaultSeed) {
|
|
|
978
978
|
return rngFn;
|
|
979
979
|
}
|
|
980
980
|
|
|
981
|
+
//
|
|
982
|
+
//
|
|
983
|
+
// Helpers
|
|
984
|
+
//
|
|
985
|
+
function isPlainObject(value) {
|
|
986
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Convert a `format` declaration (Zod schema, NaturalSchema, or a JSON Schema
|
|
990
|
+
* JsonObject) into a plain JSON Schema we can walk. Mirrors the conversion the
|
|
991
|
+
* provider adapters perform in `formatOutputSchema`, but without any
|
|
992
|
+
* provider-specific sanitization.
|
|
993
|
+
*/
|
|
994
|
+
function formatToJsonSchema(format) {
|
|
995
|
+
if (format instanceof v4.z.ZodType) {
|
|
996
|
+
return v4.z.toJSONSchema(format);
|
|
997
|
+
}
|
|
998
|
+
if (isPlainObject(format) && format.type === "json_schema") {
|
|
999
|
+
const clone = structuredClone(format);
|
|
1000
|
+
clone.type = "object";
|
|
1001
|
+
return clone;
|
|
1002
|
+
}
|
|
1003
|
+
try {
|
|
1004
|
+
return v4.z.toJSONSchema(naturalZodSchema(format));
|
|
1005
|
+
}
|
|
1006
|
+
catch {
|
|
1007
|
+
return undefined;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Strip a single pair of surrounding double quotes from a key, if present.
|
|
1012
|
+
* `"Merchant Request"` -> `Merchant Request`; `Confidence` -> `Confidence`.
|
|
1013
|
+
*/
|
|
1014
|
+
function dequoteKey(key) {
|
|
1015
|
+
if (key.length >= 2 && key.startsWith('"') && key.endsWith('"')) {
|
|
1016
|
+
return key.slice(1, -1);
|
|
1017
|
+
}
|
|
1018
|
+
return key;
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* Walk a JSON Schema alongside a parsed value, renaming any object key whose
|
|
1022
|
+
* de-quoted form matches a declared property name. Recurses into declared
|
|
1023
|
+
* object properties and array items so nested corrupted keys are also repaired.
|
|
1024
|
+
*/
|
|
1025
|
+
function repairFromSchema(schema, value) {
|
|
1026
|
+
if (!isPlainObject(schema)) {
|
|
1027
|
+
return value;
|
|
1028
|
+
}
|
|
1029
|
+
const type = schema.type;
|
|
1030
|
+
const isArray = type === "array" || (type === undefined && "items" in schema);
|
|
1031
|
+
if (isArray) {
|
|
1032
|
+
const items = schema.items;
|
|
1033
|
+
if (Array.isArray(value) && isPlainObject(items)) {
|
|
1034
|
+
return value.map((entry) => repairFromSchema(items, entry));
|
|
1035
|
+
}
|
|
1036
|
+
return value;
|
|
1037
|
+
}
|
|
1038
|
+
const isObject = type === "object" || (type === undefined && "properties" in schema);
|
|
1039
|
+
if (isObject && isPlainObject(value)) {
|
|
1040
|
+
const properties = schema.properties;
|
|
1041
|
+
if (isPlainObject(properties)) {
|
|
1042
|
+
const declared = new Set(Object.keys(properties));
|
|
1043
|
+
// Repair keys: rename a quote-wrapped key to its declared form, unless
|
|
1044
|
+
// the correct key is already present (then drop the corrupted duplicate).
|
|
1045
|
+
for (const key of Object.keys(value)) {
|
|
1046
|
+
if (declared.has(key)) {
|
|
1047
|
+
continue;
|
|
1048
|
+
}
|
|
1049
|
+
const repaired = dequoteKey(key);
|
|
1050
|
+
if (repaired !== key && declared.has(repaired)) {
|
|
1051
|
+
if (!(repaired in value)) {
|
|
1052
|
+
value[repaired] = value[key];
|
|
1053
|
+
}
|
|
1054
|
+
delete value[key];
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
// Recurse into declared properties now that keys are aligned.
|
|
1058
|
+
for (const [key, propSchema] of Object.entries(properties)) {
|
|
1059
|
+
if (key in value) {
|
|
1060
|
+
value[key] = repairFromSchema(propSchema, value[key]);
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
return value;
|
|
1065
|
+
}
|
|
1066
|
+
return value;
|
|
1067
|
+
}
|
|
1068
|
+
//
|
|
1069
|
+
//
|
|
1070
|
+
// Main
|
|
1071
|
+
//
|
|
1072
|
+
/**
|
|
1073
|
+
* Repair structured-output keys that a provider/model corrupted by wrapping
|
|
1074
|
+
* them in literal double quotes (observed on OpenAI for multi-word `format`
|
|
1075
|
+
* keys: `Merchant Request` returned as `"Merchant Request"`). A declared
|
|
1076
|
+
* `format` is a schema contract: returned keys should match the declared names
|
|
1077
|
+
* exactly. Any returned key whose de-quoted form matches a declared key is
|
|
1078
|
+
* renamed back to the declared key.
|
|
1079
|
+
*
|
|
1080
|
+
* Only mutates a (cloned) structured object; strings and non-objects pass
|
|
1081
|
+
* through untouched.
|
|
1082
|
+
*/
|
|
1083
|
+
function repairFormatKeys({ content, format, }) {
|
|
1084
|
+
const schema = formatToJsonSchema(format);
|
|
1085
|
+
if (!schema) {
|
|
1086
|
+
return content;
|
|
1087
|
+
}
|
|
1088
|
+
return repairFromSchema(schema, structuredClone(content));
|
|
1089
|
+
}
|
|
1090
|
+
|
|
981
1091
|
/**
|
|
982
1092
|
* Helper function to safely call a function that might throw
|
|
983
1093
|
* @param fn Function to call safely
|
|
@@ -3547,7 +3657,16 @@ class OpenAiAdapter extends BaseProviderAdapter {
|
|
|
3547
3657
|
? schema
|
|
3548
3658
|
: naturalZodSchema(schema);
|
|
3549
3659
|
const responseFormat = zod.zodResponseFormat(zodSchema, "response");
|
|
3550
|
-
|
|
3660
|
+
// Re-spread to drop zod v4's non-enumerable `~standard` Standard-Schema
|
|
3661
|
+
// interop marker, then strip `$schema`: OpenAI's strict json_schema subset
|
|
3662
|
+
// does not recognize the draft-2020-12 `$schema` keyword, and shipping it
|
|
3663
|
+
// can leave strict structured-output enforcement silently disabled (the
|
|
3664
|
+
// model then free-forms, omitting required fields and corrupting keys).
|
|
3665
|
+
// Mirrors the OpenRouter adapter's sanitization.
|
|
3666
|
+
const jsonSchema = {
|
|
3667
|
+
...v4.z.toJSONSchema(zodSchema),
|
|
3668
|
+
};
|
|
3669
|
+
delete jsonSchema.$schema;
|
|
3551
3670
|
// OpenAI requires additionalProperties to be false on all objects
|
|
3552
3671
|
const checks = [jsonSchema];
|
|
3553
3672
|
while (checks.length > 0) {
|
|
@@ -6313,9 +6432,12 @@ class OperateLoop {
|
|
|
6313
6432
|
return false; // Stop loop
|
|
6314
6433
|
}
|
|
6315
6434
|
/**
|
|
6316
|
-
*
|
|
6317
|
-
* `format` is a schema contract:
|
|
6318
|
-
*
|
|
6435
|
+
* Reconcile structured output against the declared `format` contract. A
|
|
6436
|
+
* declared `format` is a schema contract: returned keys should match the
|
|
6437
|
+
* declared names exactly and every declared array field should be present.
|
|
6438
|
+
* First repairs keys a provider/model corrupted by wrapping them in literal
|
|
6439
|
+
* double quotes (observed on OpenAI for multi-word keys), then backfills any
|
|
6440
|
+
* declared array field a provider/model omitted, surfacing it as `[]`.
|
|
6319
6441
|
*/
|
|
6320
6442
|
applyFormatArrayDefaults(content, options) {
|
|
6321
6443
|
if (!options.format) {
|
|
@@ -6324,7 +6446,8 @@ class OperateLoop {
|
|
|
6324
6446
|
if (typeof content !== "object" || content === null) {
|
|
6325
6447
|
return content;
|
|
6326
6448
|
}
|
|
6327
|
-
|
|
6449
|
+
const repaired = repairFormatKeys({ content, format: options.format });
|
|
6450
|
+
return fillFormatArrays({ content: repaired, format: options.format });
|
|
6328
6451
|
}
|
|
6329
6452
|
/**
|
|
6330
6453
|
* Sync the current input state from the updated provider request.
|