@samchon/openapi
Advanced tools
Comparing version 2.0.0-dev.20241119 to 2.0.0-dev.20241120
import { OpenApi } from "../OpenApi"; | ||
import { IChatGptSchema } from "../structures/IChatGptSchema"; | ||
import { ILlmApplication } from "../structures/ILlmApplication"; | ||
export declare namespace ChatGptConverter { | ||
const parameters: (props: { | ||
options: Omit<ILlmApplication.IChatGptOptions, "separate">; | ||
components: OpenApi.IComponents; | ||
@@ -9,5 +11,6 @@ schema: OpenApi.IJsonSchema.IObject; | ||
const schema: (props: { | ||
options: Omit<ILlmApplication.IChatGptOptions, "separate">; | ||
components: OpenApi.IComponents; | ||
$defs: Record<string, IChatGptSchema>; | ||
schema: OpenApi.IJsonSchema; | ||
$defs: Record<string, IChatGptSchema>; | ||
}) => IChatGptSchema | null; | ||
@@ -14,0 +17,0 @@ const separate: (props: { |
@@ -29,11 +29,2 @@ "use strict"; | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { | ||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { | ||
if (ar || !(i in from)) { | ||
if (!ar) ar = Array.prototype.slice.call(from, 0, i); | ||
ar[i] = from[i]; | ||
} | ||
} | ||
return to.concat(ar || Array.prototype.slice.call(from)); | ||
}; | ||
var __values = (this && this.__values) || function(o) { | ||
@@ -50,2 +41,11 @@ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { | ||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { | ||
if (ar || !(i in from)) { | ||
if (!ar) ar = Array.prototype.slice.call(from, 0, i); | ||
ar[i] = from[i]; | ||
} | ||
} | ||
return to.concat(ar || Array.prototype.slice.call(from)); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -60,2 +60,3 @@ exports.ChatGptConverter = void 0; | ||
var res = ChatGptConverter.schema({ | ||
options: props.options, | ||
components: props.components, | ||
@@ -79,61 +80,47 @@ schema: props.schema, | ||
var _a; | ||
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isReference(props.schema)) { | ||
var key_1 = props.schema.$ref.split("#/components/schemas/")[1]; | ||
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isOneOf(input)) { | ||
input.oneOf.forEach(visit); | ||
return 0; | ||
} | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isReference(input)) { | ||
var key_1 = input.$ref.split("#/components/schemas/")[1]; | ||
var target = (_a = props.components.schemas) === null || _a === void 0 ? void 0 : _a[key_1]; | ||
if (target === undefined) | ||
return 0; | ||
var out = function () { | ||
return union.push(__assign(__assign({}, props.schema), { $ref: "#/$defs/".concat(key_1) })); | ||
}; | ||
if (props.$defs[key_1] !== undefined) | ||
return out(); | ||
props.$defs[key_1] = {}; | ||
var converted = ChatGptConverter.schema({ | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: target, | ||
}); | ||
if (converted === null) | ||
return union.push(null); | ||
props.$defs[key_1] = converted; | ||
return out(); | ||
} | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isArray(props.schema)) { | ||
var items = ChatGptConverter.schema({ | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: props.schema.items, | ||
}); | ||
if (items === null) | ||
return union.push(null); | ||
return union.push(__assign(__assign({}, props.schema), { items: items })); | ||
} | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isTuple(props.schema)) { | ||
var prefixItems = props.schema.prefixItems.map(function (item) { | ||
return ChatGptConverter.schema({ | ||
if (props.options.reference === true || | ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isRecursiveReference({ | ||
components: props.components, | ||
schema: input, | ||
})) { | ||
var out = function () { | ||
return union.push({ | ||
schema: __assign(__assign({}, input), { $ref: "#/$defs/".concat(key_1), title: undefined, description: undefined }), | ||
tags: [], | ||
}); | ||
}; | ||
if (props.$defs[key_1] !== undefined) | ||
return out(); | ||
props.$defs[key_1] = {}; | ||
var converted = ChatGptConverter.schema({ | ||
options: props.options, | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: item, | ||
schema: target, | ||
}); | ||
}); | ||
if (prefixItems.some(function (v) { return v === null; })) | ||
return union.push(null); | ||
var additionalItems = props.schema.additionalItems === undefined | ||
? false | ||
: typeof props.schema.additionalItems === "object" && | ||
props.schema.additionalItems !== null | ||
? ChatGptConverter.schema({ | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: props.schema.additionalItems, | ||
}) | ||
: props.schema.additionalItems; | ||
if (additionalItems === null) | ||
return union.push(null); | ||
return union.push(__assign(__assign({}, props.schema), { prefixItems: prefixItems.filter(function (v) { return v !== null; }), additionalItems: additionalItems })); | ||
if (converted === null) | ||
return union.push({ | ||
schema: null, | ||
tags: [], | ||
}); | ||
props.$defs[key_1] = converted; | ||
return out(); | ||
} | ||
else | ||
return visit(target); | ||
} | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isObject(props.schema)) { | ||
var properties = Object.entries(props.schema.properties || {}).reduce(function (acc, _a) { | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isObject(input)) { | ||
var properties = Object.entries(input.properties || {}).reduce(function (acc, _a) { | ||
var _b = __read(_a, 2), key = _b[0], value = _b[1]; | ||
var converted = ChatGptConverter.schema({ | ||
options: props.options, | ||
components: props.components, | ||
@@ -149,65 +136,126 @@ $defs: props.$defs, | ||
if (Object.values(properties).some(function (v) { return v === null; })) | ||
return union.push(null); | ||
var additionalProperties = props.schema.additionalProperties === undefined | ||
return union.push({ | ||
schema: null, | ||
tags: [], | ||
}); | ||
var additionalProperties = input.additionalProperties === undefined | ||
? false | ||
: typeof props.schema.additionalProperties === "object" && | ||
props.schema.additionalProperties !== null | ||
: typeof input.additionalProperties === "object" && | ||
input.additionalProperties !== null | ||
? ChatGptConverter.schema({ | ||
options: props.options, | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: props.schema.additionalProperties, | ||
schema: input.additionalProperties, | ||
}) | ||
: props.schema.additionalProperties; | ||
: input.additionalProperties; | ||
if (additionalProperties === null) | ||
return union.push(null); | ||
return union.push(__assign(__assign({}, props.schema), { properties: properties, additionalProperties: additionalProperties })); | ||
return union.push({ | ||
schema: null, | ||
tags: [], | ||
}); | ||
return union.push({ | ||
schema: __assign(__assign({}, input), { properties: properties, additionalProperties: additionalProperties, required: Object.keys(properties) }), | ||
tags: [], | ||
}); | ||
} | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isOneOf(props.schema)) { | ||
var oneOf = props.schema.oneOf | ||
.filter(function (e) { return !OpenApiTypeChecker_1.OpenApiTypeChecker.isConstant(e); }) | ||
.map(function (item) { | ||
return ChatGptConverter.schema({ | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: item, | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isArray(input)) { | ||
var items = ChatGptConverter.schema({ | ||
options: props.options, | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: input.items, | ||
}); | ||
if (items === null) | ||
return union.push({ | ||
schema: null, | ||
tags: props.options.constraint ? [] : getArrayTags(input), | ||
}); | ||
return union.push({ | ||
schema: __assign(__assign(__assign({}, input), { items: items }), (props.options.constraint | ||
? {} | ||
: { | ||
maxItems: undefined, | ||
minItems: undefined, | ||
})), | ||
tags: props.options.constraint ? [] : getArrayTags(input), | ||
}); | ||
return union.push.apply(union, __spreadArray([], __read(oneOf), false)); | ||
} | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isString(input)) | ||
return union.push({ | ||
schema: __assign(__assign({}, input), (props.options.constraint | ||
? {} | ||
: { | ||
contentMediaType: undefined, | ||
minLength: undefined, | ||
maxLength: undefined, | ||
format: undefined, | ||
pattern: undefined, | ||
})), | ||
tags: props.options.constraint ? [] : getStringTags(input), | ||
}); | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isNumber(input) || | ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isInteger(input)) | ||
return union.push({ | ||
schema: __assign(__assign({}, input), (props.options.constraint | ||
? {} | ||
: { | ||
maximum: undefined, | ||
minimum: undefined, | ||
exclusiveMaximum: undefined, | ||
exclusiveMinimum: undefined, | ||
multipleOf: undefined, | ||
})), | ||
tags: props.options.constraint ? [] : getNumericTags(input), | ||
}); | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isConstant(input)) | ||
return 0; | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isTuple(input)) | ||
return union.push({ | ||
schema: null, | ||
tags: [], | ||
}); | ||
else | ||
return union.push(input); | ||
return union.push({ | ||
schema: __assign({}, input), | ||
tags: [], | ||
}); | ||
}; | ||
var visitConstant = function (schema) { | ||
var e_1, _a; | ||
var visitConstant = function (input) { | ||
var _a; | ||
var insert = function (value) { | ||
var _a; | ||
var _b; | ||
var matched = union.find(function (u) { | ||
return u.type === typeof value; | ||
var _a; | ||
return ((_a = u.schema) === null || _a === void 0 ? void 0 : _a.type) === | ||
typeof value; | ||
}); | ||
if (matched !== undefined) { | ||
(_a = matched.enum) !== null && _a !== void 0 ? _a : (matched.enum = []); | ||
matched.enum.push(value); | ||
(_a = (_b = matched.schema).enum) !== null && _a !== void 0 ? _a : (_b.enum = []); | ||
matched.schema.enum.push(value); | ||
} | ||
else | ||
union.push({ type: typeof value, enum: [value] }); | ||
union.push({ | ||
schema: { | ||
type: typeof value, | ||
enum: [value], | ||
}, | ||
tags: [], | ||
}); | ||
}; | ||
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isConstant(schema)) | ||
insert(schema.const); | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isOneOf(schema)) | ||
try { | ||
for (var _b = __values(schema.oneOf), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var u = _c.value; | ||
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isConstant(u)) | ||
insert(u.const); | ||
} | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isConstant(input)) | ||
insert(input.const); | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isOneOf(input)) | ||
input.oneOf.forEach(visitConstant); | ||
else if (props.options.reference === false && | ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isReference(input) && | ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isRecursiveReference({ | ||
components: props.components, | ||
schema: input, | ||
}) === false) { | ||
var target = (_a = props.components.schemas) === null || _a === void 0 ? void 0 : _a[input.$ref.split("#/components/schemas/")[1]]; | ||
if (target !== undefined) | ||
visitConstant(target); | ||
} | ||
}; | ||
@@ -221,114 +269,17 @@ visit(props.schema); | ||
else if (union.length === 1) | ||
return __assign(__assign({}, attribute), union[0]); | ||
return __assign(__assign({}, attribute), { anyOf: union }); | ||
// if (OpenApiTypeChecker.isReference(props.schema)) { | ||
// const key: string = props.schema.$ref.split("#/components/schemas/")[1]; | ||
// const target: OpenApi.IJsonSchema | undefined = | ||
// props.components.schemas?.[key]; | ||
// if (target === undefined) return null; | ||
// const out = () => ({ | ||
// ...props.schema, | ||
// $ref: `#/$defs/${key}`, | ||
// }); | ||
// if (props.$defs[key] !== undefined) return out(); | ||
// props.$defs[key] = {}; | ||
// const converted: IChatGptSchema | null = schema({ | ||
// components: props.components, | ||
// $defs: props.$defs, | ||
// schema: target, | ||
// }); | ||
// if (converted === null) return null; | ||
// props.$defs[key] = converted; | ||
// return out(); | ||
// } else if (OpenApiTypeChecker.isArray(props.schema)) { | ||
// const items: IChatGptSchema | null = schema({ | ||
// components: props.components, | ||
// $defs: props.$defs, | ||
// schema: props.schema.items, | ||
// }); | ||
// if (items === null) return null; | ||
// return { | ||
// ...props.schema, | ||
// items, | ||
// }; | ||
// } else if (OpenApiTypeChecker.isTuple(props.schema)) { | ||
// const prefixItems: Array<IChatGptSchema | null> = | ||
// props.schema.prefixItems.map((item) => | ||
// schema({ | ||
// components: props.components, | ||
// $defs: props.$defs, | ||
// schema: item, | ||
// }), | ||
// ); | ||
// if (prefixItems.some((v) => v === null)) return null; | ||
// const additionalItems = | ||
// props.schema.additionalItems === undefined | ||
// ? false | ||
// : typeof props.schema.additionalItems === "object" && | ||
// props.schema.additionalItems !== null | ||
// ? schema({ | ||
// components: props.components, | ||
// $defs: props.$defs, | ||
// schema: props.schema.additionalItems, | ||
// }) | ||
// : props.schema.additionalItems; | ||
// if (additionalItems === null) return null; | ||
// return { | ||
// ...props.schema, | ||
// prefixItems: prefixItems.filter((v) => v !== null), | ||
// additionalItems, | ||
// }; | ||
// } else if (OpenApiTypeChecker.isObject(props.schema)) { | ||
// const properties: Record<string, IChatGptSchema | null> = Object.entries( | ||
// props.schema.properties || {}, | ||
// ).reduce( | ||
// (acc, [key, value]) => { | ||
// const converted: IChatGptSchema | null = schema({ | ||
// components: props.components, | ||
// $defs: props.$defs, | ||
// schema: value, | ||
// }); | ||
// if (converted === null) return acc; | ||
// acc[key] = converted; | ||
// return acc; | ||
// }, | ||
// {} as Record<string, IChatGptSchema | null>, | ||
// ); | ||
// if (Object.values(properties).some((v) => v === null)) return null; | ||
// const additionalProperties = | ||
// props.schema.additionalProperties === undefined | ||
// ? false | ||
// : typeof props.schema.additionalProperties === "object" && | ||
// props.schema.additionalProperties !== null | ||
// ? schema({ | ||
// components: props.components, | ||
// $defs: props.$defs, | ||
// schema: props.schema.additionalProperties, | ||
// }) | ||
// : props.schema.additionalProperties; | ||
// if (additionalProperties === null) return null; | ||
// return { | ||
// ...props.schema, | ||
// properties: properties as Record<string, IChatGptSchema>, | ||
// additionalProperties, | ||
// }; | ||
// } else if (OpenApiTypeChecker.isOneOf(props.schema)) { | ||
// const oneOf: Array<IChatGptSchema | null> = props.schema.oneOf.map( | ||
// (item) => | ||
// schema({ | ||
// components: props.components, | ||
// $defs: props.$defs, | ||
// schema: item, | ||
// }), | ||
// ); | ||
// if (oneOf.some((v) => v === null)) return null; | ||
// return { | ||
// ...props.schema, | ||
// anyOf: oneOf.filter((v) => v !== null), | ||
// ...{ | ||
// oneOf: undefined, | ||
// }, | ||
// }; | ||
// } | ||
// return props.schema; | ||
return __assign(__assign(__assign({}, attribute), union[0].schema), { description: ChatGptTypeChecker_1.ChatGptTypeChecker.isReference(union[0].schema) | ||
? undefined | ||
: writeTagWithDescription({ | ||
description: attribute.description, | ||
tags: union[0].tags, | ||
}) }); | ||
return __assign(__assign({}, attribute), { anyOf: union.map(function (u) { | ||
var _a; | ||
return (__assign(__assign({}, u.schema), { description: ChatGptTypeChecker_1.ChatGptTypeChecker.isReference(u.schema) | ||
? undefined | ||
: writeTagWithDescription({ | ||
description: (_a = u.schema) === null || _a === void 0 ? void 0 : _a.description, | ||
tags: u.tags, | ||
}) })); | ||
}) }); | ||
}; | ||
@@ -375,3 +326,3 @@ ChatGptConverter.separate = function (props) { | ||
var separateObject = function (props) { | ||
var e_2, _a; | ||
var e_1, _a; | ||
var _b; | ||
@@ -394,3 +345,3 @@ var llm = __assign(__assign({}, props.schema), { properties: {} }); | ||
} | ||
catch (e_2_1) { e_2 = { error: e_2_1 }; } | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
@@ -400,3 +351,3 @@ try { | ||
} | ||
finally { if (e_2) throw e_2.error; } | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
@@ -472,2 +423,25 @@ if (typeof props.schema.additionalProperties === "object" && | ||
}; | ||
var getNumericTags = function (schema) { return __spreadArray(__spreadArray(__spreadArray([], __read((schema.minimum !== undefined | ||
? schema.exclusiveMinimum === true | ||
? ["@exclusiveMinimum ".concat(schema.minimum)] | ||
: ["@minimum ".concat(schema.minimum)] | ||
: [])), false), __read((schema.maximum !== undefined | ||
? schema.exclusiveMaximum === true | ||
? ["@exclusiveMaximum ".concat(schema.maximum)] | ||
: ["@maximum ".concat(schema.maximum)] | ||
: [])), false), __read((schema.multipleOf !== undefined | ||
? ["@multipleOf ".concat(schema.multipleOf)] | ||
: [])), false); }; | ||
var getStringTags = function (schema) { return __spreadArray(__spreadArray(__spreadArray(__spreadArray([], __read((schema.minLength !== undefined | ||
? ["@minLength ".concat(schema.minLength)] | ||
: [])), false), __read((schema.maxLength !== undefined | ||
? ["@maxLength ".concat(schema.maxLength)] | ||
: [])), false), __read((schema.format !== undefined ? ["@format ".concat(schema.format)] : [])), false), __read((schema.pattern !== undefined ? ["@pattern ".concat(schema.pattern)] : [])), false); }; | ||
var getArrayTags = function (schema) { return __spreadArray(__spreadArray([], __read((schema.minItems !== undefined ? ["@minItems ".concat(schema.minItems)] : [])), false), __read((schema.maxItems !== undefined ? ["@maxItems ".concat(schema.maxItems)] : [])), false); }; | ||
var writeTagWithDescription = function (props) { | ||
var _a; | ||
if (props.tags.length === 0) | ||
return props.description; | ||
return __spreadArray(__spreadArray([], __read((((_a = props.description) === null || _a === void 0 ? void 0 : _a.length) ? [props.description, "\n"] : [])), false), __read(props.tags), false).join("\n"); | ||
}; | ||
})(ChatGptConverter || (exports.ChatGptConverter = ChatGptConverter = {})); |
@@ -10,3 +10,3 @@ import { OpenApi } from "../OpenApi"; | ||
migrate: IHttpMigrateApplication<OpenApi.IJsonSchema, Operation>; | ||
options: IHttpLlmApplication.IOptions<Model, Parameters["properties"][string]>; | ||
options: IHttpLlmApplication.IOptions<Model, Parameters["properties"][string] extends IHttpLlmApplication.ModelSchema[Model] ? Parameters["properties"][string] : IHttpLlmApplication.ModelSchema[Model]>; | ||
}) => IHttpLlmApplication<Model, Parameters, Operation, Route>; | ||
@@ -13,0 +13,0 @@ const separateParameters: <Model extends IHttpLlmApplication.Model, Parameters extends IHttpLlmApplication.ModelParameters[Model] = IHttpLlmApplication.ModelParameters[Model]>(props: { |
@@ -125,5 +125,5 @@ "use strict"; | ||
return CASTERS[props.model]({ | ||
options: props.options, | ||
schema: s, | ||
components: props.components, | ||
recursive: props.options.recursive, | ||
schema: s, | ||
$defs: $defs, | ||
@@ -213,6 +213,31 @@ }); | ||
var CASTERS = { | ||
"3.0": function (props) { return LlmConverterV3_2.LlmConverterV3.schema(props); }, | ||
"3.1": function (props) { return LlmConverterV3_1_1.LlmConverterV3_1.schema(props); }, | ||
chatgpt: function (props) { return ChatGptConverter_1.ChatGptConverter.schema(props); }, | ||
gemini: function (props) { return GeminiConverter_1.GeminiConverter.schema(props); }, | ||
"3.0": function (props) { | ||
return LlmConverterV3_2.LlmConverterV3.schema({ | ||
components: props.components, | ||
schema: props.schema, | ||
recursive: props.options.recursive, | ||
}); | ||
}, | ||
"3.1": function (props) { | ||
return LlmConverterV3_1_1.LlmConverterV3_1.schema({ | ||
components: props.components, | ||
schema: props.schema, | ||
recursive: props.options.recursive, | ||
}); | ||
}, | ||
chatgpt: function (props) { | ||
return ChatGptConverter_1.ChatGptConverter.schema({ | ||
components: props.components, | ||
schema: props.schema, | ||
$defs: props.$defs, | ||
options: props.options, | ||
}); | ||
}, | ||
gemini: function (props) { | ||
return GeminiConverter_1.GeminiConverter.schema({ | ||
components: props.components, | ||
schema: props.schema, | ||
recursive: props.options.recursive, | ||
}); | ||
}, | ||
}; | ||
@@ -219,0 +244,0 @@ var SEPARATORS = { |
@@ -64,3 +64,3 @@ import { OpenApi } from "./OpenApi"; | ||
document: OpenApi.IDocument<OpenApi.IJsonSchema, Operation> | IHttpMigrateApplication<OpenApi.IJsonSchema, Operation>; | ||
options?: Partial<IHttpLlmApplication.IOptions<Model, Parameters["properties"][string]>>; | ||
options?: Partial<IHttpLlmApplication.IOptions<Model, Parameters["properties"][string] extends IHttpLlmApplication.ModelSchema[Model] ? Parameters["properties"][string] : IHttpLlmApplication.ModelSchema[Model]>>; | ||
}) => IHttpLlmApplication<Model, Parameters>; | ||
@@ -67,0 +67,0 @@ /** |
@@ -61,3 +61,3 @@ "use strict"; | ||
HttpLlm.application = function (props) { | ||
var _a, _b, _c, _d; | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; | ||
// MIGRATE | ||
@@ -70,8 +70,12 @@ var migrate = props.document["x-samchon-emended"] === true | ||
model: props.model, | ||
options: { | ||
separate: (_b = (_a = props.options) === null || _a === void 0 ? void 0 : _a.separate) !== null && _b !== void 0 ? _b : null, | ||
recursive: (props.model === "chatgpt" | ||
? undefined | ||
: ((_d = (_c = props.options) === null || _c === void 0 ? void 0 : _c.recursive) !== null && _d !== void 0 ? _d : 3)), | ||
}, | ||
options: (props.model === "chatgpt" | ||
? { | ||
separate: (_b = (_a = props.options) === null || _a === void 0 ? void 0 : _a.separate) !== null && _b !== void 0 ? _b : null, | ||
reference: (_d = (_c = props.options) === null || _c === void 0 ? void 0 : _c.reference) !== null && _d !== void 0 ? _d : false, | ||
constraint: (_f = (_e = props.options) === null || _e === void 0 ? void 0 : _e.constraint) !== null && _f !== void 0 ? _f : true, | ||
} | ||
: { | ||
separate: (_h = (_g = props.options) === null || _g === void 0 ? void 0 : _g.separate) !== null && _h !== void 0 ? _h : null, | ||
recursive: (_k = (_j = props.options) === null || _j === void 0 ? void 0 : _j.recursive) !== null && _k !== void 0 ? _k : 3, | ||
}), | ||
}); | ||
@@ -78,0 +82,0 @@ }; |
@@ -32,5 +32,5 @@ import { OpenApiV3 } from "./OpenApiV3"; | ||
* - Tuple type utilizes only {@link OpenApi.IJsonSchema.ITuple.prefixItems} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAllOf} to {@link OpenApi.IJsonSchema.IObject} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAnyOf} to {@link OpenApi.IJsonSchema.IOneOf} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IRecursiveReference} to {@link OpenApi.IJsonSchema.IReference} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAllOf} to {@link OpenApi.IJsonSchema.IObject} | ||
* | ||
@@ -492,5 +492,5 @@ * @author Jeongho Nam - https://github.com/samchon | ||
* - Tuple type utilizes only {@link OpenApi.IJsonSchema.ITuple.prefixItems} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAllOf} to {@link OpenApi.IJsonSchema.IObject} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAnyOf} to {@link OpenApi.IJsonSchema.IOneOf} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IRecursiveReference} to {@link OpenApi.IJsonSchema.IReference} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAllOf} to {@link OpenApi.IJsonSchema.IObject} | ||
*/ | ||
@@ -497,0 +497,0 @@ type IJsonSchema = IJsonSchema.IConstant | IJsonSchema.IBoolean | IJsonSchema.IInteger | IJsonSchema.INumber | IJsonSchema.IString | IJsonSchema.IArray | IJsonSchema.ITuple | IJsonSchema.IObject | IJsonSchema.IReference | IJsonSchema.IOneOf | IJsonSchema.INull | IJsonSchema.IUnknown; |
@@ -40,5 +40,5 @@ "use strict"; | ||
* - Tuple type utilizes only {@link OpenApi.IJsonSchema.ITuple.prefixItems} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAllOf} to {@link OpenApi.IJsonSchema.IObject} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAnyOf} to {@link OpenApi.IJsonSchema.IOneOf} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IRecursiveReference} to {@link OpenApi.IJsonSchema.IReference} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAllOf} to {@link OpenApi.IJsonSchema.IObject} | ||
* | ||
@@ -45,0 +45,0 @@ * @author Jeongho Nam - https://github.com/samchon |
@@ -1,2 +0,62 @@ | ||
export type IChatGptSchema = IChatGptSchema.IBoolean | IChatGptSchema.IInteger | IChatGptSchema.INumber | IChatGptSchema.IString | IChatGptSchema.IArray | IChatGptSchema.ITuple | IChatGptSchema.IObject | IChatGptSchema.IReference | IChatGptSchema.IAnyOf | IChatGptSchema.INull | IChatGptSchema.IUnknown; | ||
/** | ||
* Type schema info of the ChatGPT. | ||
* | ||
* `IChatGptSchema` is a type schema info of the ChatGPT function calling. | ||
* | ||
* `IChatGptSchema` basically follows the JSON schema definition of the OpenAPI v3.1 | ||
* speciifcation; {@link OpenApiV3_1.IJsonSchema}. | ||
* | ||
* However, the `IChatGptSchema` does not follow the entire specification of | ||
* the OpenAPI v3.1. It has own specific restrictions and definitions. Here is the | ||
* list of how `IChatGptSchema` is different with the OpenAPI v3.1 JSON schema. | ||
* | ||
* - Decompose mixed type: {@link OpenApiV3_1.IJsonSchema.IMixed} | ||
* - Resolve nullable property: {@link OpenApiV3_1.IJsonSchema.__ISignificant.nullable} | ||
* - Tuple type is banned: {@link OpenApiV3_1.IJsonSchema.ITuple.prefixItems} | ||
* - Constant type is banned: {@link OpenApiV3_1.IJsonSchema.IConstant} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IOneOf} to {@link IChatGptSchema.IAnOf} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAllOf} to {@link IChatGptSchema.IObject} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IRecursiveReference} to {@link IChatGptSchema.IReference} | ||
* - Forcibly transform every object properties to be required | ||
* | ||
* If compare with the {@link OpenApi.IJsonSchema}, the emended JSON schema type of | ||
* | ||
* - {@link IChatGptSchema.IAnyOf} instead of the {@link OpenApi.IJsonSchema.IOneOf} | ||
* - {@link IChatGptSchema.IParameters.$defs} instead of the {@link OpenApi.IJsonSchema.IComponents.schemas} | ||
* - {@link IChatGptSchema.IString.enum} instead of the {@link OpenApi.IJsonSchema.IConstant} | ||
* - No tuple type {@link OpenApi.IJsonSchema.ITuple} support | ||
* - Forcibly transform every object properties to be required | ||
* | ||
* For reference, if you've composed the `IChatGptSchema` type with the | ||
* {@link ILlmApplication.IChatGptOptions.escape} `true` option, only the recursived | ||
* named types would be archived into the {@link IChatGptSchema.IParameters.$defs}, | ||
* and the others would be ecaped from the {@link IChatGptSchema.IReference} type. | ||
* | ||
* Also, if you've composed the `IChatGptSchema` type with the | ||
* {@link ILlmApplication.IChatGptOptions.constraint} `false` option, the | ||
* `IChatGptSchema` would not compose these properties. Instead, these | ||
* properties would be written on {@link IChatGptSchema.__IAttribute.descripotion} | ||
* field like `@format uuid` case. | ||
* | ||
* - {@link IChatGptSchema.INumber.minimum} | ||
* - {@link IChatGptSchema.INumber.maximum} | ||
* - {@link IChatGptSchema.INumber.multipleOf} | ||
* - {@link IChatGptSchema.IString.minLength} | ||
* - {@link IChatGptSchema.IString.maxLength} | ||
* - {@link IChatGptSchema.IString.format} | ||
* - {@link IChatGptSchema.IString.pattern} | ||
* - {@link IChatGptSchema.IString.contentMediaType} | ||
* - {@link IChatGptSchema.IArray.minItems} | ||
* - {@link IChatGptSchema.IArray.maxItems} | ||
* - {@link IChatGptSchema.IArray.unique} | ||
* | ||
* @reference https://platform.openai.com/docs/guides/function-calling | ||
* @reference https://platform.openai.com/docs/guides/structured-outputs | ||
* @warning Specified not by the ChatGPT documentation, but by my experiments. | ||
* Therefore, its definitions can be inaccurate or be changed in the future. | ||
* If you find any wrong or outdated definitions, please let me know by issue | ||
* @issue https://github.com/samchon/openapi/issues | ||
* @author Jeongho Nam - https://github.com/samchon | ||
*/ | ||
export type IChatGptSchema = IChatGptSchema.IBoolean | IChatGptSchema.IInteger | IChatGptSchema.INumber | IChatGptSchema.IString | IChatGptSchema.IArray | IChatGptSchema.IObject | IChatGptSchema.IReference | IChatGptSchema.IAnyOf | IChatGptSchema.INull | IChatGptSchema.IUnknown; | ||
export declare namespace IChatGptSchema { | ||
@@ -198,55 +258,2 @@ /** | ||
/** | ||
* Tuple type info. | ||
*/ | ||
interface ITuple extends __ISignificant<"array"> { | ||
/** | ||
* Prefix items. | ||
* | ||
* The `prefixItems` means the type schema info of the prefix items in the | ||
* tuple type. In the TypeScript, it is expressed as `[T1, T2]`. | ||
* | ||
* If you want to express `[T1, T2, ...TO[]]` type, you can configure the | ||
* `...TO[]` through the {@link additionalItems} property. | ||
*/ | ||
prefixItems: IChatGptSchema[]; | ||
/** | ||
* Additional items. | ||
* | ||
* The `additionalItems` means the type schema info of the additional items | ||
* after the {@link prefixItems}. In the TypeScript, if there's a type | ||
* `[T1, T2, ...TO[]]`, the `...TO[]` is represented by the `additionalItems`. | ||
* | ||
* By the way, if you configure the `additionalItems` as `true`, it means | ||
* the additional items are not restricted. They can be any type, so that | ||
* it is equivalent to the TypeScript type `[T1, T2, ...any[]]`. | ||
* | ||
* Otherwise configure the `additionalItems` as the {@link IJsonSchema}, | ||
* it means the additional items must follow the type schema info. | ||
* Therefore, it is equivalent to the TypeScript type `[T1, T2, ...TO[]]`. | ||
*/ | ||
additionalItems?: boolean | IChatGptSchema; | ||
/** | ||
* Unique items restriction. | ||
* | ||
* If this property value is `true`, target tuple must have unique items. | ||
*/ | ||
uniqueItems?: boolean; | ||
/** | ||
* Minimum items restriction. | ||
* | ||
* Restriction of minumum number of items in the tuple. | ||
* | ||
* @type uint64 | ||
*/ | ||
minItems?: number; | ||
/** | ||
* Maximum items restriction. | ||
* | ||
* Restriction of maximum number of items in the tuple. | ||
* | ||
* @type uint64 | ||
*/ | ||
maxItems?: number; | ||
} | ||
/** | ||
* Object type info. | ||
@@ -253,0 +260,0 @@ */ |
@@ -6,2 +6,3 @@ import { OpenApi } from "../OpenApi"; | ||
import { IHttpMigrateRoute } from "./IHttpMigrateRoute"; | ||
import { ILlmApplication } from "./ILlmApplication"; | ||
import { ILlmSchemaV3 } from "./ILlmSchemaV3"; | ||
@@ -96,3 +97,3 @@ import { ILlmSchemaV3_1 } from "./ILlmSchemaV3_1"; | ||
*/ | ||
options: IHttpLlmApplication.IOptions<Model, Parameters["properties"][string]>; | ||
options: IHttpLlmApplication.IOptions<Model, Parameters["properties"][string] extends IHttpLlmApplication.ModelSchema[Model] ? Parameters["properties"][string] : IHttpLlmApplication.ModelSchema[Model]>; | ||
} | ||
@@ -147,46 +148,5 @@ export declare namespace IHttpLlmApplication { | ||
} | ||
/** | ||
* Options for composing the LLM application. | ||
*/ | ||
interface IOptions<Model extends IHttpLlmApplication.Model, Schema extends ILlmSchemaV3 | ILlmSchemaV3_1 | IChatGptSchema | IGeminiSchema = IHttpLlmApplication.ModelSchema[Model]> { | ||
/** | ||
* Whether to allow recursive types or not. | ||
* | ||
* If allow, then how many times to repeat the recursive types. | ||
* | ||
* By the way, if the model is "chatgpt", the recursive types are always | ||
* allowed without any limitation, due to it supports the reference type. | ||
* | ||
* @default 3 | ||
*/ | ||
recursive: Model extends "chatgpt" ? never : false | number; | ||
/** | ||
* Separator function for the parameters. | ||
* | ||
* When composing parameter arguments through LLM function call, | ||
* there can be a case that some parameters must be composed by Human, | ||
* or LLM cannot understand the parameter. For example, if the | ||
* parameter type has configured | ||
* {@link ILlmSchemaV3.IString.contentMediaType} which indicates file | ||
* uploading, it must be composed by Human, not by LLM | ||
* (Large Language Model). | ||
* | ||
* In that case, if you configure this property with a function that | ||
* predicating whether the schema value must be composed by Human or | ||
* not, the parameters would be separated into two parts. | ||
* | ||
* - {@link IHttpLlmFunction.separated.llm} | ||
* - {@link IHttpLlmFunction.separated.Human} | ||
* | ||
* When writing the function, note that returning value `true` means | ||
* to be a Human composing the value, and `false` means to LLM | ||
* composing the value. Also, when predicating the schema, it would | ||
* better to utilize the {@link LlmTypeChecker} features. | ||
* | ||
* @param schema Schema to be separated. | ||
* @returns Whether the schema value must be composed by Human or not. | ||
* @default null | ||
*/ | ||
separate: null | ((schema: Schema) => boolean); | ||
} | ||
export import IOptions = ILlmApplication.IOptions; | ||
export import ICommonOptions = ILlmApplication.ICommonOptions; | ||
export import IChatGptOptions = ILlmApplication.IChatGptOptions; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.IHttpLlmApplication = void 0; | ||
var IHttpLlmApplication; | ||
(function (IHttpLlmApplication) { | ||
})(IHttpLlmApplication || (exports.IHttpLlmApplication = IHttpLlmApplication = {})); |
@@ -50,3 +50,3 @@ import { IChatGptSchema } from "./IChatGptSchema"; | ||
*/ | ||
options: ILlmApplication.IOptions<Model, Parameters["properties"][string]>; | ||
options: ILlmApplication.IOptions<Model, Parameters["properties"][string] extends ILlmApplication.ModelSchema[Model] ? Parameters["properties"][string] : ILlmApplication.ModelSchema[Model]>; | ||
} | ||
@@ -70,3 +70,7 @@ export declare namespace ILlmApplication { | ||
*/ | ||
interface IOptions<Model extends ILlmApplication.Model, Schema extends ILlmSchemaV3 | ILlmSchemaV3_1 | IChatGptSchema | IGeminiSchema = ILlmApplication.ModelSchema[Model]> { | ||
type IOptions<Model extends ILlmApplication.Model, Schema extends ILlmApplication.ModelSchema[Model] = ILlmApplication.ModelSchema[Model]> = Model extends "chatgpt" ? IChatGptOptions<Schema extends IChatGptSchema ? Schema : IChatGptSchema> : ICommonOptions<Exclude<Model, "chatgpt">, Schema extends ILlmApplication.ModelSchema[Exclude<Model, "chatgpt">] ? Schema : ILlmApplication.ModelSchema[Exclude<Model, "chatgpt">]>; | ||
/** | ||
* Options for non "chatgpt" model. | ||
*/ | ||
interface ICommonOptions<Model extends Exclude<ILlmApplication.Model, "chatgpt">, Schema extends ILlmApplication.ModelSchema[Model] = ILlmApplication.ModelSchema[Model]> { | ||
/** | ||
@@ -82,3 +86,3 @@ * Whether to allow recursive types or not. | ||
*/ | ||
recursive: Model extends "chatgpt" ? never : false | number; | ||
recursive: false | number; | ||
/** | ||
@@ -113,2 +117,84 @@ * Separator function for the parameters. | ||
} | ||
/** | ||
* Options for "chatgpt" model. | ||
*/ | ||
interface IChatGptOptions<Schema extends IChatGptSchema = IChatGptSchema> { | ||
/** | ||
* Separator function for the parameters. | ||
* | ||
* When composing parameter arguments through LLM function call, | ||
* there can be a case that some parameters must be composed by human, | ||
* or LLM cannot understand the parameter. For example, if the | ||
* parameter type has configured | ||
* {@link IChatGptSchema.IString.contentMediaType} which indicates file | ||
* uploading, it must be composed by human, not by LLM | ||
* (Large Language Model). | ||
* | ||
* In that case, if you configure this property with a function that | ||
* predicating whether the schema value must be composed by human or | ||
* not, the parameters would be separated into two parts. | ||
* | ||
* - {@link ILlmFunction.separated.llm} | ||
* - {@link ILlmFunction.separated.human} | ||
* | ||
* When writing the function, note that returning value `true` means | ||
* to be a human composing the value, and `false` means to LLM | ||
* composing the value. Also, when predicating the schema, it would | ||
* better to utilize the {@link ChatGptTypeChecker} features. | ||
* | ||
* @param schema Schema to be separated. | ||
* @returns Whether the schema value must be composed by human or not. | ||
* @default null | ||
*/ | ||
separate: null | ((schema: Schema) => boolean); | ||
/** | ||
* Whether to allow reference type in everywhere. | ||
* | ||
* If you configure this property to `false`, most of reference types | ||
* represented by {@link IChatGptSchema.IReference} would be escaped to | ||
* a plain type unless recursive type case. | ||
* | ||
* This is because the lower version of ChatGPT does not understand the | ||
* reference type well, and even the modern version of ChatGPT sometimes occur | ||
* the hallucination. | ||
* | ||
* However, the reference type makes the schema size smaller, so that reduces | ||
* the LLM token cost. Therefore, if you're using the modern version of ChatGPT, | ||
* and want to reduce the LLM token cost, you can configure this property to | ||
* `true`. | ||
* | ||
* @default false | ||
*/ | ||
reference: boolean; | ||
/** | ||
* Whether to allow contraint properties or not. | ||
* | ||
* If you configure this property to `false`, the schemas do not containt | ||
* the constraint properties of below. Instead, below properties would be | ||
* written to the {@link IChatGptSchema.__IAttribute.description} property | ||
* as a comment string like `"@format uuid"`. | ||
* | ||
* This is because the ChatGPT function calling understands the constraint | ||
* properties when the function parameter types are simple, however it occurs | ||
* some errors when the parameter types are complex. | ||
* | ||
* Therefore, considering the complexity of your parameter types, determine | ||
* which is better, to allow the constraint properties or not. | ||
* | ||
* - {@link IChatGptSchema.INumber.minimum} | ||
* - {@link IChatGptSchema.INumber.maximum} | ||
* - {@link IChatGptSchema.INumber.multipleOf} | ||
* - {@link IChatGptSchema.IString.minLength} | ||
* - {@link IChatGptSchema.IString.maxLength} | ||
* - {@link IChatGptSchema.IString.format} | ||
* - {@link IChatGptSchema.IString.pattern} | ||
* - {@link IChatGptSchema.IString.contentMediaType} | ||
* - {@link IChatGptSchema.IArray.minItems} | ||
* - {@link IChatGptSchema.IArray.maxItems} | ||
* - {@link IChatGptSchema.IArray.unique} | ||
* | ||
* @default false | ||
*/ | ||
constraint: boolean; | ||
} | ||
} |
@@ -10,3 +10,2 @@ import { IChatGptSchema } from "../structures/IChatGptSchema"; | ||
const isArray: (schema: IChatGptSchema) => schema is IChatGptSchema.IArray; | ||
const isTuple: (schema: IChatGptSchema) => schema is IChatGptSchema.ITuple; | ||
const isObject: (schema: IChatGptSchema) => schema is IChatGptSchema.IObject; | ||
@@ -13,0 +12,0 @@ const isReference: (schema: IChatGptSchema) => schema is IChatGptSchema.IReference; |
@@ -61,6 +61,2 @@ "use strict"; | ||
}; | ||
ChatGptTypeChecker.isTuple = function (schema) { | ||
return schema.type === "array" && | ||
schema.prefixItems !== undefined; | ||
}; | ||
ChatGptTypeChecker.isObject = function (schema) { | ||
@@ -80,3 +76,3 @@ return schema.type === "object"; | ||
var e_1, _a; | ||
var _b, _c, _d; | ||
var _b, _c; | ||
props.closure(schema); | ||
@@ -96,4 +92,4 @@ if (ChatGptTypeChecker.isReference(schema)) { | ||
try { | ||
for (var _e = __values(Object.values((_c = schema.properties) !== null && _c !== void 0 ? _c : {})), _f = _e.next(); !_f.done; _f = _e.next()) { | ||
var value = _f.value; | ||
for (var _d = __values(Object.values((_c = schema.properties) !== null && _c !== void 0 ? _c : {})), _e = _d.next(); !_e.done; _e = _d.next()) { | ||
var value = _e.value; | ||
next(value); | ||
@@ -105,3 +101,3 @@ } | ||
try { | ||
if (_f && !_f.done && (_a = _e.return)) _a.call(_e); | ||
if (_e && !_e.done && (_a = _d.return)) _a.call(_d); | ||
} | ||
@@ -116,8 +112,2 @@ finally { if (e_1) throw e_1.error; } | ||
next(schema.items); | ||
else if (ChatGptTypeChecker.isTuple(schema)) { | ||
((_d = schema.prefixItems) !== null && _d !== void 0 ? _d : []).forEach(next); | ||
if (typeof schema.additionalItems === "object" && | ||
schema.additionalItems !== null) | ||
next(schema.additionalItems); | ||
} | ||
}; | ||
@@ -192,3 +182,3 @@ next(props.schema); | ||
else if (ChatGptTypeChecker.isArray(p.x)) | ||
return ((ChatGptTypeChecker.isArray(p.y) || ChatGptTypeChecker.isTuple(p.y)) && | ||
return (ChatGptTypeChecker.isArray(p.y) && | ||
coverArray({ | ||
@@ -213,20 +203,3 @@ $defs: p.$defs, | ||
var coverArray = function (p) { | ||
if (ChatGptTypeChecker.isTuple(p.y)) | ||
return (p.y.prefixItems.every(function (v) { | ||
return coverStation({ | ||
$defs: p.$defs, | ||
visited: p.visited, | ||
x: p.x.items, | ||
y: v, | ||
}); | ||
}) && | ||
(p.y.additionalItems === undefined || | ||
(typeof p.y.additionalItems === "object" && | ||
coverStation({ | ||
$defs: p.$defs, | ||
visited: p.visited, | ||
x: p.x.items, | ||
y: p.y.additionalItems, | ||
})))); | ||
else if (!(p.x.minItems === undefined || | ||
if (!(p.x.minItems === undefined || | ||
(p.y.minItems !== undefined && p.x.minItems <= p.y.minItems))) | ||
@@ -233,0 +206,0 @@ return false; |
@@ -101,3 +101,4 @@ "use strict"; | ||
return false; | ||
var counter = new Map(); | ||
var current = props.schema.$ref.split("#/components/schemas/")[1]; | ||
var counter = 0; | ||
OpenApiTypeChecker.visit({ | ||
@@ -107,10 +108,10 @@ components: props.components, | ||
closure: function (schema) { | ||
var _a; | ||
if (OpenApiTypeChecker.isReference(schema)) { | ||
var key = schema.$ref.split("#/components/schemas/")[1]; | ||
counter.set(key, ((_a = counter.get(key)) !== null && _a !== void 0 ? _a : 0) + 1); | ||
var next = schema.$ref.split("#/components/schemas/")[1]; | ||
if (current === next) | ||
++counter; | ||
} | ||
}, | ||
}); | ||
return Array.from(counter.values()).some(function (v) { return v > 1; }); | ||
return counter > 1; | ||
}; | ||
@@ -117,0 +118,0 @@ /* ----------------------------------------------------------- |
{ | ||
"name": "@samchon/openapi", | ||
"version": "2.0.0-dev.20241119", | ||
"version": "2.0.0-dev.20241120", | ||
"description": "OpenAPI definitions and converters for 'typia' and 'nestia'.", | ||
@@ -5,0 +5,0 @@ "main": "./lib/index.js", |
import { OpenApi } from "../OpenApi"; | ||
import { IChatGptSchema } from "../structures/IChatGptSchema"; | ||
import { ILlmApplication } from "../structures/ILlmApplication"; | ||
import { ChatGptTypeChecker } from "../utils/ChatGptTypeChecker"; | ||
@@ -8,2 +9,3 @@ import { OpenApiTypeChecker } from "../utils/OpenApiTypeChecker"; | ||
export const parameters = (props: { | ||
options: Omit<ILlmApplication.IChatGptOptions, "separate">; | ||
components: OpenApi.IComponents; | ||
@@ -14,2 +16,3 @@ schema: OpenApi.IJsonSchema.IObject; | ||
const res: IChatGptSchema.IParameters | null = schema({ | ||
options: props.options, | ||
components: props.components, | ||
@@ -25,7 +28,8 @@ schema: props.schema, | ||
export const schema = (props: { | ||
options: Omit<ILlmApplication.IChatGptOptions, "separate">; | ||
components: OpenApi.IComponents; | ||
$defs: Record<string, IChatGptSchema>; | ||
schema: OpenApi.IJsonSchema; | ||
$defs: Record<string, IChatGptSchema>; | ||
}): IChatGptSchema | null => { | ||
const union: Array<IChatGptSchema | null> = []; | ||
const union: Array<IUnionElement> = []; | ||
const attribute: IChatGptSchema.__IAttribute = { | ||
@@ -43,66 +47,49 @@ title: props.schema.title, | ||
const visit = (input: OpenApi.IJsonSchema): number => { | ||
if (OpenApiTypeChecker.isReference(props.schema)) { | ||
const key: string = props.schema.$ref.split("#/components/schemas/")[1]; | ||
if (OpenApiTypeChecker.isOneOf(input)) { | ||
input.oneOf.forEach(visit); | ||
return 0; | ||
} else if (OpenApiTypeChecker.isReference(input)) { | ||
const key: string = input.$ref.split("#/components/schemas/")[1]; | ||
const target: OpenApi.IJsonSchema | undefined = | ||
props.components.schemas?.[key]; | ||
if (target === undefined) return 0; | ||
const out = () => | ||
union.push({ | ||
...props.schema, | ||
$ref: `#/$defs/${key}`, | ||
} as IChatGptSchema); | ||
if (props.$defs[key] !== undefined) return out(); | ||
props.$defs[key] = {}; | ||
const converted: IChatGptSchema | null = schema({ | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: target, | ||
}); | ||
if (converted === null) return union.push(null); | ||
props.$defs[key] = converted; | ||
return out(); | ||
} else if (OpenApiTypeChecker.isArray(props.schema)) { | ||
const items: IChatGptSchema | null = schema({ | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: props.schema.items, | ||
}); | ||
if (items === null) return union.push(null); | ||
return union.push({ | ||
...props.schema, | ||
items, | ||
}); | ||
} else if (OpenApiTypeChecker.isTuple(props.schema)) { | ||
const prefixItems: Array<IChatGptSchema | null> = | ||
props.schema.prefixItems.map((item) => | ||
schema({ | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: item, | ||
}), | ||
); | ||
if (prefixItems.some((v) => v === null)) return union.push(null); | ||
const additionalItems = | ||
props.schema.additionalItems === undefined | ||
? false | ||
: typeof props.schema.additionalItems === "object" && | ||
props.schema.additionalItems !== null | ||
? schema({ | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: props.schema.additionalItems, | ||
}) | ||
: props.schema.additionalItems; | ||
if (additionalItems === null) return union.push(null); | ||
return union.push({ | ||
...props.schema, | ||
prefixItems: prefixItems.filter((v) => v !== null), | ||
additionalItems, | ||
}); | ||
} else if (OpenApiTypeChecker.isObject(props.schema)) { | ||
if ( | ||
props.options.reference === true || | ||
OpenApiTypeChecker.isRecursiveReference({ | ||
components: props.components, | ||
schema: input, | ||
}) | ||
) { | ||
const out = () => | ||
union.push({ | ||
schema: { | ||
...input, | ||
$ref: `#/$defs/${key}`, | ||
title: undefined, | ||
description: undefined, | ||
}, | ||
tags: [], | ||
}); | ||
if (props.$defs[key] !== undefined) return out(); | ||
props.$defs[key] = {}; | ||
const converted: IChatGptSchema | null = schema({ | ||
options: props.options, | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: target, | ||
}); | ||
if (converted === null) | ||
return union.push({ | ||
schema: null, | ||
tags: [], | ||
}); | ||
props.$defs[key] = converted; | ||
return out(); | ||
} else return visit(target); | ||
} else if (OpenApiTypeChecker.isObject(input)) { | ||
const properties: Record<string, IChatGptSchema | null> = | ||
Object.entries(props.schema.properties || {}).reduce( | ||
Object.entries(input.properties || {}).reduce( | ||
(acc, [key, value]) => { | ||
const converted: IChatGptSchema | null = schema({ | ||
options: props.options, | ||
components: props.components, | ||
@@ -119,49 +106,141 @@ $defs: props.$defs, | ||
if (Object.values(properties).some((v) => v === null)) | ||
return union.push(null); | ||
return union.push({ | ||
schema: null, | ||
tags: [], | ||
}); | ||
const additionalProperties = | ||
props.schema.additionalProperties === undefined | ||
input.additionalProperties === undefined | ||
? false | ||
: typeof props.schema.additionalProperties === "object" && | ||
props.schema.additionalProperties !== null | ||
: typeof input.additionalProperties === "object" && | ||
input.additionalProperties !== null | ||
? schema({ | ||
options: props.options, | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: props.schema.additionalProperties, | ||
schema: input.additionalProperties, | ||
}) | ||
: props.schema.additionalProperties; | ||
if (additionalProperties === null) return union.push(null); | ||
: input.additionalProperties; | ||
if (additionalProperties === null) | ||
return union.push({ | ||
schema: null, | ||
tags: [], | ||
}); | ||
return union.push({ | ||
...props.schema, | ||
properties: properties as Record<string, IChatGptSchema>, | ||
additionalProperties, | ||
schema: { | ||
...input, | ||
properties: properties as Record<string, IChatGptSchema>, | ||
additionalProperties, | ||
required: Object.keys(properties), | ||
}, | ||
tags: [], | ||
}); | ||
} else if (OpenApiTypeChecker.isOneOf(props.schema)) { | ||
const oneOf: Array<IChatGptSchema | null> = props.schema.oneOf | ||
.filter((e) => !OpenApiTypeChecker.isConstant(e)) | ||
.map((item) => | ||
schema({ | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: item, | ||
}), | ||
); | ||
return union.push(...oneOf); | ||
} else if (OpenApiTypeChecker.isConstant(input)) return 0; | ||
else return union.push(input); | ||
} else if (OpenApiTypeChecker.isArray(input)) { | ||
const items: IChatGptSchema | null = schema({ | ||
options: props.options, | ||
components: props.components, | ||
$defs: props.$defs, | ||
schema: input.items, | ||
}); | ||
if (items === null) | ||
return union.push({ | ||
schema: null, | ||
tags: props.options.constraint ? [] : getArrayTags(input), | ||
}); | ||
return union.push({ | ||
schema: { | ||
...input, | ||
items, | ||
...(props.options.constraint | ||
? {} | ||
: { | ||
maxItems: undefined, | ||
minItems: undefined, | ||
}), | ||
}, | ||
tags: props.options.constraint ? [] : getArrayTags(input), | ||
}); | ||
} else if (OpenApiTypeChecker.isString(input)) | ||
return union.push({ | ||
schema: { | ||
...input, | ||
...(props.options.constraint | ||
? {} | ||
: { | ||
contentMediaType: undefined, | ||
minLength: undefined, | ||
maxLength: undefined, | ||
format: undefined, | ||
pattern: undefined, | ||
}), | ||
}, | ||
tags: props.options.constraint ? [] : getStringTags(input), | ||
}); | ||
else if ( | ||
OpenApiTypeChecker.isNumber(input) || | ||
OpenApiTypeChecker.isInteger(input) | ||
) | ||
return union.push({ | ||
schema: { | ||
...input, | ||
...(props.options.constraint | ||
? {} | ||
: { | ||
maximum: undefined, | ||
minimum: undefined, | ||
exclusiveMaximum: undefined, | ||
exclusiveMinimum: undefined, | ||
multipleOf: undefined, | ||
}), | ||
}, | ||
tags: props.options.constraint ? [] : getNumericTags(input), | ||
}); | ||
else if (OpenApiTypeChecker.isConstant(input)) return 0; | ||
else if (OpenApiTypeChecker.isTuple(input)) | ||
return union.push({ | ||
schema: null, | ||
tags: [], | ||
}); | ||
else | ||
return union.push({ | ||
schema: { ...input }, | ||
tags: [], | ||
}); | ||
}; | ||
const visitConstant = (schema: OpenApi.IJsonSchema): void => { | ||
const visitConstant = (input: OpenApi.IJsonSchema): void => { | ||
const insert = (value: any): void => { | ||
const matched: IChatGptSchema.INumber | undefined = union.find( | ||
(u) => | ||
(u as IChatGptSchema.__ISignificant<any>).type === typeof value, | ||
) as IChatGptSchema.INumber | undefined; | ||
const matched: IUnionElement<IChatGptSchema.IString> | undefined = | ||
union.find( | ||
(u) => | ||
(u.schema as IChatGptSchema.__ISignificant<any>)?.type === | ||
typeof value, | ||
) as IUnionElement<IChatGptSchema.IString> | undefined; | ||
if (matched !== undefined) { | ||
matched.enum ??= []; | ||
matched.enum.push(value); | ||
} else union.push({ type: typeof value as "number", enum: [value] }); | ||
matched.schema!.enum ??= []; | ||
matched.schema!.enum.push(value); | ||
} else | ||
union.push({ | ||
schema: { | ||
type: typeof value as "number", | ||
enum: [value], | ||
}, | ||
tags: [], | ||
}); | ||
}; | ||
if (OpenApiTypeChecker.isConstant(schema)) insert(schema.const); | ||
else if (OpenApiTypeChecker.isOneOf(schema)) | ||
for (const u of schema.oneOf) | ||
if (OpenApiTypeChecker.isConstant(u)) insert(u.const); | ||
if (OpenApiTypeChecker.isConstant(input)) insert(input.const); | ||
else if (OpenApiTypeChecker.isOneOf(input)) | ||
input.oneOf.forEach(visitConstant); | ||
else if ( | ||
props.options.reference === false && | ||
OpenApiTypeChecker.isReference(input) && | ||
OpenApiTypeChecker.isRecursiveReference({ | ||
components: props.components, | ||
schema: input, | ||
}) === false | ||
) { | ||
const target: OpenApi.IJsonSchema | undefined = | ||
props.components.schemas?.[ | ||
input.$ref.split("#/components/schemas/")[1] | ||
]; | ||
if (target !== undefined) visitConstant(target); | ||
} | ||
}; | ||
@@ -180,121 +259,22 @@ visit(props.schema); | ||
...attribute, | ||
...union[0], | ||
...union[0].schema, | ||
description: ChatGptTypeChecker.isReference(union[0].schema!) | ||
? undefined | ||
: writeTagWithDescription({ | ||
description: attribute.description, | ||
tags: union[0].tags, | ||
}), | ||
}; | ||
return { | ||
...attribute, | ||
anyOf: union as IChatGptSchema[], | ||
anyOf: union.map((u) => ({ | ||
...u.schema, | ||
description: ChatGptTypeChecker.isReference(u.schema!) | ||
? undefined | ||
: writeTagWithDescription({ | ||
description: u.schema?.description, | ||
tags: u.tags, | ||
}), | ||
})), | ||
}; | ||
// if (OpenApiTypeChecker.isReference(props.schema)) { | ||
// const key: string = props.schema.$ref.split("#/components/schemas/")[1]; | ||
// const target: OpenApi.IJsonSchema | undefined = | ||
// props.components.schemas?.[key]; | ||
// if (target === undefined) return null; | ||
// const out = () => ({ | ||
// ...props.schema, | ||
// $ref: `#/$defs/${key}`, | ||
// }); | ||
// if (props.$defs[key] !== undefined) return out(); | ||
// props.$defs[key] = {}; | ||
// const converted: IChatGptSchema | null = schema({ | ||
// components: props.components, | ||
// $defs: props.$defs, | ||
// schema: target, | ||
// }); | ||
// if (converted === null) return null; | ||
// props.$defs[key] = converted; | ||
// return out(); | ||
// } else if (OpenApiTypeChecker.isArray(props.schema)) { | ||
// const items: IChatGptSchema | null = schema({ | ||
// components: props.components, | ||
// $defs: props.$defs, | ||
// schema: props.schema.items, | ||
// }); | ||
// if (items === null) return null; | ||
// return { | ||
// ...props.schema, | ||
// items, | ||
// }; | ||
// } else if (OpenApiTypeChecker.isTuple(props.schema)) { | ||
// const prefixItems: Array<IChatGptSchema | null> = | ||
// props.schema.prefixItems.map((item) => | ||
// schema({ | ||
// components: props.components, | ||
// $defs: props.$defs, | ||
// schema: item, | ||
// }), | ||
// ); | ||
// if (prefixItems.some((v) => v === null)) return null; | ||
// const additionalItems = | ||
// props.schema.additionalItems === undefined | ||
// ? false | ||
// : typeof props.schema.additionalItems === "object" && | ||
// props.schema.additionalItems !== null | ||
// ? schema({ | ||
// components: props.components, | ||
// $defs: props.$defs, | ||
// schema: props.schema.additionalItems, | ||
// }) | ||
// : props.schema.additionalItems; | ||
// if (additionalItems === null) return null; | ||
// return { | ||
// ...props.schema, | ||
// prefixItems: prefixItems.filter((v) => v !== null), | ||
// additionalItems, | ||
// }; | ||
// } else if (OpenApiTypeChecker.isObject(props.schema)) { | ||
// const properties: Record<string, IChatGptSchema | null> = Object.entries( | ||
// props.schema.properties || {}, | ||
// ).reduce( | ||
// (acc, [key, value]) => { | ||
// const converted: IChatGptSchema | null = schema({ | ||
// components: props.components, | ||
// $defs: props.$defs, | ||
// schema: value, | ||
// }); | ||
// if (converted === null) return acc; | ||
// acc[key] = converted; | ||
// return acc; | ||
// }, | ||
// {} as Record<string, IChatGptSchema | null>, | ||
// ); | ||
// if (Object.values(properties).some((v) => v === null)) return null; | ||
// const additionalProperties = | ||
// props.schema.additionalProperties === undefined | ||
// ? false | ||
// : typeof props.schema.additionalProperties === "object" && | ||
// props.schema.additionalProperties !== null | ||
// ? schema({ | ||
// components: props.components, | ||
// $defs: props.$defs, | ||
// schema: props.schema.additionalProperties, | ||
// }) | ||
// : props.schema.additionalProperties; | ||
// if (additionalProperties === null) return null; | ||
// return { | ||
// ...props.schema, | ||
// properties: properties as Record<string, IChatGptSchema>, | ||
// additionalProperties, | ||
// }; | ||
// } else if (OpenApiTypeChecker.isOneOf(props.schema)) { | ||
// const oneOf: Array<IChatGptSchema | null> = props.schema.oneOf.map( | ||
// (item) => | ||
// schema({ | ||
// components: props.components, | ||
// $defs: props.$defs, | ||
// schema: item, | ||
// }), | ||
// ); | ||
// if (oneOf.some((v) => v === null)) return null; | ||
// return { | ||
// ...props.schema, | ||
// anyOf: oneOf.filter((v) => v !== null), | ||
// ...{ | ||
// oneOf: undefined, | ||
// }, | ||
// }; | ||
// } | ||
// return props.schema; | ||
}; | ||
@@ -475,2 +455,52 @@ | ||
}; | ||
const getNumericTags = ( | ||
schema: OpenApi.IJsonSchema.IInteger | OpenApi.IJsonSchema.INumber, | ||
) => [ | ||
...(schema.minimum !== undefined | ||
? schema.exclusiveMinimum === true | ||
? [`@exclusiveMinimum ${schema.minimum}`] | ||
: [`@minimum ${schema.minimum}`] | ||
: []), | ||
...(schema.maximum !== undefined | ||
? schema.exclusiveMaximum === true | ||
? [`@exclusiveMaximum ${schema.maximum}`] | ||
: [`@maximum ${schema.maximum}`] | ||
: []), | ||
...(schema.multipleOf !== undefined | ||
? [`@multipleOf ${schema.multipleOf}`] | ||
: []), | ||
]; | ||
const getStringTags = (schema: OpenApi.IJsonSchema.IString) => [ | ||
...(schema.minLength !== undefined | ||
? [`@minLength ${schema.minLength}`] | ||
: []), | ||
...(schema.maxLength !== undefined | ||
? [`@maxLength ${schema.maxLength}`] | ||
: []), | ||
...(schema.format !== undefined ? [`@format ${schema.format}`] : []), | ||
...(schema.pattern !== undefined ? [`@pattern ${schema.pattern}`] : []), | ||
]; | ||
const getArrayTags = (schema: OpenApi.IJsonSchema.IArray) => [ | ||
...(schema.minItems !== undefined ? [`@minItems ${schema.minItems}`] : []), | ||
...(schema.maxItems !== undefined ? [`@maxItems ${schema.maxItems}`] : []), | ||
]; | ||
const writeTagWithDescription = (props: { | ||
description: string | undefined; | ||
tags: string[]; | ||
}): string | undefined => { | ||
if (props.tags.length === 0) return props.description; | ||
return [ | ||
...(props.description?.length ? [props.description, "\n"] : []), | ||
...props.tags, | ||
].join("\n"); | ||
}; | ||
} | ||
interface IUnionElement<Schema extends IChatGptSchema = IChatGptSchema> { | ||
schema: Schema | null; | ||
tags: string[]; | ||
} |
@@ -27,3 +27,5 @@ import { OpenApi } from "../OpenApi"; | ||
Model, | ||
Parameters["properties"][string] | ||
Parameters["properties"][string] extends IHttpLlmApplication.ModelSchema[Model] | ||
? Parameters["properties"][string] | ||
: IHttpLlmApplication.ModelSchema[Model] | ||
>; | ||
@@ -138,3 +140,5 @@ }): IHttpLlmApplication<Model, Parameters, Operation, Route> => { | ||
Model, | ||
Parameters["properties"][string] | ||
Parameters["properties"][string] extends IHttpLlmApplication.ModelSchema[Model] | ||
? Parameters["properties"][string] | ||
: IHttpLlmApplication.ModelSchema[Model] | ||
>; | ||
@@ -147,5 +151,5 @@ }): IHttpLlmFunction<Parameters, Operation, Route> | null => { | ||
CASTERS[props.model]({ | ||
options: props.options as any, | ||
schema: s, | ||
components: props.components, | ||
recursive: props.options.recursive, | ||
schema: s, | ||
$defs, | ||
@@ -221,3 +225,3 @@ }) as Parameters["properties"][string] | null; | ||
model: props.model, | ||
predicate: props.options.separate, | ||
predicate: props.options.separate as any, | ||
parameters, | ||
@@ -252,20 +256,41 @@ }) | ||
schema: OpenApi.IJsonSchema; | ||
recursive: false | number; | ||
}) => LlmConverterV3.schema(props), | ||
options: IHttpLlmApplication.IOptions<"3.0">; | ||
}) => | ||
LlmConverterV3.schema({ | ||
components: props.components, | ||
schema: props.schema, | ||
recursive: props.options.recursive, | ||
}), | ||
"3.1": (props: { | ||
components: OpenApi.IComponents; | ||
schema: OpenApi.IJsonSchema; | ||
recursive: false | number; | ||
}) => LlmConverterV3_1.schema(props), | ||
options: IHttpLlmApplication.IOptions<"3.1">; | ||
}) => | ||
LlmConverterV3_1.schema({ | ||
components: props.components, | ||
schema: props.schema, | ||
recursive: props.options.recursive, | ||
}), | ||
chatgpt: (props: { | ||
components: OpenApi.IComponents; | ||
schema: OpenApi.IJsonSchema; | ||
recursive: false | number; | ||
$defs: Record<string, IChatGptSchema>; | ||
}) => ChatGptConverter.schema(props), | ||
options: Omit<IHttpLlmApplication.IChatGptOptions, "separate">; | ||
}) => | ||
ChatGptConverter.schema({ | ||
components: props.components, | ||
schema: props.schema, | ||
$defs: props.$defs, | ||
options: props.options, | ||
}), | ||
gemini: (props: { | ||
components: OpenApi.IComponents; | ||
schema: OpenApi.IJsonSchema; | ||
recursive: false | number; | ||
}) => GeminiConverter.schema(props), | ||
options: IHttpLlmApplication.IOptions<"gemini">; | ||
}) => | ||
GeminiConverter.schema({ | ||
components: props.components, | ||
schema: props.schema, | ||
recursive: props.options.recursive, | ||
}), | ||
}; | ||
@@ -272,0 +297,0 @@ |
@@ -80,3 +80,8 @@ import { HttpMigration } from "./HttpMigration"; | ||
options?: Partial< | ||
IHttpLlmApplication.IOptions<Model, Parameters["properties"][string]> | ||
IHttpLlmApplication.IOptions< | ||
Model, | ||
Parameters["properties"][string] extends IHttpLlmApplication.ModelSchema[Model] | ||
? Parameters["properties"][string] | ||
: IHttpLlmApplication.ModelSchema[Model] | ||
> | ||
>; | ||
@@ -92,11 +97,31 @@ }): IHttpLlmApplication<Model, Parameters> => { | ||
model: props.model, | ||
options: { | ||
separate: props.options?.separate ?? null, | ||
recursive: (props.model === "chatgpt" | ||
? undefined | ||
: (props.options?.recursive ?? 3)) as IHttpLlmApplication.IOptions< | ||
Model, | ||
Parameters["properties"][string] | ||
>["recursive"], | ||
}, | ||
options: (props.model === "chatgpt" | ||
? ({ | ||
separate: | ||
(props.options | ||
?.separate as IHttpLlmApplication.IChatGptOptions["separate"]) ?? | ||
null, | ||
reference: | ||
(props.options as IHttpLlmApplication.IChatGptOptions | undefined) | ||
?.reference ?? false, | ||
constraint: | ||
(props.options as IHttpLlmApplication.IChatGptOptions | undefined) | ||
?.constraint ?? true, | ||
} satisfies IHttpLlmApplication.IChatGptOptions) | ||
: ({ | ||
separate: | ||
(props.options?.separate as IHttpLlmApplication.ICommonOptions< | ||
Exclude<Model, "chatgpt"> | ||
>["separate"]) ?? null, | ||
recursive: | ||
( | ||
props.options as | ||
| IHttpLlmApplication.ICommonOptions< | ||
Exclude<Model, "chatgpt"> | ||
> | ||
| undefined | ||
)?.recursive ?? 3, | ||
} satisfies IHttpLlmApplication.ICommonOptions< | ||
Exclude<Model, "chatgpt"> | ||
>)) as IHttpLlmApplication.IOptions<Model>, | ||
}); | ||
@@ -103,0 +128,0 @@ }; |
@@ -38,5 +38,5 @@ import { OpenApiV3 } from "./OpenApiV3"; | ||
* - Tuple type utilizes only {@link OpenApi.IJsonSchema.ITuple.prefixItems} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAllOf} to {@link OpenApi.IJsonSchema.IObject} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAnyOf} to {@link OpenApi.IJsonSchema.IOneOf} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IRecursiveReference} to {@link OpenApi.IJsonSchema.IReference} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAllOf} to {@link OpenApi.IJsonSchema.IObject} | ||
* | ||
@@ -634,5 +634,5 @@ * @author Jeongho Nam - https://github.com/samchon | ||
* - Tuple type utilizes only {@link OpenApi.IJsonSchema.ITuple.prefixItems} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAllOf} to {@link OpenApi.IJsonSchema.IObject} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAnyOf} to {@link OpenApi.IJsonSchema.IOneOf} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IRecursiveReference} to {@link OpenApi.IJsonSchema.IReference} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAllOf} to {@link OpenApi.IJsonSchema.IObject} | ||
*/ | ||
@@ -639,0 +639,0 @@ export type IJsonSchema = |
@@ -0,1 +1,61 @@ | ||
/** | ||
* Type schema info of the ChatGPT. | ||
* | ||
* `IChatGptSchema` is a type schema info of the ChatGPT function calling. | ||
* | ||
* `IChatGptSchema` basically follows the JSON schema definition of the OpenAPI v3.1 | ||
* speciifcation; {@link OpenApiV3_1.IJsonSchema}. | ||
* | ||
* However, the `IChatGptSchema` does not follow the entire specification of | ||
* the OpenAPI v3.1. It has own specific restrictions and definitions. Here is the | ||
* list of how `IChatGptSchema` is different with the OpenAPI v3.1 JSON schema. | ||
* | ||
* - Decompose mixed type: {@link OpenApiV3_1.IJsonSchema.IMixed} | ||
* - Resolve nullable property: {@link OpenApiV3_1.IJsonSchema.__ISignificant.nullable} | ||
* - Tuple type is banned: {@link OpenApiV3_1.IJsonSchema.ITuple.prefixItems} | ||
* - Constant type is banned: {@link OpenApiV3_1.IJsonSchema.IConstant} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IOneOf} to {@link IChatGptSchema.IAnOf} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IAllOf} to {@link IChatGptSchema.IObject} | ||
* - Merge {@link OpenApiV3_1.IJsonSchema.IRecursiveReference} to {@link IChatGptSchema.IReference} | ||
* - Forcibly transform every object properties to be required | ||
* | ||
* If compare with the {@link OpenApi.IJsonSchema}, the emended JSON schema type of | ||
* | ||
* - {@link IChatGptSchema.IAnyOf} instead of the {@link OpenApi.IJsonSchema.IOneOf} | ||
* - {@link IChatGptSchema.IParameters.$defs} instead of the {@link OpenApi.IJsonSchema.IComponents.schemas} | ||
* - {@link IChatGptSchema.IString.enum} instead of the {@link OpenApi.IJsonSchema.IConstant} | ||
* - No tuple type {@link OpenApi.IJsonSchema.ITuple} support | ||
* - Forcibly transform every object properties to be required | ||
* | ||
* For reference, if you've composed the `IChatGptSchema` type with the | ||
* {@link ILlmApplication.IChatGptOptions.escape} `true` option, only the recursived | ||
* named types would be archived into the {@link IChatGptSchema.IParameters.$defs}, | ||
* and the others would be ecaped from the {@link IChatGptSchema.IReference} type. | ||
* | ||
* Also, if you've composed the `IChatGptSchema` type with the | ||
* {@link ILlmApplication.IChatGptOptions.constraint} `false` option, the | ||
* `IChatGptSchema` would not compose these properties. Instead, these | ||
* properties would be written on {@link IChatGptSchema.__IAttribute.descripotion} | ||
* field like `@format uuid` case. | ||
* | ||
* - {@link IChatGptSchema.INumber.minimum} | ||
* - {@link IChatGptSchema.INumber.maximum} | ||
* - {@link IChatGptSchema.INumber.multipleOf} | ||
* - {@link IChatGptSchema.IString.minLength} | ||
* - {@link IChatGptSchema.IString.maxLength} | ||
* - {@link IChatGptSchema.IString.format} | ||
* - {@link IChatGptSchema.IString.pattern} | ||
* - {@link IChatGptSchema.IString.contentMediaType} | ||
* - {@link IChatGptSchema.IArray.minItems} | ||
* - {@link IChatGptSchema.IArray.maxItems} | ||
* - {@link IChatGptSchema.IArray.unique} | ||
* | ||
* @reference https://platform.openai.com/docs/guides/function-calling | ||
* @reference https://platform.openai.com/docs/guides/structured-outputs | ||
* @warning Specified not by the ChatGPT documentation, but by my experiments. | ||
* Therefore, its definitions can be inaccurate or be changed in the future. | ||
* If you find any wrong or outdated definitions, please let me know by issue | ||
* @issue https://github.com/samchon/openapi/issues | ||
* @author Jeongho Nam - https://github.com/samchon | ||
*/ | ||
export type IChatGptSchema = | ||
@@ -7,3 +67,2 @@ | IChatGptSchema.IBoolean | ||
| IChatGptSchema.IArray | ||
| IChatGptSchema.ITuple | ||
| IChatGptSchema.IObject | ||
@@ -263,60 +322,2 @@ | IChatGptSchema.IReference | ||
/** | ||
* Tuple type info. | ||
*/ | ||
export interface ITuple extends __ISignificant<"array"> { | ||
/** | ||
* Prefix items. | ||
* | ||
* The `prefixItems` means the type schema info of the prefix items in the | ||
* tuple type. In the TypeScript, it is expressed as `[T1, T2]`. | ||
* | ||
* If you want to express `[T1, T2, ...TO[]]` type, you can configure the | ||
* `...TO[]` through the {@link additionalItems} property. | ||
*/ | ||
prefixItems: IChatGptSchema[]; | ||
/** | ||
* Additional items. | ||
* | ||
* The `additionalItems` means the type schema info of the additional items | ||
* after the {@link prefixItems}. In the TypeScript, if there's a type | ||
* `[T1, T2, ...TO[]]`, the `...TO[]` is represented by the `additionalItems`. | ||
* | ||
* By the way, if you configure the `additionalItems` as `true`, it means | ||
* the additional items are not restricted. They can be any type, so that | ||
* it is equivalent to the TypeScript type `[T1, T2, ...any[]]`. | ||
* | ||
* Otherwise configure the `additionalItems` as the {@link IJsonSchema}, | ||
* it means the additional items must follow the type schema info. | ||
* Therefore, it is equivalent to the TypeScript type `[T1, T2, ...TO[]]`. | ||
*/ | ||
additionalItems?: boolean | IChatGptSchema; | ||
/** | ||
* Unique items restriction. | ||
* | ||
* If this property value is `true`, target tuple must have unique items. | ||
*/ | ||
uniqueItems?: boolean; | ||
/** | ||
* Minimum items restriction. | ||
* | ||
* Restriction of minumum number of items in the tuple. | ||
* | ||
* @type uint64 | ||
*/ | ||
minItems?: number; | ||
/** | ||
* Maximum items restriction. | ||
* | ||
* Restriction of maximum number of items in the tuple. | ||
* | ||
* @type uint64 | ||
*/ | ||
maxItems?: number; | ||
} | ||
/** | ||
* Object type info. | ||
@@ -323,0 +324,0 @@ */ |
@@ -6,2 +6,3 @@ import { OpenApi } from "../OpenApi"; | ||
import { IHttpMigrateRoute } from "./IHttpMigrateRoute"; | ||
import { ILlmApplication } from "./ILlmApplication"; | ||
import { ILlmSchemaV3 } from "./ILlmSchemaV3"; | ||
@@ -108,3 +109,5 @@ import { ILlmSchemaV3_1 } from "./ILlmSchemaV3_1"; | ||
Model, | ||
Parameters["properties"][string] | ||
Parameters["properties"][string] extends IHttpLlmApplication.ModelSchema[Model] | ||
? Parameters["properties"][string] | ||
: IHttpLlmApplication.ModelSchema[Model] | ||
>; | ||
@@ -169,54 +172,5 @@ } | ||
/** | ||
* Options for composing the LLM application. | ||
*/ | ||
export interface IOptions< | ||
Model extends IHttpLlmApplication.Model, | ||
Schema extends | ||
| ILlmSchemaV3 | ||
| ILlmSchemaV3_1 | ||
| IChatGptSchema | ||
| IGeminiSchema = IHttpLlmApplication.ModelSchema[Model], | ||
> { | ||
/** | ||
* Whether to allow recursive types or not. | ||
* | ||
* If allow, then how many times to repeat the recursive types. | ||
* | ||
* By the way, if the model is "chatgpt", the recursive types are always | ||
* allowed without any limitation, due to it supports the reference type. | ||
* | ||
* @default 3 | ||
*/ | ||
recursive: Model extends "chatgpt" ? never : false | number; | ||
/** | ||
* Separator function for the parameters. | ||
* | ||
* When composing parameter arguments through LLM function call, | ||
* there can be a case that some parameters must be composed by Human, | ||
* or LLM cannot understand the parameter. For example, if the | ||
* parameter type has configured | ||
* {@link ILlmSchemaV3.IString.contentMediaType} which indicates file | ||
* uploading, it must be composed by Human, not by LLM | ||
* (Large Language Model). | ||
* | ||
* In that case, if you configure this property with a function that | ||
* predicating whether the schema value must be composed by Human or | ||
* not, the parameters would be separated into two parts. | ||
* | ||
* - {@link IHttpLlmFunction.separated.llm} | ||
* - {@link IHttpLlmFunction.separated.Human} | ||
* | ||
* When writing the function, note that returning value `true` means | ||
* to be a Human composing the value, and `false` means to LLM | ||
* composing the value. Also, when predicating the schema, it would | ||
* better to utilize the {@link LlmTypeChecker} features. | ||
* | ||
* @param schema Schema to be separated. | ||
* @returns Whether the schema value must be composed by Human or not. | ||
* @default null | ||
*/ | ||
separate: null | ((schema: Schema) => boolean); | ||
} | ||
export import IOptions = ILlmApplication.IOptions; | ||
export import ICommonOptions = ILlmApplication.ICommonOptions; | ||
export import IChatGptOptions = ILlmApplication.IChatGptOptions; | ||
} |
@@ -57,3 +57,8 @@ import { IChatGptSchema } from "./IChatGptSchema"; | ||
*/ | ||
options: ILlmApplication.IOptions<Model, Parameters["properties"][string]>; | ||
options: ILlmApplication.IOptions< | ||
Model, | ||
Parameters["properties"][string] extends ILlmApplication.ModelSchema[Model] | ||
? Parameters["properties"][string] | ||
: ILlmApplication.ModelSchema[Model] | ||
>; | ||
} | ||
@@ -78,9 +83,22 @@ export namespace ILlmApplication { | ||
*/ | ||
export interface IOptions< | ||
export type IOptions< | ||
Model extends ILlmApplication.Model, | ||
Schema extends | ||
| ILlmSchemaV3 | ||
| ILlmSchemaV3_1 | ||
| IChatGptSchema | ||
| IGeminiSchema = ILlmApplication.ModelSchema[Model], | ||
ILlmApplication.ModelSchema[Model] = ILlmApplication.ModelSchema[Model], | ||
> = Model extends "chatgpt" | ||
? IChatGptOptions<Schema extends IChatGptSchema ? Schema : IChatGptSchema> | ||
: ICommonOptions< | ||
Exclude<Model, "chatgpt">, | ||
Schema extends ILlmApplication.ModelSchema[Exclude<Model, "chatgpt">] | ||
? Schema | ||
: ILlmApplication.ModelSchema[Exclude<Model, "chatgpt">] | ||
>; | ||
/** | ||
* Options for non "chatgpt" model. | ||
*/ | ||
export interface ICommonOptions< | ||
Model extends Exclude<ILlmApplication.Model, "chatgpt">, | ||
Schema extends | ||
ILlmApplication.ModelSchema[Model] = ILlmApplication.ModelSchema[Model], | ||
> { | ||
@@ -97,3 +115,3 @@ /** | ||
*/ | ||
recursive: Model extends "chatgpt" ? never : false | number; | ||
recursive: false | number; | ||
@@ -129,2 +147,89 @@ /** | ||
} | ||
/** | ||
* Options for "chatgpt" model. | ||
*/ | ||
export interface IChatGptOptions< | ||
Schema extends IChatGptSchema = IChatGptSchema, | ||
> { | ||
/** | ||
* Separator function for the parameters. | ||
* | ||
* When composing parameter arguments through LLM function call, | ||
* there can be a case that some parameters must be composed by human, | ||
* or LLM cannot understand the parameter. For example, if the | ||
* parameter type has configured | ||
* {@link IChatGptSchema.IString.contentMediaType} which indicates file | ||
* uploading, it must be composed by human, not by LLM | ||
* (Large Language Model). | ||
* | ||
* In that case, if you configure this property with a function that | ||
* predicating whether the schema value must be composed by human or | ||
* not, the parameters would be separated into two parts. | ||
* | ||
* - {@link ILlmFunction.separated.llm} | ||
* - {@link ILlmFunction.separated.human} | ||
* | ||
* When writing the function, note that returning value `true` means | ||
* to be a human composing the value, and `false` means to LLM | ||
* composing the value. Also, when predicating the schema, it would | ||
* better to utilize the {@link ChatGptTypeChecker} features. | ||
* | ||
* @param schema Schema to be separated. | ||
* @returns Whether the schema value must be composed by human or not. | ||
* @default null | ||
*/ | ||
separate: null | ((schema: Schema) => boolean); | ||
/** | ||
* Whether to allow reference type in everywhere. | ||
* | ||
* If you configure this property to `false`, most of reference types | ||
* represented by {@link IChatGptSchema.IReference} would be escaped to | ||
* a plain type unless recursive type case. | ||
* | ||
* This is because the lower version of ChatGPT does not understand the | ||
* reference type well, and even the modern version of ChatGPT sometimes occur | ||
* the hallucination. | ||
* | ||
* However, the reference type makes the schema size smaller, so that reduces | ||
* the LLM token cost. Therefore, if you're using the modern version of ChatGPT, | ||
* and want to reduce the LLM token cost, you can configure this property to | ||
* `true`. | ||
* | ||
* @default false | ||
*/ | ||
reference: boolean; | ||
/** | ||
* Whether to allow contraint properties or not. | ||
* | ||
* If you configure this property to `false`, the schemas do not containt | ||
* the constraint properties of below. Instead, below properties would be | ||
* written to the {@link IChatGptSchema.__IAttribute.description} property | ||
* as a comment string like `"@format uuid"`. | ||
* | ||
* This is because the ChatGPT function calling understands the constraint | ||
* properties when the function parameter types are simple, however it occurs | ||
* some errors when the parameter types are complex. | ||
* | ||
* Therefore, considering the complexity of your parameter types, determine | ||
* which is better, to allow the constraint properties or not. | ||
* | ||
* - {@link IChatGptSchema.INumber.minimum} | ||
* - {@link IChatGptSchema.INumber.maximum} | ||
* - {@link IChatGptSchema.INumber.multipleOf} | ||
* - {@link IChatGptSchema.IString.minLength} | ||
* - {@link IChatGptSchema.IString.maxLength} | ||
* - {@link IChatGptSchema.IString.format} | ||
* - {@link IChatGptSchema.IString.pattern} | ||
* - {@link IChatGptSchema.IString.contentMediaType} | ||
* - {@link IChatGptSchema.IArray.minItems} | ||
* - {@link IChatGptSchema.IArray.maxItems} | ||
* - {@link IChatGptSchema.IArray.unique} | ||
* | ||
* @default false | ||
*/ | ||
constraint: boolean; | ||
} | ||
} |
@@ -41,7 +41,2 @@ import { IChatGptSchema } from "../structures/IChatGptSchema"; | ||
(schema as IChatGptSchema.IArray).items !== undefined; | ||
export const isTuple = ( | ||
schema: IChatGptSchema, | ||
): schema is IChatGptSchema.ITuple => | ||
(schema as IChatGptSchema.ITuple).type === "array" && | ||
(schema as IChatGptSchema.ITuple).prefixItems !== undefined; | ||
export const isObject = ( | ||
@@ -85,10 +80,2 @@ schema: IChatGptSchema, | ||
} else if (ChatGptTypeChecker.isArray(schema)) next(schema.items); | ||
else if (ChatGptTypeChecker.isTuple(schema)) { | ||
(schema.prefixItems ?? []).forEach(next); | ||
if ( | ||
typeof schema.additionalItems === "object" && | ||
schema.additionalItems !== null | ||
) | ||
next(schema.additionalItems); | ||
} | ||
}; | ||
@@ -178,3 +165,3 @@ next(props.schema); | ||
return ( | ||
(isArray(p.y) || isTuple(p.y)) && | ||
isArray(p.y) && | ||
coverArray({ | ||
@@ -205,24 +192,5 @@ $defs: p.$defs, | ||
x: IChatGptSchema.IArray; | ||
y: IChatGptSchema.IArray | IChatGptSchema.ITuple; | ||
y: IChatGptSchema.IArray; | ||
}): boolean => { | ||
if (isTuple(p.y)) | ||
return ( | ||
p.y.prefixItems.every((v) => | ||
coverStation({ | ||
$defs: p.$defs, | ||
visited: p.visited, | ||
x: p.x.items, | ||
y: v, | ||
}), | ||
) && | ||
(p.y.additionalItems === undefined || | ||
(typeof p.y.additionalItems === "object" && | ||
coverStation({ | ||
$defs: p.$defs, | ||
visited: p.visited, | ||
x: p.x.items, | ||
y: p.y.additionalItems, | ||
}))) | ||
); | ||
else if ( | ||
if ( | ||
!( | ||
@@ -229,0 +197,0 @@ p.x.minItems === undefined || |
@@ -78,3 +78,4 @@ import { OpenApi } from "../OpenApi"; | ||
if (isReference(props.schema) === false) return false; | ||
const counter: Map<string, number> = new Map(); | ||
const current: string = props.schema.$ref.split("#/components/schemas/")[1]; | ||
let counter: number = 0; | ||
visit({ | ||
@@ -85,8 +86,8 @@ components: props.components, | ||
if (OpenApiTypeChecker.isReference(schema)) { | ||
const key: string = schema.$ref.split("#/components/schemas/")[1]; | ||
counter.set(key, (counter.get(key) ?? 0) + 1); | ||
const next: string = schema.$ref.split("#/components/schemas/")[1]; | ||
if (current === next) ++counter; | ||
} | ||
}, | ||
}); | ||
return Array.from(counter.values()).some((v) => v > 1); | ||
return counter > 1; | ||
}; | ||
@@ -93,0 +94,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1521085
206
26381